Webhooks endpoints
The webhooks endpoints let you manage your company's webhook subscriptions programmatically: create a new endpoint, list existing ones, update events or URL, disable, and delete.
For the receiving side of webhooks (verifying signatures, handling retries, event payloads), see Webhooks.
GET /api/v1/webhooks
List all webhook endpoints configured for your company.
Required scope: webhooks:read
Example
curl https://distribu.app/api/v1/webhooks \
-H "Authorization: Bearer dk_..."
Response
{
"data": [
{
"id": "clxxwebhook1...",
"url": "https://api.your-system.com/webhooks/distribu",
"events": ["order.created", "order.status_changed"],
"isActive": true,
"secretRotationGraceExpiresAt": null,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-04-10T09:30:00.000Z"
}
]
}
Notes on fields
secretis never included in this response — it's only returned once, at creation time. Store it when you get it.secretRotationGraceExpiresAt— Non-null when the webhook is currently in a rotation grace window (both the old and new secret are accepted). See Secret rotation below.- No pagination. There's a hard cap of 10 webhooks per company, so this endpoint always returns everything in one shot.
POST /api/v1/webhooks
Create a new webhook endpoint.
Required scope: webhooks:write
Request body
{
"url": "https://api.your-system.com/webhooks/distribu",
"events": ["order.created", "order.status_changed"],
"isActive": true
}
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | yes | HTTPS or HTTP URL. 1–2048 chars. |
events | string[] | yes | At least one valid event name. See Event types for the full catalog. |
isActive | boolean | no | Defaults to true. Set to false to register the endpoint but not fire events yet. |
Example
curl -X POST https://distribu.app/api/v1/webhooks \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.your-system.com/webhooks/distribu",
"events": ["order.created", "order.status_changed"]
}'
Response
201 Created. The secret field is returned only on this
response — copy it somewhere safe immediately.
{
"data": {
"id": "clxxwebhook1...",
"url": "https://api.your-system.com/webhooks/distribu",
"events": ["order.created", "order.status_changed"],
"isActive": true,
"secretRotationGraceExpiresAt": null,
"createdAt": "2026-04-17T14:22:00.000Z",
"updatedAt": "2026-04-17T14:22:00.000Z",
"secret": "whsec_AbCdEfGhIjKlMnOpQrStUvWxYz0123456789-abcd"
}
}
The secret is 24 random bytes, base64url-encoded, prefixed with
whsec_ — around 37 characters total. Use it to verify incoming
payloads via HMAC-SHA256; see
Signature verification.
Errors
| Status | Message |
|---|---|
400 | Invalid JSON body. |
400 | URL is required. |
400 | Invalid URL. |
400 | At least one event is required. |
400 | Unknown event: "{name}". |
409 | Maximum of 10 webhooks per company. |
GET /api/v1/webhooks/{id}
Fetch a single webhook's config.
Required scope: webhooks:read
Response
Same shape as one element of the list response. No secret.
{
"data": {
"id": "clxxwebhook1...",
"url": "https://api.your-system.com/webhooks/distribu",
"events": ["order.created", "order.status_changed"],
"isActive": true,
"secretRotationGraceExpiresAt": null,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-04-10T09:30:00.000Z"
}
}
Errors
404—Webhook not found.— No webhook with that ID in your company.
PATCH /api/v1/webhooks/{id}
Update a webhook's URL, events, or active state. Every field is optional.
Required scope: webhooks:write
Request body
{
"url": "https://new-host.your-system.com/webhooks/distribu",
"events": ["order.created"],
"isActive": false
}
| Field | Type | Notes |
|---|---|---|
url | string | 1–2048 chars. |
events | string[] | Replaces the full event list — not additive. Send the complete set you want subscribed. |
isActive | boolean | Toggle the endpoint on/off. |
Example
# Disable a webhook
curl -X PATCH https://distribu.app/api/v1/webhooks/clxxwebhook1... \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{ "isActive": false }'
Response
The full updated webhook, no secret.
Errors
| Status | Message |
|---|---|
400 | Invalid URL. |
400 | At least one event is required. |
400 | Unknown event: "{name}". |
404 | Webhook not found. |
DELETE /api/v1/webhooks/{id}
Permanently delete a webhook. No confirmation, no undo — the row and its delivery log are removed.
Required scope: webhooks:write
Example
curl -X DELETE https://distribu.app/api/v1/webhooks/clxxwebhook1... \
-H "Authorization: Bearer dk_..."
Response
{
"data": {
"id": "clxxwebhook1...",
"deleted": true
}
}
Errors
404—Webhook not found.
Secret rotation
Secret rotation — generating a new signing secret while keeping the
old one valid during a grace window — is available in the dashboard
(Settings → Webhooks → Rotate secret) but is not currently
exposed over the API.
When a rotation is in progress:
- The webhook's
secretRotationGraceExpiresAtfield is set to the cutover time. - Incoming webhook deliveries include both an
X-Webhook-Signatureheader (new secret) and anX-Webhook-Signature-Oldheader (old secret) so your receiver can migrate without downtime. - After the grace window expires, only the new secret is used.
If rotating secrets over the API is blocking you, email support@distribu.app — it's on the roadmap.
Event catalog
events[] must contain only valid event names. The full list:
| Event | Fires when… |
|---|---|
order.created | A new order is placed (storefront or API). |
order.status_changed | An order transitions between statuses. |
order.shipped | An order transitions specifically to SHIPPED. |
order.cancelled | An order transitions specifically to CANCELLED. |
customer.created | A new customer account is created. |
customer.updated | A customer's details change. |
product.updated | A product is edited. |
product.low_stock | A product's stock crosses below its low-stock threshold. |
invoice.paid | A Stripe invoice succeeds (subscription billing). |
return.created | A return is opened. |
return.approved | A return transitions to APPROVED. |
refund.processed | A refund is issued. |
See Event types for the payload shape of each.
What's not here (yet)
POST /api/v1/webhooks/{id}/rotate-secret— Secret rotation is dashboard-only today.- Delivery log access. The per-delivery history (status codes, response times) visible in the dashboard isn't exposed over the API. Use the dashboard for forensics.
- Manual redelivery. The "Resend" button in the dashboard doesn't have an API equivalent.
Related:
- Webhooks overview — the receiving side.
- Signature verification — how to validate incoming payloads with the secret.
- Event types — payload schemas.
