Webhooks management
Register, list, and revoke webhook subscriptions programmatically.
The actual webhook contract — events, signing, retries — is documented under Webhooks. This page covers the management API: creating, updating, and deleting subscriptions.
You can also manage webhooks from the panel (Settings → Webhooks). The API exists for repeatable infra-as-code setups.
Webhook object
{
"id": "wh_a1b2c3...",
"name": "Shipping integration",
"url": "https://erp.example.com/sellvik-events",
"events": ["order.created", "order.fulfilled", "order.cancelled"],
"enabled": true,
"failureCount": 0,
"lastDeliveryAt": "2026-05-27T13:45:00.000Z",
"createdAt": "2026-05-20T10:00:00.000Z"
}The secret field is only ever returned at creation time. It is not
queryable afterward. Lose it ⇒ delete and recreate the webhook.
List webhooks
GET /api/v1/admin/webhooksScope: webhooks:read
Query parameters
| Name | Type | Notes |
|---|---|---|
limit | integer (1–100) | Default 50. |
cursor | string | Opaque. |
Response
{
"items": [/* … Webhook objects without `secret` … */],
"nextCursor": null
}Create a webhook
POST /api/v1/admin/webhooksScope: webhooks:write
Request body
{
"name": "Shipping integration",
"url": "https://erp.example.com/sellvik-events",
"events": ["order.created", "order.fulfilled", "order.cancelled"]
}| Field | Required | Notes |
|---|---|---|
name | no | Human-readable label. Default null. |
url | yes | HTTPS only. http:// is rejected outside dev shops. |
events | yes | Non-empty array of event names. See Events. |
Response
HTTP/1.1 201 Created
{
"id": "wh_a1b2c3...",
"name": "Shipping integration",
"url": "https://erp.example.com/sellvik-events",
"events": ["order.created", "order.fulfilled", "order.cancelled"],
"enabled": true,
"secret": "whsec_a1b2c3d4e5f6...",
"createdAt": "2026-05-27T14:00:00.000Z"
}Store secret immediately. It's needed to verify incoming webhook
signatures. The same value never appears in any other response.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_body | Missing fields, invalid URL, unknown event name. |
| 400 | http_url_rejected | Trying to set an http:// URL on a non-dev shop. |
| 409 | duplicate_endpoint | Same URL already subscribed (for any event set). |
Get a webhook
GET /api/v1/admin/webhooks/{id}Scope: webhooks:read
Update a webhook
PATCH /api/v1/admin/webhooks/{id}Scope: webhooks:write
Any subset of:
{
"enabled": false,
"url": "https://new.example.com/sellvik-events",
"events": ["order.created"],
"name": "Shipping integration (paused)"
}Disabling stops new deliveries but does not invalidate the secret — re-enable to resume. Use this for incident response without losing the secret.
Delete a webhook
DELETE /api/v1/admin/webhooks/{id}Scope: webhooks:write
204 No Content. Pending deliveries continue draining for ~5 minutes after
deletion, then stop.
List webhook deliveries
GET /api/v1/admin/webhooks/{id}/deliveriesScope: webhooks:read
Returns delivery attempts for a webhook, newest first. Useful for debugging 4xx/5xx responses from your endpoint.
Query parameters
| Name | Type | Notes |
|---|---|---|
limit | integer (1–100) | Default 50. |
cursor | string | Opaque. |
status | enum | pending, succeeded, failed, dropped. |
Response
{
"items": [
{
"id": "del_a1b2c3...",
"event": "order.created",
"status": "succeeded",
"attempts": 1,
"lastAttemptAt": "2026-05-27T13:45:01.000Z",
"lastResponseCode": 200,
"lastResponseBody": "{\"received\":true}",
"deliveredAt": "2026-05-27T13:45:01.000Z"
},
{
"id": "del_xyz...",
"event": "order.fulfilled",
"status": "failed",
"attempts": 5,
"lastAttemptAt": "2026-05-27T13:50:30.000Z",
"lastResponseCode": 502,
"lastResponseBody": "Bad Gateway",
"deliveredAt": null
}
],
"nextCursor": null
}Deliveries are retained for 30 days.