POST with the new state. A background worker on the API process polls every 2s, fires pending deliveries, and retries failures with an exponential backoff. After 8 consecutive failures the endpoint is marked inactive and a webhook_endpoint.failed meta-event fans out to any other still-active endpoints in the same workspace.
Register an endpoint
signing_secret is shown once; store it):
GET /webhook-endpoints or GET /webhook-endpoints/:id) omit signing_secret.
Signature
Every delivery carries:<timestamp>.<body> with your whsec_… secret, then compare with constant-time equality. Reject deliveries older than 5 minutes to prevent replay.
Verifier (Node)
Payload shape
delivery_id is unique per delivery — use it for idempotent receiver-side processing (the same event may be re-delivered after a transient receiver failure).
Retry schedule
1s → 5s → 30s → 5min → 30min → 2h → 12h between attempts. After the 8th attempt fails, the delivery is marked failed, the endpoint flips is_active = false, and a webhook_endpoint.failed meta-event fans out to other still-active endpoints in the workspace:
Events
| Object | Events |
|---|---|
person, company, deal | .created, .updated, .deleted |
note, task, activity | .created, .updated, .deleted |
custom_object_record | .created, .updated, .deleted |
schema | .attribute_added, .attribute_modified, .attribute_deprecated |
| meta | webhook_endpoint.failed |
"*" for everything, or pass a list of exact event names (no glob patterns in v1).
API surface
| Verb | Path | Notes |
|---|---|---|
| POST | /webhook-endpoints | Returns signing_secret (once) |
| GET | /webhook-endpoints | List, paginated |
| GET | /webhook-endpoints/:id | Single |
| DELETE | /webhook-endpoints/:id | Cascade deletes deliveries |
| GET | /webhook-endpoints/:id/deliveries | Audit log, newest first |
| POST | /webhook-endpoints/:id/test | Synchronous fire; returns receiver response |
Test endpoint
{event: "webhook_endpoint.test", data: {ping: "pong"}} to your URL and returns the receiver’s HTTP status + body. Doesn’t enqueue, doesn’t retry — just a single fire to confirm wiring is right.
Delivery audit
status is one of: pending, in_flight, delivered, failed. next_retry_at is the next scheduled attempt for pending rows; null once terminal.