Webhooks & events

Every domain mutation emits a versioned event. Register HTTPS endpoints via POST /api/v1/webhooks (or the console) and we deliver matching events as JSON POSTs with retries and exponential backoff for up to 8 attempts. Failed deliveries can be replayed from the console or POST /api/v1/webhook-deliveries/{id}/replay.

Event types

  • campaign.created.v1
  • campaign.updated.v1
  • campaign.status_changed.v1
  • line_item.created.v1
  • line_item.updated.v1
  • creative.created.v1
  • creative.updated.v1
  • conversion_event.created.v1
  • segment.created.v1
  • segment.evaluated.v1
  • workspace.created.v1
  • sync.succeeded.v1
  • sync.failed.v1
  • report.ready.v1
  • budget.threshold.v1
  • spend.anomaly.v1
  • decision.applied.v1
  • package.created.v1
  • deal.created.v1
  • proposal.created.v1
  • proposal.signed.v1
  • change_request.created.v1
  • change_request.reviewed.v1

Types are append-only and versioned (.v1): payload shape never changes within a version. Subscribe to specific types or leave the filter empty for all.

Delivery format

POST <your endpoint>
Content-Type: application/json
X-Waveband-Event: campaign.status_changed.v1
X-Waveband-Delivery: <delivery-uuid>
X-Waveband-Signature: sha256=<hex hmac>

{
  "id": "<event-uuid>",
  "type": "campaign.status_changed.v1",
  "entityType": "campaign",
  "entityId": "<campaign-uuid>",
  "workspaceId": "<workspace-uuid>",
  "payload": { "from": "active", "to": "paused" },
  "occurredAt": "2026-08-01T12:00:00.000Z"
}

Verifying signatures

Each endpoint has a signing secret (shown once at creation). Compute an HMAC-SHA256 of the raw request body with your secret and compare to the header:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret: string, body: string, header: string): boolean {
  const expected = "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Respond with any 2xx status within 10 seconds. Non-2xx responses and timeouts are retried with backoff; after 8 failed attempts the delivery is marked dead (replayable).

Webhooks & events — Waveband Docs