Skip to documentation content

Webhooks

Receive CookieBeam events as signed HTTP POST requests on your own endpoints.

Webhooks deliver CookieBeam events to an HTTPS endpoint you control. Webhooks are a plan-gated feature, and endpoint management is currently restricted: endpoints are configured for your team by CookieBeam rather than self-served in the dashboard. Each endpoint subscribes to a set of event types and has a signing secret, which starts with whsec_.

There are no public REST endpoints for webhook management. The webhooks:read and webhooks:write API key scopes exist on keys but currently gate nothing.

Event types

Six event types are currently emitted:

  • consent.given — a visitor recorded an explicit consent choice
  • scan.completed — a cookie scan finished
  • scan.policy_update_needed — scan results require a policy review
  • dsar.request_submitted — a data subject access request was submitted
  • banner.published — a banner configuration was published
  • compliance.report_generated — a compliance report was generated

The endpoint configuration form may list additional event types that are registered but not yet emitted by any code path — subscribing to one of those is accepted but delivers nothing. Subscribe only to the six above.

Delivery format

Each delivery is an HTTP POST with a JSON envelope:

{
  "event": "consent.given",
  "data": {
    "consentLogId": "9b2f7c14-8b3a-4e21-9d5c-1a2b3c4d5e6f",
    "bannerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "consentGiven": { "necessary": true, "analytics": false },
    "pageUrl": "https://example.com/pricing",
    "timestamp": "2026-08-13T12:00:00.000Z"
  },
  "timestamp": "2026-08-13T12:00:01.000Z",
  "deliveryId": "d290f1ee-6c54-4b01-90e6-d701748f0851"
}

The data payload is the example above for consent.given; other event types carry their own payloads. For dsar.request_submitted, data.receivedAt is the ISO 8601 time the submission was received and starts the deadline clock. data.submittedAt is the later verification time. The payload also includes deadlineAt and slaPolicy.

Request headers:

HeaderValue
Content-Typeapplication/json
User-AgentCookieBeam-Webhooks/1.0
X-CookieBeam-TimestampUnix time in seconds when the delivery was signed
X-CookieBeam-Signature-V1One or more v1=<hex> entries, comma-separated: HMAC-SHA256 of timestamp + "." + raw body, keyed with an endpoint secret
X-CookieBeam-EventThe event type, for example consent.given
X-CookieBeam-DeliveryThe delivery ID, matching deliveryId in the body
X-CookieBeam-SignatureLegacy, only for endpoints created before timestamped signatures (see below): HMAC-SHA256 hex digest of the raw body

Verify the signature

Verify X-CookieBeam-Signature-V1 before you trust a delivery:

  1. Read X-CookieBeam-Timestamp. Reject the request if it is missing, not a whole number, or more than 300 seconds away from your clock. This stops a captured request from being replayed later.
  2. Build the signed string: the timestamp, a dot, then the raw request body exactly as received.
  3. For each secret you accept (normally one; two while you rotate), compute the HMAC-SHA256 hex digest of that string.
  4. Split X-CookieBeam-Signature-V1 on commas and keep the entries that start with v1=. Accept the request if any entry equals one of your digests, compared in constant time. Otherwise reject it.
timestamp = header("X-CookieBeam-Timestamp")
if timestamp is not digits or abs(now_seconds() - int(timestamp)) > 300: reject
signed = timestamp + "." + raw_body
candidates = [e[3:] for e in header("X-CookieBeam-Signature-V1").split(",") if e starts with "v1="]
for secret in accepted_secrets:
    expected = hex(hmac_sha256(key = secret, message = signed))
    if any(constant_time_equal(expected, c) for c in candidates): accept
reject

Use the raw body as received. Parsing and re-serializing the JSON can change the bytes and produce a false mismatch.

The v1= prefix names the signature scheme. A later scheme would be added as another prefix in the same header, so ignore entries you do not recognise rather than failing on them.

The legacy X-CookieBeam-Signature header

Endpoints created before timestamped signatures still receive X-CookieBeam-Signature, unchanged in name and format: the HMAC-SHA256 hex digest of the raw body alone, keyed with the endpoint secret. Receivers that verify it today keep working.

It has no timestamp, so it does not protect against replays. It is sent for each existing endpoint until that endpoint's end date, which is announced by email at least six months ahead, with a reminder one month before. Once your receiver verifies X-CookieBeam-Signature-V1, you can ask CookieBeam to switch it off earlier for that endpoint; switching it off cannot be undone. Endpoints created now receive only the v1 headers.

If your receiver checks both during the move, check them separately. Never accept a request on the legacy digest after the v1 check failed: that would let an old captured request through.

Signing secrets

The signing secret is shown once, when the endpoint is created or the secret is rotated, and is stored encrypted. It cannot be displayed again; if you lose it, ask CookieBeam to rotate it.

Rotating creates a new secret. You can keep the old one signing for up to 72 hours so you can update your receiver without missing events. During that overlap X-CookieBeam-Signature-V1 carries one v1= entry per secret (the new one first), and the legacy header, where it is still sent, stays signed with the old secret until the overlap ends.

Duplicates

A delivery can arrive more than once, for example when your endpoint answered after the 10-second timeout. Use X-CookieBeam-Delivery (or deliveryId in the body) to ignore deliveries you have already processed.

Receiving requirements

Your endpoint must:

  • Use HTTPS with a publicly resolvable host. Private, loopback, and reserved IP addresses are rejected when the endpoint is created and again at delivery time.
  • Answer directly. Redirects are refused and count as failed deliveries.
  • Respond within 10 seconds. The response body is recorded only up to 4,000 characters.
  • Return a 2xx status to acknowledge a delivery. Any other outcome follows the retry policy below.

Retries and disabling

Deliveries are queued and sent by a background runner that processes pending deliveries every few minutes. Each delivery is claimed by one run at a time, so overlapping runs do not send it twice.

A failed delivery is tried up to 8 times in total over about 27 hours: immediately, then after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours. Each delay includes random variation so that queued deliveries do not all arrive at once when your endpoint recovers.

Network errors, timeouts, HTTP 5xx, 408, and 429 responses are retried. Other 4xx responses are treated as permanent rejections and are not retried, because the endpoint rejected the request itself.

An endpoint that accumulates 10 consecutive delivery failures is disabled automatically, and the team owner is notified by email. Ask CookieBeam to re-enable the endpoint once it is healthy again.