Webhooks
A webhook is a registered endpoint URL carrying one or more feed subscriptions. RaceHooks POSTs a JSON payload to that URL for every matching event during a live session. The webhook infrastructure is sport-agnostic — the same endpoint, signature verification, and filter system works across every sport RaceHooks supports. One endpoint can subscribe to many feeds (all sharing a single signing secret), each subscription can carry its own filters to narrow which events trigger a delivery, and the X-RaceHooks-Feed header tells you which feed produced each payload.
Lifecycle
Webhooks have three operational states:
Create a webhook
One webhook endpoint (URL + signing secret) can subscribe to many feeds. Provide exactly one feed selection: feedId for a single feed (the simplest form), feedIds to subscribe one endpoint to several feeds at once, or subscriptions when different feeds need different filters — omitting all three returns 400. Every feed on the endpoint shares one signing secret, and the X-RaceHooks-Feed header on each delivery tells you which feed produced it. The webhookSecret is returned at creation time and retrievable anytime via GET /v1/webhooks/:id/secret.
webhookSecret anytime via GET /v1/webhooks/:id/secret. To issue a new secret, rotate it from the webhook detail page or via POST /v1/webhooks/:id/rotate-secret. Rotation takes effect immediately.Request fields
| Field | Type | Description |
|---|---|---|
webhookUrl | string | Your HTTPS endpoint URL. Must be publicly reachable. Localhost is supported during Simulate replays. |
feedId | string (one of) | Subscribe to a single feed (the simplest form). See Feed catalog for all available IDs. |
feedIds | string[] (one of) | Subscribe this one endpoint to many feeds at once. Supports "*" (all feeds in your tier) and group globs like "analytics.*". All feeds share one signing secret. |
subscriptions | object[] (one of) | Per-feed subscriptions with their own filters: [{ feedId, filters }]. Use instead of feedIds when different feeds need different filters. |
webhookMethod | string? | HTTP method for deliveries. Defaults to POST. Can be PUT. |
filters | object? | Optional endpoint-wide delivery filter applied to every feed. See Filters below. |
Provide exactly one of feedId, feedIds, or subscriptions — omitting all three returns 400.
Filters
Filters let you narrow which events trigger a delivery. They are evaluated per payload before each delivery attempt — only matching events are sent. Filters are supported on per-driver feeds (timing.data, tire.stints, timing.driver-info, etc.) and on the events.race feed. Filters are validated strictly: an unrecognized key (e.g. a typo like driverNumber) or a wrong value type is rejected with a 400 invalid_filters error naming every violation, rather than silently delivering unfiltered.
Available filters
| Field | Type | Description |
|---|---|---|
drivers | string[] | Three-letter driver codes (TLAs). e.g. ["VER", "NOR"]. Resolved to driver numbers at delivery time. |
driverNumbers | string[] | Raw driver racing numbers. e.g. ["1", "4"]. Use drivers (TLAs) for readability. |
constructors | string[] | Team name keywords (case-insensitive partial match). e.g. ["ferrari", "mclaren"]. Resolved to all drivers on those teams using the current session's DriverList. |
positions | { min?: number; max?: number } | Race position range. Only delivers when at least one matching driver is within the specified position window. |
eventTypes | string[] | events.race feed only: deliver only these event types, e.g. ["overtake", "pit_entry", "fastest_lap"]. |
constructors and positions, a payload is delivered only when a constructor driver is within the position range."red bull" and "redbull" both match Red Bull Racing. The driver list is resolved live from the current session's DriverList feed, so mid-season team swaps are handled automatically.HMAC signatures
Every delivery, on every tier — Free included — includes an X-RaceHooks-Signature header containing an HMAC-SHA256 signature of the request body. Verifying this header proves the delivery originated from RaceHooks and the body was not tampered with in transit.
X-RaceHooks-Signature: sha256=a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0The signature is computed as:
Always verify against the raw request body bytes, not the parsed JSON object. Use a timing-safe comparison function (timingSafeEqual in Node.js, hmac.compare_digest in Python, subtle.ConstantTimeCompare in Go) to prevent timing attacks.
Rotate a secret
If a secret is compromised or you want to rotate it for security hygiene, call the rotation endpoint. The new secret takes effect immediately.
GET /v1/webhooks/:id/secret. Update your verification code before sending the next delivery.Live, replay, and test deliveries
Every delivery carries an X-RaceHooks-Mode header so you can tell real session data apart from a replay or a test. It has three values:
live— real session data from a live session.replay— a Simulate replay of a past session (you started it from the Simulate page). CarriesX-RaceHooks-Replay-Session(the original session id),X-RaceHooks-Replay-Run-Id(one id shared by every event of that replay run), andX-RaceHooks-Replay-Speed.test— a manual connectivity ping from the “Send test payload” button.
X-RaceHooks-Mode is notlive. Group a replay’s events by X-RaceHooks-Replay-Run-Id to handle or discard a whole run at once.Delivery SLA and retries
RaceHooks retries failed deliveries with exponential backoff:
A delivery is considered successful when your endpoint returns a 2xx status code within 10 seconds. Any other response (timeout, 4xx, 5xx) triggers a retry.
Free and Developer are best-effort — there's no contractual delivery SLA. Custom includes a 99.5% delivery SLA, measured per calendar month, covering delivery infrastructure and excluding upstream feed availability; remedies are service credits, with full terms negotiated per contract.