Skip to main content
Webhooks push events to a URL you control instead of you polling for them. They’re the server-to-server equivalent of the discovery event stream, for callers that run batch jobs or don’t hold a connection open.
The only event a subscription can register today is discovery.revision. Media buy decisions, task completion and creative reviews don’t send webhooks yet; poll tasks and media buy status for those. Audience and syndication outcomes arrive as notifications, and an audience sync can call your URL directly: see Audience and syndication events.
All paths are under https://api.semicola.com/api/v2/buyer.

Register a subscription

The secret is stored encrypted and never echoed back, so keep your own copy when you register.

List and delete

  • GET /webhook-subscriptions returns every subscription on the account, newest first, without secrets.
  • DELETE /webhook-subscriptions/{id} stops deliveries at once and returns { "success": true, "id": … }. An id that doesn’t exist, or belongs to another account, returns 404.

Verify deliveries

Every delivery carries X-Webhook-Signature: the hex-encoded HMAC-SHA256 of the exact request body, keyed with your subscription’s secret. Recompute it over the raw body and compare before trusting the payload.
There’s no timestamp header and no sha256= prefix, and the signed message is the body alone. Hash the raw bytes you received, not a re-serialized copy: key order or whitespace changes the signature.

Audience and syndication events

These outcomes are raised as notifications (in-app, and by email if you turn email on for the type): Webhook subscriptions can’t list these types yet (eventTypes accepts only discovery.revision), so read them from notifications or poll syndication-status.

The audience sync callback

An audience sync (POST /advertisers/{advertiserId}/audiences/sync or sync_audiences) can call your URL when it finishes: pass pushNotificationConfig. The details are under Audiences.

Delivery and failures

Each event is one POST with a 5-second timeout. A response outside 2xx is a failure, and it isn’t retried: discovery revisions are time-sensitive, and a late copy would be stale.
  • Each failure adds one to failureCount; a success resets it to zero.
  • After 10 consecutive failures the subscription’s status becomes failed and deliveries stop. Check status, failureCount and lastFailure, then delete and re-register once your endpoint is healthy.
Treat webhooks as an optimization, not your only source of truth. An endpoint that was down can catch up by reading the discovery’s products (GET /discovery/{id}/products).

discovery.revision

Fires when a progressive discovery’s snapshot advances: the same moment the event stream (GET /discovery/{id}/events) emits a revision.
pendingAgents lists the sellers still answering, by slug. The payload says how far the discovery has got; read the products themselves from the discovery. Each revision goes to the subscriptions that are active when it happens; earlier revisions aren’t replayed to a new subscription.