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.v1campaign.updated.v1campaign.status_changed.v1line_item.created.v1line_item.updated.v1creative.created.v1creative.updated.v1conversion_event.created.v1segment.created.v1segment.evaluated.v1workspace.created.v1sync.succeeded.v1sync.failed.v1report.ready.v1budget.threshold.v1spend.anomaly.v1decision.applied.v1package.created.v1deal.created.v1proposal.created.v1proposal.signed.v1change_request.created.v1change_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).