Webhooks API
Subscribe an HTTPS endpoint to project events, and inspect what was delivered.
Webhook endpoints receive a signed HTTPS POST whenever a subscribed event happens. See Receiving Webhooks for the payload format, signature verification, and retry behaviour.
Endpoints are scoped to a project. The signing key is returned in full exactly
once — at creation and on rotation. Every other response exposes only
secretHint, the key's last four characters.
List Endpoints
GET /v1/projects/:projectId/webhooksReturns every endpoint in the project with its health state.
Auth: Required (member, scope: webhooks:read)
{
"success": true,
"data": [
{
"id": "clw1a2b3c",
"name": "Email tracking",
"description": null,
"url": "https://api.example.com/webhooks/datablock",
"events": ["email.delivered", "email.bounced"],
"enabled": true,
"secretHint": "9f2c",
"consecutiveFailures": 0,
"disabledAt": null,
"disabledReason": null,
"lastSuccessAt": "2026-07-28T09:12:00.000Z",
"lastFailureAt": null,
"createdAt": "2026-07-01T10:00:00.000Z",
"updatedAt": "2026-07-28T09:12:00.000Z"
}
]
}Get Endpoint
GET /v1/projects/:projectId/webhooks/:endpointIdReturns the endpoint plus delivery counts by status.
Auth: Required (member, scope: webhooks:read)
Create Endpoint
POST /v1/projects/:projectId/webhooksCreates an endpoint and returns its signing key. Store the key now — it is not retrievable afterwards. The URL must use HTTPS.
Auth: Required (member, non-viewer, scope: webhooks:write)
{
"name": "Email tracking",
"url": "https://api.example.com/webhooks/datablock",
"events": ["email.delivered", "email.bounced", "email.complained"]
}Update Endpoint
PATCH /v1/projects/:projectId/webhooks/:endpointIdUpdates the name, description, URL, subscribed events, or enabled state. Any field may be omitted. Re-enabling an endpoint also clears its failure streak.
Auth: Required (member, non-viewer, scope: webhooks:write)
Delete Endpoint
DELETE /v1/projects/:projectId/webhooks/:endpointIdPermanently deletes the endpoint, its delivery history, and any events still queued for it.
Auth: Required (member, non-viewer, scope: webhooks:write)
Resume a Paused Endpoint
POST /v1/projects/:projectId/webhooks/:endpointId/resumeRe-enables an endpoint that was paused after repeated failures and clears its failure streak. Events queued while it was paused were never dropped — they are delivered right after the resume.
Auth: Required (member, non-viewer, scope: webhooks:write)
Rotate the Signing Key
POST /v1/projects/:projectId/webhooks/:endpointId/rotate-secretGenerates a new signing key and returns it in full. The old key stops working immediately, so update your receiver in the same change.
Auth: Required (member, non-viewer, scope: webhooks:write)
{
"success": true,
"data": {
"id": "clw1a2b3c",
"secret": "whsec_…"
}
}Send a Test Event
POST /v1/projects/:projectId/webhooks/:endpointId/testDelivers a synthetic event immediately and returns what your endpoint answered. Test sends never count towards the auto-pause failure streak.
Auth: Required (member, non-viewer, scope: webhooks:write)
{
"eventType": "email.delivered"
}eventType is optional and defaults to the endpoint's first subscribed event.
List Deliveries
GET /v1/projects/:projectId/webhooks/:endpointId/deliveriesCursor-paginated delivery log, newest first, with the request payload and the response your endpoint returned.
Auth: Required (member, scope: webhooks:read)
Query parameters
| Parameter | Description |
|---|---|
status | PENDING, SUCCEEDED, or FAILED |
eventType | Restrict to one event type |
limit | 1–100, default 25 |
cursor | nextCursor from the previous page |
{
"success": true,
"data": {
"deliveries": [
{
"id": "clw9x8y7z",
"eventType": "email.bounced",
"eventId": "0100018f…:email.bounced",
"payload": { "messageId": "0100018f…", "email": "[email protected]" },
"status": "SUCCEEDED",
"attempt": 2,
"nextAttemptAt": null,
"responseStatus": 200,
"responseBody": "ok",
"errorMessage": null,
"durationMs": 143,
"deliveredAt": "2026-07-28T09:12:00.000Z",
"createdAt": "2026-07-28T09:11:28.000Z"
}
],
"nextCursor": null
}
}Replay a Delivery
POST /v1/projects/:projectId/webhooks/:endpointId/deliveries/:deliveryId/replayQueues the same payload again as a new delivery. The original row is kept, so the log still shows what happened the first time. The endpoint must be enabled.
Auth: Required (member, non-viewer, scope: webhooks:write)