POST that names the job, and your server then reads the job with its API key.
Each delivery follows this pattern:
Create a webhook
This request creates a webhook for completed and failed parses. It sends a static header with every delivery, such as a token your gateway checks.client is the one from SDKs. The response is 201 with the new webhook:
secretsigns every delivery. Store it now: only this response and a rotate return it.urlmust be a publichttpsURL on port 443, and it can’t change.events_fromgives, for each event, the time it started counting: 15 seconds after you added it. Only jobs created after that time send the event. It appears only in responses.pingsays whether a testwebhook.pingreached your endpoint. The first ping waits only 5 seconds, so atimeoutmay only mean your endpoint was slow to start. Retest withPOST /webhook/{webhook_id}/ping, which waits 15.
Events
An event’s name is<job type>.<status>, such as extract.completed:
A webhook receives only the events in its
events list, and none if you leave the list out. Sync jobs send events too, but never queued. Each job in a batch or pipeline sends its own endpoint’s events, and a pipeline also sends pipeline events. There are no batch events.
Each delivery’s body names the job, not its result:
created_at is when the job reached that status. A test ping has the type webhook.ping, and its data names the webhook.
Each delivery carries these Standard Webhooks headers, plus your static headers:
Verify the signature
Each signature isv1, followed by the base64 HMAC-SHA256 of <webhook-id>.<webhook-timestamp>.<body>, keyed with the base64-decoded part of the secret after whsec_. Verify the raw body before you parse it, and reject old timestamps. Any Standard Webhooks library does this for you.
This function returns True when any of a delivery’s signatures matches:
Receive deliveries
Return a2xx within 5 seconds, and do the work after you respond. This Flask endpoint verifies each delivery, drops retries it has already seen, and queues the rest:
already_seen and enqueue are yours to write. When you handle an event, read the job’s current status with client.<endpoint>.get(data.id) before acting on it. Events can arrive out of order, and if a job’s status changes before an event is delivered, Pulse may send only the newer status. If your organization deletes results on first read, read each result once, in one place.
Retries and switch-off
Pulse doesn’t follow redirects, so a3xx counts as a failure. A failed delivery is retried, with growing delays of up to a day, for about 35 hours.
Pulse turns a webhook off when:
- 10 events in a row can’t be delivered after all their retries;
- its deliveries have been failing for 3 days; or
- your endpoint returns
410 Gone.
enabled then reads false, and its disabled_reason says why. To turn it back on, send PATCH /webhook/{webhook_id} with {"enabled": true}. If it was off for 30 days or more, it then counts only jobs created from 15 seconds after that request.
Rotate the secret
POST /webhook/{webhook_id}/rotate returns a new secret, or you can send your own as secret in a PATCH. For the next 24 hours, each delivery is signed with both the old and the new secret, so you can deploy the new one without missing an event.
Manage webhooks
You can also list, read, change and delete your organization’s webhooks.PATCH changes a webhook’s events, headers, description or secret, or turns it on or off. The Webhook API reference covers every route, with its hourly limits.