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

TypeTriggers when
events.createdEditorial team adds a new event to the catalog.
events.updatedMaterial change to an existing event (date, impact score, description, source).
events.cancelledEvent is removed from the catalog (cancelled, retracted, or merged into another).
events.high-impactAn 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": "2025-10-01",
  "deliveredAt": "2026-04-29T14:22:08Z",
  "data": {
    "id": "evt_2026_05_06_eth_pectra",
    "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 the HMAC-SHA256 of the raw request body, signed with your endpoint's signing secret. Reject any request whose signature doesn't match. Anything else lets forged deliveries through.

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 sig = req.header("CMC-Signature");
    const expected = crypto
      .createHmac("sha256", SECRET)
      .update(req.body)
      .digest("hex");

    if (
      !sig ||
      !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
    ) {
      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…). Dedupe on it; retries reuse the same id, so the same delivery never reaches your handler twice.

Endpoints

GET/v2/webhooksElite+

List your webhooks

Returns every webhook you've registered. The signingSecret field is masked; use the rotate endpoint or the dashboard to retrieve a usable secret.

Parameters

No parameters.

Response

FieldTypeDescription
dataarray<Webhook>All registered webhooks.

Webhook

FieldTypeDescription
idstringStable webhook id (e.g. `wh_01HW...`).
namestringFriendly label for your dashboard.
urlstringYour endpoint that receives `POST` deliveries.
eventsstring[]Subscribed event types. See the supported list in the resource description.
apiVersionstringAPI version the payload is shaped against (e.g. `2025-10-01`). Locked at creation time so future API changes don't break your verifier.
signingSecretstringHMAC secret used to sign each delivery's body. Returned in full ONLY on creation and on rotation. Subsequent reads return a masked value.
statusstringOne of `healthy` · `degraded` · `paused`. `degraded` fires when 3+ consecutive deliveries fail in a 24h window.
createdAtiso8601When the webhook was created.

Request

curl -X GET "https://api.coinmarketcal.com/v2/webhooks" \
  -H "Authorization: Bearer $COINMARKETCAL_API_KEY" \
  -H "Accept: application/json"

Example response

{
  "data": [
    {
      "id": "wh_01HW8K2D5N",
      "name": "events-prod",
      "url": "https://api.acme.io/cmc/webhooks",
      "events": [
        "events.created",
        "events.updated"
      ],
      "apiVersion": "2025-10-01",
      "signingSecret": "whsec_••••5e6f",
      "status": "healthy",
      "createdAt": "2026-04-12T08:30:00Z"
    }
  ]
}
POST/v2/webhooksElite+

Create a webhook

Registers a new endpoint. Returns the full signingSecret; store it now, subsequent reads will mask it.

Parameters

FieldInTypeRequiredDescription
namebodystringyesFriendly label (≤ 64 chars).
urlbodystringyesYour `https://` endpoint. Must respond `2xx` within 10 s.
eventsbodystring[]yesAt least one of: `events.created`, `events.updated`, `events.cancelled`, `events.high-impact`.
apiVersionbodystringnoPin to a specific API version (e.g. `2025-10-01`). Defaults to the latest at creation time.

Response

FieldTypeDescription
idstringStable webhook id (e.g. `wh_01HW...`).
namestringFriendly label for your dashboard.
urlstringYour endpoint that receives `POST` deliveries.
eventsstring[]Subscribed event types. See the supported list in the resource description.
apiVersionstringAPI version the payload is shaped against (e.g. `2025-10-01`). Locked at creation time so future API changes don't break your verifier.
signingSecretstringHMAC secret used to sign each delivery's body. Returned in full ONLY on creation and on rotation. Subsequent reads return a masked value.
statusstringOne of `healthy` · `degraded` · `paused`. `degraded` fires when 3+ consecutive deliveries fail in a 24h window.
createdAtiso8601When the webhook was created.

Request

curl -X POST "https://api.coinmarketcal.com/v2/webhooks" \
  -H "Authorization: Bearer $COINMARKETCAL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example",
  "url": "example",
  "events": [
    "example"
  ],
  "apiVersion": "example"
}'

Example response

{
  "id": "wh_01HW8K2D5N",
  "name": "events-prod",
  "url": "https://api.acme.io/cmc/webhooks",
  "events": [
    "events.created",
    "events.updated"
  ],
  "apiVersion": "2025-10-01",
  "signingSecret": "whsec_7e8f1a2b3c4d5e6f7e8f1a2b3c4d5e6f",
  "status": "healthy",
  "createdAt": "2026-04-12T08:30:00Z"
}
DELETE/v2/webhooks/{id}Elite+

Delete a webhook

Permanently removes the endpoint. In-flight deliveries already queued will not be sent. Returns 204 No Content on success.

Parameters

FieldInTypeRequiredDescription
idpathstringyesThe webhook id.

Response

FieldTypeDescription
stringNo body. The `204` status is the success signal.

Request

curl -X DELETE "https://api.coinmarketcal.com/v2/webhooks/{id}" \
  -H "Authorization: Bearer $COINMARKETCAL_API_KEY" \
  -H "Accept: application/json"

Example response

No body (empty response).