Webhooks
Push event updates to your servers in real time. Each delivery is a POST carrying the full event payload + a CMC-Signature header. Verify the signature using the endpoint's signing secret before trusting the body.
◆ Event types
| Type | Triggers when |
|---|---|
| events.created | Editorial team adds a new event to the catalog. |
| events.updated | Material change to an existing event (date, impact score, description, source). |
| events.cancelled | Event is removed from the catalog (cancelled, retracted, or merged into another). |
| events.high-impact | An event reaches impact >= 7.5 for the first time. Fires once per event lifecycle. |
◆ Delivery payload
Every delivery is a JSON body with the same outer shape regardless of type. The data field carries the full event resource (same shape as GET /v2/events/{id}).
{ "id": "evt_dlv_01HW8K2D5N", "type": "events.created", "apiVersion": "v2", "deliveredAt": "2026-04-29T14:22:08Z", "data": { "id": "48291", "slug": "ethereum-pectra-upgrade", "title": "Ethereum Pectra Upgrade", "date": "2026-05-06T12:00:00Z", "isEstimated": false, "displayedDate": "06 May 2026", "coins": [ { "slug": "ethereum", "symbol": "ETH", "name": "Ethereum" } ], "impact": 8.5 } }
◆ Verify the signature
Each POST carries a CMC-Signature header containing sha256=followed by the HMAC-SHA256 hex digest of the raw request body, signed with your endpoint's signing secret. Reject any request whose signature doesn't match.
import crypto from "node:crypto"; import express from "express"; const app = express(); const SECRET = process.env.CMC_WEBHOOK_SECRET; app.post( "/cmc/webhooks", express.raw({ type: "application/json" }), (req, res) => { const sigHeader = req.header("CMC-Signature") ?? ""; const expected = "sha256=" + crypto .createHmac("sha256", SECRET) .update(req.body) .digest("hex"); const sigBuf = Buffer.from(sigHeader); const expBuf = Buffer.from(expected); if ( sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf) ) { return res.status(401).end(); } const event = JSON.parse(req.body.toString("utf8")); // ... handle event res.status(200).end(); }, );
◆ Retry policy
- Success window: your endpoint must respond
2xxwithin 10 s. Anything else (4xx, 5xx, timeout, connection error) is treated as a failed delivery. - Backoff: failed deliveries are retried with exponential backoff for up to 24 hours. Schedule: 1m → 5m → 30m → 2h → 6h.
- Endpoint health: if 3+ consecutive deliveries fail in a 24h window, the endpoint enters
degradedstate and surfaces in your dashboard. After 24h of continuous failure, it auto-pauses; resume manually once your receiver is fixed. - Idempotency: every delivery carries a unique
id(e.g.evt_dlv_01HW…). Dedupe on it; retries reuse the same id, so the same delivery never reaches your handler twice.