Webhooks API Reference¶
Outbound webhooks let Centrali send signed HTTP POST requests to your systems whenever matching record events occur.
Use this page for endpoint shapes and lifecycle operations. For delivery semantics, verification examples, and migration guidance, see Outbound Webhooks and Outbound Webhook Migration (6.1).
Authentication¶
All webhook-management endpoints require:
Base URL¶
Webhook Subscription Object¶
{
"id": "6d6f4f59-9c85-4c9d-8a3d-4cfd4db2f6be",
"name": "Order Notifications",
"url": "https://your-app.com/webhooks/centrali",
"events": ["record_created", "record_updated"],
"recordSlugs": ["orders"],
"active": true,
"workspaceSlug": "acme",
"secret": "whsec_...",
"previousSecret": null,
"previousSecretValidUntil": null,
"createdAt": "2026-05-14T14:00:00.000Z",
"updatedAt": "2026-05-14T14:00:00.000Z"
}
Notes:
secretis only returned on create and rotate-secret responsespreviousSecretandpreviousSecretValidUntilare server-managed rotation fields
Create a Subscription¶
POST /webhook-subscriptions
Request Body¶
{
"name": "Order Notifications",
"url": "https://your-app.com/webhooks/centrali",
"events": ["record_created", "record_updated"],
"recordSlugs": ["orders"],
"active": true
}
Notes¶
recordSlugsis optional. Omit it to receive matching events across all collections.- Send an
Idempotency-Keyheader for safe retries.
List, Get, Update, Delete¶
List Subscriptions¶
GET /webhook-subscriptions
Returns an array of webhook subscription objects.
Get One Subscription¶
GET /webhook-subscriptions/{id}
Returns the webhook subscription object directly.
Update a Subscription¶
PATCH /webhook-subscriptions/{id}
Editable fields:
nameurleventsrecordSlugsactive
The signing secret is server-managed. Use the rotate-secret endpoint instead of patching secret fields directly.
Delete a Subscription¶
DELETE /webhook-subscriptions/{id}
Returns 204 No Content on success.
Rotate the Signing Secret¶
POST /webhook-subscriptions/{id}/rotate-secret
Rotation behavior in 6.1:
- Returns the new
secretonce - Moves the previous secret into
previousSecret - Sets
previousSecretValidUntilto 24 hours in the future - Causes outbound deliveries during the grace window to include two space-separated signatures
Send a Synthetic Test Delivery¶
POST /webhook-subscriptions/{id}/test
Dispatch a synthetic event through the production delivery path.
Optional Request Body¶
If omitted, event defaults to the first configured event on the subscription.
Response¶
Returns the created delivery row:
{
"id": "d87fd42a-cf29-4950-9cf9-44ff5df785fd",
"webhookSubscriptionId": "6d6f4f59-9c85-4c9d-8a3d-4cfd4db2f6be",
"workspaceSlug": "acme",
"event": "record_updated",
"attemptCount": 1,
"status": "success",
"httpStatus": 200,
"lastAttemptAt": "2026-05-14T14:12:00.000Z",
"nextAttemptAt": null,
"requestPayload": {
"event": "record_updated",
"workspaceSlug": "acme",
"recordId": "test-2f5f6b7c-8d9e-4012-9f88-41c868f95ca8",
"data": {
"source": "smoke-test"
},
"timestamp": "2026-05-14T14:12:00.000Z",
"isTest": true
}
}
The outbound request includes Centrali-Test-Event: true.
Get Endpoint Health¶
GET /webhook-subscriptions/{id}/health
Response¶
{
"successRate1h": 100,
"successRate24h": 99.2,
"totalDeliveries1h": 6,
"totalDeliveries24h": 243,
"lastFailureAt": "2026-05-14T09:48:21.000Z",
"lastFailureError": "Request failed with status code 500"
}
This is a customer-facing health summary. It does not expose the raw in-process circuit-breaker state.
Delivery History¶
List Deliveries for a Subscription¶
GET /webhook-subscriptions/{id}/deliveries
Query Parameters¶
| Parameter | Type | Description |
|---|---|---|
limit | number | Rows per page. Default 50. |
offset | number | Offset into the result set. Default 0. |
status | string | success, failed, or retrying |
since | string | ISO 8601 timestamp; only deliveries created at or after this time |
until | string | ISO 8601 timestamp; only deliveries created at or before this time |
Response Shape¶
{
"data": [
{
"id": "d87fd42a-cf29-4950-9cf9-44ff5df785fd",
"webhookSubscriptionId": "6d6f4f59-9c85-4c9d-8a3d-4cfd4db2f6be",
"workspaceSlug": "acme",
"event": "record_created",
"attemptCount": 2,
"status": "retrying",
"lastError": "Request failed with status code 500",
"httpStatus": 500,
"lastAttemptAt": "2026-05-14T14:15:00.000Z",
"nextAttemptAt": "2026-05-14T14:17:00.000Z",
"replayedFrom": null,
"createdAt": "2026-05-14T14:14:30.000Z",
"updatedAt": "2026-05-14T14:15:00.000Z"
}
],
"meta": {
"total": 1,
"limit": 50,
"offset": 0
}
}
List rows omit requestPayload and responseBody.
Get a Single Delivery¶
GET /webhook-subscriptions/{id}/deliveries/{deliveryId}
Returns the full delivery record, including requestPayload and responseBody.
Workspace-wide Delivery Helpers¶
GET /webhook-subscriptions/deliveries/recent
GET /webhook-subscriptions/deliveries/failed
Use these endpoints when you need the latest failures or recent activity across every subscription in the workspace.
Replay and Cancel¶
Replay a Delivery¶
POST /webhook-subscriptions/deliveries/{deliveryId}/retry
Returns:
{
"deliveryId": "a0b95d75-67c4-45b7-b3f5-9c3caee5217d",
"replayedFrom": "d87fd42a-cf29-4950-9cf9-44ff5df785fd",
"status": "retrying"
}
Replay creates a new delivery row and re-dispatches the original stored payload.
Cancel a Pending Retry¶
POST /webhook-subscriptions/deliveries/{deliveryId}/cancel
Returns:
{
"deliveryId": "d87fd42a-cf29-4950-9cf9-44ff5df785fd",
"status": "failed",
"lastError": "Cancelled by user"
}
Signing Model¶
6.1 outbound deliveries use:
webhook-idwebhook-timestampwebhook-signature
The signed input is ${webhook-id}.${webhook-timestamp}.${raw-body}. During the 24 hour rotation window, webhook-signature may contain multiple space-separated v1,<base64> values.
For worked verification examples in Node, Python, and Go, see Outbound Webhooks and Outbound Webhook Migration (6.1).