Looking for the full interactive reference?

Open API Reference →

Webhooks

HMAC-SHA256 signed deliveries, 72-hour dual-secret rotation grace window, capped exponential retries, replay via API.

Signing

Every delivery carries three headers plus the JSON payload. The signature is HMAC-SHA256 of the raw request body using the signing secret the console revealed when you created the endpoint.

http
X-GA-Webhook-Delivery: <uuid>
X-GA-Webhook-Timestamp: 2026-05-28T12:03:11Z
X-GA-Webhook-Signature: sha256=<hex(hmac(secret, rawBody))>
Content-Type: application/json

Node.js verifier:

js
const crypto = require("crypto");
function verify(rawBody, headerSig, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret)
                      .update(rawBody)
                      .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(headerSig),
  );
}

Python verifier (uses constant-time compare to resist timing attacks):

py
import hmac, hashlib

def verify(raw_body: bytes, header_sig: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode("utf-8"),
        raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, header_sig)

Rotation

Rotating a signing secret opens a 72-hour grace window during which every delivery is signed with both the new and the old secret. Receivers may accept either; once the window closes the old secret stops signing. This lets you roll your verifier without dropping deliveries.

bash
Day 0  : primary=A  secondary=(none)
Day T  : rotate            -> primary=B  secondary=A   (72h grace window)
Day T+72h: window closes   -> primary=B  secondary=(none)

During the grace window every delivery is signed twice with both A and B
(in separate X-GA-Webhook-Signature- headers). Receivers may accept either.

Retry & backoff

Failed deliveries are retried up to five times with exponential backoff starting at one second. After the final attempt the endpoint is marked failed for that delivery; replay manually if needed.

AttemptDelay
1immediate
21s
35s
425s
5125s (~2m)
6give up + mark failed

Replay

Re-deliver a single event by ID. Available from the console under Settings → Integrations → Event log and via the API endpoint shown below. The events:replay scope action is required.

bash
curl -X POST \
  -H "Authorization: Bearer gaf_pk_<your-token>" \
  -H "X-Org-Id: <your-organization-uuid>" \
  https://api.gaflight.io/api/v1/public/events/evt_01HZ.../replay

Idempotency

Every delivery carries a stable X-GA-Webhook-Delivery UUID. Dedupe on this header — the same delivery ID may arrive multiple times if your receiver times out and we retry. Consumers must be idempotent; exactly-once is not guaranteed.