API Reference
The RaceHooks API is a REST API returning JSON. All requests are authenticated via Bearer token and versioned under /v1. The API is sport-agnostic at the infrastructure level — feeds, webhooks, and simulate endpoints will serve all supported sports as the platform expands beyond F1.
https://api.racehooks.io/v1Authentication
RaceHooks uses OAuth 2.0 client credentials. Exchange your client_id and client_secret for a Bearer token, then include it in the Authorization header on all other endpoints. Tokens expire after 12 hours.
New accounts sign up, verify their email, and retrieve credentials first — the full account lifecycle (signup, verify-email, login, resend-verification) is documented on the Authentication page. Get your client_id/client_secret from the console API Keys page, or programmatically via POST /v1/oauth/credentials with a session cookie.
/v1/oauth/v1/oauth/credentialsReturns { clientId, clientSecret } for the logged-in account. Authenticated by the session cookie set by POST /v1/auth/login or POST /v1/auth/verify-email — no Bearer token required.
Webhooks
Create, list, update, delete, and test webhook endpoint registrations.
Create a webhook
/v1/webhooksProvide exactly one feed selection: feedId, feedIds, or subscriptions — omitting all three returns 400.
| Field | Type | Description |
|---|---|---|
webhookUrl | string (required) | The HTTPS endpoint to receive deliveries. Must be publicly reachable. |
feedId | string (one required) | Subscribe to a single feed (the simplest form). See the feed catalog for valid IDs. |
feedIds | string[] (one required) | Subscribe 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 required) | Per-feed subscriptions with their own filters: [{ feedId, filters }]. Use instead of feedIds when different feeds need different filters. |
filters | object (optional) | Restrict which deliveries are sent. Supports drivers (TLAs), driverNumbers, constructors (team keywords), positions ({min,max}), and eventTypes (events.race only). Omit for all. Unknown keys or wrong value types are rejected with 400 invalid_filters. See the Webhooks guide for the full schema. |
webhookSecret is returned in the create response and used to verify signatures. It's retrievable anytime via GET /v1/webhooks/:webhookId/secret; rotate it with POST /v1/webhooks/:webhookId/rotate-secret.List webhooks
/v1/webhooksReturns your webhook endpoints, each carrying its per-feed subscriptions — one endpoint (URL + signing secret) can subscribe to many feeds. The list is paginated via limit (default 20, max 100) and offset query parameters.
Update a webhook
/v1/webhooks/:webhookId| Field | Type | Description |
|---|---|---|
active | boolean (optional) | Pause (false) or resume (true) deliveries to this endpoint (all feeds). |
webhookUrl | string (optional) | Move the endpoint to a new URL. Applies to all of its feed subscriptions. |
webhookMethod | string (optional) | "post" (default) or "put". |
filters | object (optional) | Endpoint-wide filters, applied to every feed. To change one feed's filters use PATCH /v1/webhooks/:webhookId/feeds/:feedId. |
Delete a webhook
/v1/webhooks/:webhookIdDelivery logs
/v1/webhooks/:webhookId/logs| Field | Type | Description |
|---|---|---|
limit | integer (query) | Number of log entries to return. Default 50, max 500. |
cursor | string (query) | Pagination cursor from a previous response for the next page. |
Send a test delivery
/v1/webhooks/:webhookId/testSends a sample payload to the registered endpoint. Useful for verifying your endpoint is reachable and signature verification is working.
Rotate webhook secret
/v1/webhooks/:webhookId/rotate-secretGenerates a new webhook secret. The new secret takes effect immediately. Retrieve it anytime via GET /v1/webhooks/:webhookId/secret.
Feeds
/v1/feedsReturns all subscribable feeds. Each feed carries its feedId, name, seriesId, and availability — the feed's access class (free, live, or analytics), which maps to the plan required to subscribe: free feeds are open to every plan, live feeds require the Developer plan, and analytics feeds require the Custom plan. See the feed catalog for cadences and payload schemas.
Simulate
Replay a session against your registered webhooks. Self-serve tiers cover current-season F1 sessions; the full historical archive is on Custom. Sessions are unlocked into lifetime slots — check yours with GET /v1/simulate/quota.
Browse replayable sessions
/v1/simulate/sessionsCheck your simulate slots
/v1/simulate/quotaSimulate is gated by lifetime unique-session slots (Free 5, Developer 10, Custom unlimited) — a slot is consumed the first time you deliver a newsession's replay, and re-running an already-unlocked session is free. Watching a replay in the console never consumes a slot.
| Field | Type | Description |
|---|---|---|
limit | number | Lifetime unique-session slots for your tier (-1 = unlimited on Custom). |
used | number | Distinct sessions you have unlocked so far. |
remaining | number | Slots left before you hit the cap. |
unlocked | string[] | Session ids you have already unlocked — re-running any of these is free. |
currentSeasonOnly | boolean | true on self-serve tiers (current-season sessions only); false on Custom, which unlocks the full historical archive. |
429; requesting an out-of-season session on a self-serve tier returns 403 — the full historical archive is on Custom.Prepare a session
/v1/simulate/prepare| Field | Type | Description |
|---|---|---|
sessionId | string (required) | Session id from GET /v1/simulate/sessions. The playback artifact is generated once and cached. |
Check readiness
/v1/simulate/status?session=:sessionIdPlay back
/v1/simulate/stream?session=:sessionId&speed=10&sinks=webhook| Field | Type | Description |
|---|---|---|
speed | number (optional) | Playback speed multiplier, up to 10. |
sinks | string (optional) | "visual" (SSE to you, default) | "webhook" (deliver to your registered webhooks, detached) | "both" (SSE + webhooks in lockstep). |
Stop a delivery
/v1/simulate/stream?runId=:runIdStops a detached (sinks=webhook) replay. The runId comes from the stream response. Returns 200 when the run stops immediately, or 202 while the stop propagates across instances (a few seconds). Events already delivered stay delivered. A simulate slot is consumed when you first unlock a session; stopping a run does not free the slot, and re-running an already-unlocked session is free.
Delivery volume during replays
A replay re-delivers every recorded event for the feeds each endpoint is subscribed to — a full race is tens of thousands of events, and the speed multiplier compresses them into a shorter window (10× ≈ a full race's events in ~9 minutes). Each event is POSTed to every active endpoint, so total attempts = events × endpoints. Free capture bins (webhook.site and similar) rate-limit far below this throughput and will drop or 429 mid-replay; for clean samples use speed=1 with a single endpoint, or point the replay at a receiver sized for bursts. Every delivery carries X-RaceHooks-Replay-* headers so a receiver can tell replay traffic from live and group or discard a whole run. An endpoint that fails many deliveries in a row (errors, timeouts, or any non-2xx response — including 429s from an overwhelmed receiver) is paused for that run: deliveries stop, a single probe goes out every few seconds, and deliveries resume automatically once the endpoint responds successfully. The standing webhook subscription is never affected.
Demo session: replaying the curated demo race delivers the full Analytics feed set to all of your active endpoints, regardless of your tier or per-endpoint feed subscriptions — it is the platform showcase and is exempt from the replay quota. Expect the highest event volume there, even on the Free tier. Every other session delivers only your tier's feeds and each endpoint's own subscriptions.
Events
/v1/eventsReturns the race calendar for all supported sports with sessions and their statuses. Currently returns F1 season data. Use it to detect when live sessions are starting; for replayable session ids use GET /v1/simulate/sessions.
Predictions
/v1/preview/upcoming/v1/preview/:sessionIdSession previews with real model output — win probability, qualifying probability, expected strategy, circuit intelligence, and championship form for upcoming scoring sessions. Available to everytier, including Free (a headline "light" view; paid tiers get the full object). Full field reference on the Predictions page.
Fantasy
Fantasy points and pit-stop time leaderboards for a race weekend. All three endpoints require a paid plan — Developer tier or higher; on the Free tier they return 403. Scores use RaceHooks' estimated fantasy model (finishing position, qualifying, positions gained, fastest lap, teammate comparison, and retirements), with a full per-driver breakdown on every entry. See the Fantasy guide for the scoring tables and a build-an-app walkthrough.
Race scores
/v1/fantasy/races/:raceId/scoresDEVELOPER+Estimated fantasy points per driver for a completed session. Defaults to the Grand Prix; pass ?session=sprint to score the Sprint (compressed points table). The response sessionType (grand_prix | sprint) echoes which was scored.
| Field | Type | Description |
|---|---|---|
raceId | string (path) | Race id slug, e.g. 2026-italy-r16. |
session | string (query) | "race" (default) = Grand Prix; "sprint" = Sprint race. |
Live in-session scores
/v1/fantasy/session/:sessionId/scoresDEVELOPER+A running, provisional score for each driver while a session is live, from the current running order and retirements. The response carries live and provisional flags plus currentLap / totalLaps. Position, teammate and DNF components update live; grid-derived and fastest-lap components stay null until the session ends. Returns live: false with an empty scores list and a message when no session is live for the id.
Pit-lane leaderboard
/v1/fantasy/session/:sessionId/pit-timesDEVELOPER+Pit-lane times for a session ranked fastest to slowest, with the fastest stop broken out. Returns { sessionId, source, fastestStop, stops }; source is live during the session and historical afterward.
Usage
Delivery statistics for the authenticated client. All usage data resets at the start of each calendar month.
Summary
/v1/usage| Field | Type | Description |
|---|---|---|
deliveryCount | number | Total webhook deliveries in the current billing window. |
successCount | number | Deliveries that received a 2xx response from your endpoint. |
failureCount | number | Deliveries that received a non-2xx response or timed out. |
windowStart | string | ISO 8601 timestamp for the start of the current billing window. |
Breakdown by feed
/v1/usage/by-feedReturns per-feed delivery counts. Useful for understanding which feeds are generating the most traffic.
| Field | Type | Description |
|---|---|---|
byFeed[].feedId | string | Feed identifier. |
byFeed[].deliveryCount | number | Total deliveries for this feed in the current window. |
Latency percentiles
/v1/usage/latencyReturns p50, p95, and p99 delivery latency per feed, measured from when the F1 event was detected to when your endpoint acknowledged it.
| Field | Type | Description |
|---|---|---|
byFeed[].feedId | string | Feed identifier. |
byFeed[].p50 | number | Median delivery latency in milliseconds. |
byFeed[].p95 | number | 95th percentile latency in milliseconds. |
byFeed[].p99 | number | 99th percentile latency in milliseconds. |
byFeed[].sampleCount | number | Number of deliveries included in the sample. |
Plans & limits
Enforced limits per plan. Creating past the endpoint or feeds-per-endpoint limit returns 402; the API rate limit returns429 with X-RateLimit-* headers. The monthly delivery bucket works differently: on Free, deliveries beyond it areskippedas a hard backstop (your endpoint stops receiving events until the month rolls over); on Developer, delivery continues and overage bills at $3/1,000 up to your spend cap. You're warned by email as you approach the bucket — monitorGET /v1/usage. Remaining simulate slots are at GET /v1/simulate/quota.
| Limit | Free | Developer |
|---|---|---|
| Webhook endpoints | 3 | 25 |
| Feeds per endpoint | 6 | Unlimited |
| Deliveries per month | 5,000 | 50,000 + $3/1k |
| API requests per hour | 600 | 1,800 |
| Simulate sessions (lifetime) | 5 | 10 |
| Replay session archive | Current season | Current season |
| gRPC streaming | — | — |
| ML analytics enrichment | — | — |
Every plan includes HMAC-signed deliveries. Simulate is gated by your lifetime unique-session slots (see GET /v1/simulate/quota), separate from the monthly delivery bucket — see the Simulate section above for replay delivery volume.
Error codes
All error responses return a JSON body with error (human-readable), code (machine-readable), and statusCode fields.