Webhooks
Wickets, innings and results posted to your own address as they happen, signed, and tried again until your server takes them.
Webhooks send live events to an address of yours the moment we see them, so nothing has to poll. They come with Match Week, Pro and Analyst Pro, and do not count as calls. Add up to 10 endpoints on your account; each one picks its events and the matches it follows (every match, internationals, women's matches, or one competition), and has its own signing secret.
The events
| Event | When | In data |
|---|---|---|
match.started | A match goes from upcoming to in play | toss, starts_at, venue, city |
wicket | Each wicket as it falls (retirements are not wickets) | innings, team, score, dismissed with their runs and balls, how_out, dismissal, and the ball as /v1/live/{match}/balls gives it |
innings.finished | An innings ends: all out, its overs used, declared, or the next one begun | innings, team, runs, wickets, overs, all_out, declared, target |
match.finished | The match ends | winner, result |
A few matches are followed by their score only, with no balls: their wicket events carry the score, with dismissed, how_out, dismissal and ball as null.
What arrives
A POST of JSON. Every event has the same shape: its id, type and time, the match as /v1/live gives it, and data.
{
"id": "evt_5c1f0a9e2b7d43e8a6f19c20",
"type": "wicket",
"created_at": "2026-10-20T14:21:07Z",
"test": false,
"match": {"match": "2026-10-20-india-v-australia", "name": "India v Australia", "format": "ODI", "state": "live", "teams": [ ... ], "innings": [ ... ], ... },
"data": {
"innings": 1, "team": "India",
"score": {"runs": 87, "wickets": 2, "overs": "14.3"},
"dismissed": {"player": "s-gill", "name": "Shubman Gill", "runs": 41, "balls": 38},
"how_out": "caught", "dismissal": "c Smith b Starc",
"ball": {"innings": 1, "over": 15, "ball": 3, ... }
}
}
Three headers come with it: X-CDB-Event (the type), X-CDB-Delivery (the event id) and X-CDB-Signature.
Checking it is ours
X-CDB-Signature: t=1792425720,v1=... is an HMAC-SHA256 of the time, a dot and the raw body, with the endpoint's secret (it starts whsec_; the Secret button on your account shows it). Check it against the body exactly as it arrived, before parsing it, and refuse a time more than 5 minutes off:
$body = file_get_contents('php://input');
$sig = $_SERVER['HTTP_X_CDB_SIGNATURE'] ?? '';
preg_match('/t=(\d+)/', $sig, $t);
preg_match_all('/v1=([0-9a-f]{64})/', $sig, $v);
$want = hash_hmac('sha256', $t[1] . '.' . $body, $secret);
$ok = abs(time() - (int)$t[1]) < 300
&& array_filter($v[1], fn($s) => hash_equals($want, $s));
In Python: hmac.compare_digest(hmac.new(secret.encode(), f"{t}.{body}".encode(), "sha256").hexdigest(), v1) for each v1. When you make a new secret, the old one keeps working for 24 hours: each delivery in that day carries a v1 for each secret, so accept the event when any of them matches.
Answering, and when it goes wrong
Answer with any 2xx within 10 seconds, and do the work afterwards. Anything else is tried again: 8 tries in all, after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, a day and 40 hours, about 3 days altogether. A 4xx that will not change (400, 401, 403, 404, 410, 422 and the like) stops that delivery at once; 408, 409, 425 and 429 are tried again. Redirects are not followed.
After 20 failed tries in a row an endpoint is turned off, and we email you. Turn it back on from your account; it sends a test first. Every delivery is in the log on your account for 30 days, with what your server answered, and any of them can be sent again with the same id.
Good to know
A retried or resent event keeps its id, so keep the ids you have handled and skip one you have seen. Events of one match arrive in order within one run, but tries can overtake each other, so order by the ball or created_at if order matters. Addresses must be https on the public internet; private, loopback and link-local addresses are refused, and are checked again at every delivery. The Test button sends a real recent event, marked "test": true.
For a steady flow of every ball, rather than the moments that matter, follow the live stream.