Webhooks

The same webhooks the settings screen manages, from a setup script. What they send, and how to verify it, is on the webhooks guide.

List webhooks

GET /api/v1/webhooks
Scope: webhooks:read

Response:
[
  {
    "id": "w7c4m2t9xk5b8q1h",
    "name": "CI notifier",
    "type": "http",
    "url": "https://ci.acme.dev/hooks/mailclutch",
    "is_enabled": true,
    "inbox": { "id": "k3n8x2p9qa7c1m4z", "name": "Acme — staging" },
    "last_triggered_at": "2026-09-02T09:14:23.000000Z",
    "created_at": "2026-08-20T16:02:11.000000Z"
  }
]

inbox is null for a webhook that fires for every inbox of the organization. The signing secret is never returned here.

Create a webhook

POST /api/v1/webhooks
Scope: webhooks:write
Idempotency-Key: <recommended>

{
  "name": "CI notifier",
  "type": "http",
  "url": "https://ci.acme.dev/hooks/mailclutch",
  "inbox_id": "k3n8x2p9qa7c1m4z"
}

Response, 201:
{
  "webhook": { …as listed above… },
  "secret": "3kd9…"
}
Fields accepted when creating a webhook
FieldAccepts
nameRequired, up to 100 characters
typehttp (default) or slack
urlRequired, HTTPS only, up to 2048 characters
inbox_idOptional. An inbox the token reaches; omit or null for the whole organization

The secret is shown once. Store it: it signs every delivery, and the webhooks guide shows how to verify the signature. A Slack webhook has no secret — the URL is the credential.

Update or delete a webhook

PATCH /api/v1/webhooks/{id}
Scope: webhooks:write

{ "is_enabled": false }
{ "name": "…", "url": "https://…", "inbox_id": null }

Response: the webhook

DELETE /api/v1/webhooks/{id}
Scope: webhooks:write
→ { "deleted": true }

{id} is the webhook's id, as listed or returned on creation. Send only the fields to change. Disabling keeps the webhook and its history; deleting removes both.

Delivery history

GET /api/v1/webhooks/{id}/deliveries
Scope: webhooks:read

Response, the last 50:
[
  { "id": "d2r8v5n1jx6p3k9w", "success": true,  "response_code": 200, "duration_ms": 84,   "error": null, "created_at": "…" },
  { "id": "d9h4s7b2mq5t8c1z", "success": false, "response_code": 503, "duration_ms": 3012, "error": "Server error", "created_at": "…" }
]

The same rows the settings screen shows. A run of failures usually means the receiving endpoint was down; the webhook keeps retrying on its own schedule.