Skip to content

Webhooks

Receive Fellow events at your HTTPS endpoint. Use webhooks to connect feature changes and account activity to your systems and workflows.

Webhooks are available on Scale. Every active account member can manage them. Each account supports up to 25 endpoints.

  1. Open Developers → Webhooks on desktop.
  2. Select Create webhook. Enter a name, a public HTTPS URL and the events to receive.
  3. Copy the signing secret. It is shown once.
  4. Send a test from the webhook settings.

Your endpoint must accept POST requests with Content-Type: application/json. Return a 2xx response within 15 seconds. Redirects are not followed.

EventWhen it is sent
app.features.detectedFeatures first appear or reappear for one tracked app.
app.features.updatedExisting features gain or lose countries for one tracked app.
app.features.endedFeatures end for one tracked app.
app.features.country.addedExisting features appear in additional countries.
app.features.country.removedExisting features stop appearing in countries.
features.detectedFeatures first appear or reappear across tracked apps.
features.updatedExisting features gain or lose countries across tracked apps.
features.endedFeatures end across tracked apps.
app.addedAn app is added to tracking.
app.removedAn app is removed from tracking.
user.addedAn account member becomes active.
user.removedAn account member is removed.
webhook.testA test is sent from webhook settings.

Choose either the per-app events or the account-wide feature events to avoid receiving the same change in both formats. webhook.test is only sent on request.

Country removals and endings require a complete scrape. A feature ends three days after its last sighting.

app.features.updated and features.updated report country additions and removals. Changes only to titles, tabs, placement or recognition metadata do not emit these events.

Each event has an id, type, UTC timestamp, schema version and event-specific data.

{
  "id": "2b6f9826-85c5-5f33-a5b5-547d456b3fd2",
  "type": "app.features.detected",
  "timestamp": "2026-09-17T12:00:00Z",
  "version": 1,
  "data": {
    "fellow_app_id": "app_30274105",
    "apple_app_id": "570060128",
    "name": "Duolingo",
    "features": [
      {
        "fellow_feature_id": "feat_20860906",
        "apple_feature_id": "1234567890",
        "feature_type": "story",
        "title": "Learn something new",
        "countries": [
          "GB",
          "US"
        ],
        "first_seen_date": "2026-09-17",
        "is_reappearance": false,
        "previous_ended_date": null
      }
    ]
  }
}

Per-app feature events include fellow_app_id and apple_app_id in data. Account-wide feature events include both IDs on each feature. Every feature includes fellow_feature_id and apple_feature_id. Fellow IDs work with the API.

feature_type is story, room, section, app or event. The optional apple_url links to the feature when a URL is available. Event URLs link through the parent app using https://apps.apple.com/<country>/app/id<apple_app_id>?eventid=<apple_feature_id>.

Feature payloads do not include structured tab, placement or recognition metadata. Missing metadata does not establish absence of a placement or recognition.

Updated features include countries_added and countries_removed. Ended features include last_seen_date and ended_date. Country events include the corresponding country list.

Tracking events include fellow_app_id, apple_app_id, name and store_country. Member events include email and role.

Feature payloads contain at most 100 features and stay below 2 MiB. Larger batches use separate events with data.part and data.parts. Parts start at 1.

Fellow uses Standard Webhooks signatures.

HeaderValue
Webhook-IdThe event ID. Stable across retries.
Webhook-TimestampUnix timestamp for this delivery.
Webhook-Signaturev1, followed by the Base64 HMAC-SHA256 signature.

Verify the original request body before parsing it. The signing secret starts with whsec_.

npm install standardwebhooks
import { Webhook } from "standardwebhooks";

const webhook = new Webhook(process.env.FELLOW_WEBHOOK_SECRET);

export function verifyFellowEvent(rawBody, headers) {
return webhook.verify(rawBody, headers);
}

Pass the raw body string or buffer and the request headers. Verification returns the parsed event. It throws for an invalid signature or a delivery timestamp outside the five-minute tolerance.

Rotating the secret invalidates the previous secret immediately. New deliveries and retries use the new secret.

Events are queued when the change occurs. Deliveries can repeat or arrive out of order. Deduplicate by id.

Failed deliveries retry up to five times with exponential backoff. Retries start after about five minutes.

Fellow disables an endpoint after an HTTP 410 response or three consecutive events exhaust their retries. Account admins receive an email. Re-enable the endpoint in its settings.

Test deliveries and manual retries run once. They do not trigger automatic retries or disable the endpoint.

Open Developers → Webhook Events to inspect payloads, response codes and attempts. Failed events can be retried while the endpoint is active.

Webhook events are retained for 30 days. Each event keeps its latest 20 attempt details.

Feature payloads require active tracking and follow the account’s available history. Access is checked again when viewing or delivering an event. Pending events that no longer qualify are cancelled.

Disabling or deleting a webhook cancels its pending deliveries.