Webhooks

Push event updates to your servers in real time. Each delivery is a POST carrying an event payload and a CMC-Signature header. Verify the signature using the endpoint's signing secret before trusting the body.

Event types

TypeTriggers when
events.createdAn event is published for the first time.
events.updatedA published event is edited, temporarily unpublished, or republished with the same id.
events.cancelledAn event is permanently removed from the catalog, whether cancelled by a project or deleted by the editorial team.
events.high-impactAn event reaches impact >= 7.5 for the first time. Fires once per event lifecycle.

Delivery payload

Every delivery uses the same outer envelope. Its evt_dlv_* id identifies the delivery and is distinct from data.id, which is the exact numeric API V2 event id serialized as a string. Created, updated, and high-impact deliveries carry current event data. Cancelled deliveries contain only the event's id, slug, title, and cancelled: true. Use data.id to remove it from your local catalog.

{
  "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 2xx within 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 degraded state 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…). Retries reuse the same id and may reach your handler more than once, so persist that id and ignore duplicates.