Skip to content

Webhooks

See the Webhooks guide for events, signatures and retries. Operator and above.

EndpointWhat it does
GET /webhook-endpointsThe account’s webhooks, and eventTypes, the events you can subscribe to.
POST /webhook-endpointsAdd one. Send a client-generated id (whk_…), an https url, events (a list, or ["*"]) and a sealed meta naming it. Returns webhook and its secret, shown only this once. 10 per account. Session only.
PATCH /webhook-endpoints/:idChange url, events or meta, or set status to active or disabled. Switching one back on clears its failure record. Session only.
DELETE /webhook-endpoints/:idRemove it and its delivery log. Session only.
POST /webhook-endpoints/:id/rotate-secretA new secret, shown only this once. The old one stops working at once. Session only.
POST /webhook-endpoints/:id/testSend a webhook.test event. Returns the deliveryId and eventId. Tests and redeliveries together are limited to 60 an hour.
GET /webhook-endpoints/:id/deliveriesThe delivery log, newest first, 50 at a time or limit up to 200. Filter with status (pending, succeeded or failed) and page with cursor. Returns deliveries and nextCursor. Kept 30 days.
POST /webhook-endpoints/:id/deliveries/:deliveryId/redeliverSend that delivery’s event again, with the same event id. Returns the new deliveryId.

“Session only” endpoints answer 403 session_required to an API key. An API key can list webhooks, read the delivery log, send a test and redeliver.

A webhook returns:

{
"id": "whk_k3v9x2mq7a8b",
"url": "https://example.com/mailcycle",
"events": ["message.received"],
"meta": { "…": "sealed" },
"status": "active",
"disabledReason": null,
"failingSince": null,
"lastSuccessAt": "2026-09-19T09:14:04.000Z",
"createdAt": "2026-09-18T10:02:11.000Z"
}

failingSince is set while every attempt since the last success has failed. disabledReason says why a webhook is off.

A delivery returns id, eventId, eventType, the event exactly as sent, status, attempts, responseStatus, error, createdAt, lastAttemptAt and nextAttemptAt.

CodeStatusMeaning
invalid_url400The URL is not https, uses an IP address or a local name, or points at Mailcycle.
plan_required403The plan does not include webhooks.
limit_reached409The account already has 10 webhooks.
webhook_disabled409Switch the webhook on before sending a test or an event again.
feature_disabled503Adding webhooks is paused for everyone. Deliveries to existing webhooks wait and go out afterwards.

© Northlab Studios Ltd, trading as Mailcycle. Registered in England and Wales, company no. 17462734. Registered office: 167-169 Great Portland Street, London W1W 5PF.