One signed POST per change, for the competitions and events you choose. Build the receiver to the delivery contract and your system stays in step with every match, without polling.
LIGR webhooks send one signed HTTP POST to your URL each time a match, fact, summary, team, competition or overlay changes in a competition you subscribe to. Verify the HMAC-SHA256 signature in x-ligr-webhook-sig, answer 2xx within 10 seconds, and deduplicate on (entity, data.id, date), because delivery is at least once. The REST API holds current state, and webhooks tell you when it changed. This guide draws on the Webhooks overview and the Receive webhooks guide in the LIGR developer docs.
Who this is for
Developers of results pages, club and league apps, notification services, data warehouses and production tools that need to react to a match as it happens. Webhooks are a dashboard feature: there is no REST endpoint to create one, and LIGR turns them on for your organisation.
What you can build
| Sport | What you build | Events |
|---|---|---|
| Football | A goal alert that fires on the new fact, then confirms the score from the summary update that follows | fact, summary |
| AFL | A club app that refreshes its scoreboard when the match status, score, clock or lineups change | match |
| Netball | A results page that updates from match and summary changes instead of polling the API | match, summary |
| Tennis | A draw page that shows the players: in a singles match, homeTeam and awayTeam each carry a player, and in a doubles match each carries a pair | match |
| Basketball | A data warehouse that stores every fact and summary for a competition, then fills gaps from REST after an outage | fact, summary |
| American football | A production tool that sees an overlay key change and updates the browser source it manages | overlay |
Set up a webhook, step by step
Ask LIGR to enable webhooks
Webhooks sit behind the f-webhooks feature flag. Ask LIGR to enable it for your organisation.
Add your endpoint
Open Developers > Webhooks in the dashboard, add a public HTTPS URL and select the competitions and the events you want. Subscribe only to the events you handle: every extra event costs your endpoint time.
Copy the signing secret
Your organisation has one signing secret, and every webhook of the organisation uses it. Keep it in an environment variable on your server, never in a browser. A webhook with no signing secret is skipped without an error.
Verify every delivery
Read the raw body before anything parses it. LIGR signs v0:{timestamp}:{body} with HMAC-SHA256 and sends the hex digest in x-ligr-webhook-sig, with the timestamp in x-ligr-webhook-timestamp as Unix milliseconds. This Node function is copied from Verify signatures, which also has a Python version:
import { createHmac, timingSafeEqual } from 'node:crypto'
const FIVE_MINUTES = 5 * 60_000
export function verify(rawBody: string, headers: Record<string, string>, secret: string): boolean {
const ts = headers['x-ligr-webhook-timestamp']
const sig = headers['x-ligr-webhook-sig']
if (!ts || !sig) return false
if (Math.abs(Date.now() - Number(ts)) > FIVE_MINUTES) return false
const expected = createHmac('sha256', secret).update(`v0:${ts}:${rawBody}`).digest('hex')
if (sig.length !== expected.length) return false
return timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
}
Compare in constant time, reject a request older than five minutes to stop a replay, reject one with no signature header, and never log the secret. If every delivery fails verification, your framework parsed and serialised the body again before the check.
Answer first, then process
LIGR waits 10 seconds for your answer. Return 2xx at once and queue the work. A slow database write inside the request is the usual cause of a timeout.
Trigger a test delivery
Post a fact to a test match, then delete it. Your receiver should log fact create, then fact delete, with a summary update between them. The live score API guide shows the fact calls.
Read the event log
Open the webhook under Developers > Webhooks and select Event Logs. The log keeps the newest 50 attempts per webhook, with the status, the response body and the payload. A status of 0 means your endpoint sent no answer.
The events
| Entity | Verbs | Fires when |
|---|---|---|
match | create, update | A match is created, or its details, status, score, clock or lineups change |
fact | create, update, delete | A fact is created, edited, undone or deleted |
summary | update, delete | The match summary is recomputed. A delete carries ids only |
team | create, update | A team in the competition changes |
competition | update | The competition itself changes |
overlay | create, update, delete | An overlay of a match is created, its settings or key change, or it is deleted |
Every event has the same envelope: type, entity, competitionId, date and data. data is the webhook shape of the entity, not the REST shape, so do not assume the two have the same fields. To see every field your competition produces, read one live delivery in the event log. See Payloads.
The delivery contract
- Retries. LIGR retries when your endpoint sends no answer, or answers
408,429or any5xx. It does not retry a2xxor any other4xx. Match, fact and summary events get up to 6 attempts with 30 seconds of retry delays. Other events get up to 3 attempts with 1 minute of retry delays. - Order. Match, fact and summary events for one match arrive in order, one at a time. A retried delivery can arrive after a newer event, so compare
date, orupdatedAton the entity, and ignore the older one. There is no order across matches. - Duplicates. Delivery is at least once. Every attempt of one event keeps its
date, so(entity, data.id, date)deduplicates it. Answer2xxto a duplicate. - Gaps. An event that fails every attempt is lost. Retries cover a restart or a deploy, not an outage. If your receiver starts mid-match, or was down for more than a minute, read the matches and summaries you track once from REST, then continue from the webhooks.
The dashboard shows one health state per webhook: unknown, healthy, degraded after 1 to 4 consecutive failures, and failing after 5 or more. During the current rollout, failures do not suspend delivery, and LIGR will email affected customers with an effective date before stricter enforcement. Changing the URL resets the health to unknown and drops deliveries queued for the old URL. See Delivery health and logs.
Things that surprise people
- A match is never deleted. A cancelled, abandoned or early-finished match arrives as a
fact.createnamedMATCH_CANCELLED,MATCH_ABANDONEDorMATCH_FINISHED_EARLY, then asummary.update, then amatch.updatewithfinishedStatusset. summary.createandcompetition.createdo not exist. A summary starts to exist with its first update.- A graphic shown or hidden on an overlay is not an overlay event, and an overlay with no match fires nothing.
- A live football match produces tens of events, and a
summary.updatefollows most fact changes.
Frequently asked questions
How do I verify a LIGR webhook signature?
Compute the hex HMAC-SHA256 of v0:{timestamp}:{body} over the raw request body, with your organisation's signing secret. The timestamp is the x-ligr-webhook-timestamp header, in Unix milliseconds. Compare the result with x-ligr-webhook-sig in constant time, and reject a request older than five minutes or with no signature.
How many times does LIGR retry a webhook?
Match, fact and summary events get up to 6 attempts with 30 seconds of retry delays. Other events get up to 3 attempts with 1 minute of retry delays. LIGR retries when your endpoint sends no answer, or answers 408, 429 or a 5xx, and waits 10 seconds for each answer.
Can I create a LIGR webhook through the API?
No. Webhooks are a dashboard feature with no REST endpoint. Ask LIGR to enable the f-webhooks feature flag, then add the URL, the competitions and the events under Developers, Webhooks, and copy the signing secret.
Why did I receive the same event twice?
Delivery is at least once, so a duplicate is normal, for example after a lost answer. Every attempt of one event keeps the same date, so deduplicate on (entity, data.id, date) and answer 2xx to the duplicate.
Which events can a LIGR webhook send?
Match create and update, fact create, update and delete, summary update and delete, team create and update, competition update, and overlay create, update and delete. You choose the competitions and the events for each webhook.
Build your receiver
The Receive webhooks guide stands up a Node endpoint, verifies every delivery and reads the delivery log, in about half an hour.