Webhooks
Webhook event
POST{your endpoint URL}All plans
One request per event and endpoint. Types: fixture.score (a side’s current score changed) and fixture.status (kick-off, a new period, a break, full time, postponed, canceled) for every live fixture your filters match; fixture.events (match events added, corrected or removed — goals with scorers, cards, substitutions) and fixture.lineups (from about 90 minutes before kick-off — the official lineups, usually out an hour before — and their changes in play) only for fixtures you name in the endpoint’s fixture ids; ping is the dashboard’s test. data.changes is the same partial Fixture as a WebSocket delta.
Verify every request: SportsAPI-Signature is t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>"> with the endpoint’s signing secret (shown once when you create or rotate it) — compare in constant time and reject a t older than a few minutes. Answer 2xx within 10 seconds; anything else (a redirect included) is retried after 10 s, 1 min, 5 min, 30 min, 2 h and 6 h, then marked failed. An endpoint that fails every attempt for 24 hours is disabled (re-enable it in the dashboard). Deliveries are not strictly ordered: use createdAt and the event id (also in SportsAPI-Event-Id) to drop duplicates. Only public https:// hosts are accepted.
Every /v2 call can also answer the common errors.
Example
POST https://your-server.example.com/sportsapi SportsAPI-Signature: t=1793551606,v1=5f0c… SportsAPI-Event: fixture.score SportsAPI-Event-Id: evt_8a1f… Content-Type: application/json { "id": "evt_8a1f…", "type": "fixture.score", "createdAt": "2026-11-01T16:46:46.208Z", "data": { "fixtureId": 211521, "sport": "football", "leagueId": 17, "changes": { "homeScore": { "current": 1, "periods": { "period1": 1 } } } } } // Node: verify the signature const [t, v1] = header.split(',').map((p) => p.split('=')[1]); const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) && Date.now() / 1000 - Number(t) < 300;