Webhooks

An email sent through the API did not go out

Posted to the subscriptions to email.failed when an email sent through the API was recorded but did not go out — the status failed of GET /api/v1/emails/{id} — one event per address. reason says why: provider_rejected, safety_review, suspended or interrupted. A refusal that recorded nothing (quota, domain, suppression list…) produces no event: there is no email, only an error response. The test event (POST /api/v1/webhooks/{id}/test) arrives under this type too, with data: { test: true, message }: check data.test first.

postWebhookemail.failed

Headers

Mailcheer-Signaturestring required

t=<unix timestamp>,v1=<hex>: v1 is the HMAC-SHA256 of "<t>.<raw body>" keyed with the subscription's secret. Reject a t more than 300 seconds away from your clock.

Mailcheer-Timestampstring required

The same t, in seconds.

Mailcheer-Event-Idstring required

The event's id — the same on every attempt and every replay: the deduplication key.

Mailcheer-Event-Typestring required

The event's type.

Mailcheer-Delivery-Idstring required

This delivery. A manual replay gets a new one.

Mailcheer-Attemptstring required

The attempt number, starting at 1.

Payload

OR

Example payload

{
  "id": "evt_Ab3cD9eF0gH1iJ2k",
  "type": "email.bounced",
  "created_at": "2026-09-25T08:31:09.020Z",
  "data": {
    "message_id": "cmu651xf200021n7nm68sikfw",
    "email": "nobody@example.com",
    "source": "api",
    "subject": "Your September invoice",
    "reason": "Permanent"
  }
}

Response

Any 2xx within 15 seconds acknowledges receipt. Anything else — another status, a redirect (not followed), no answer, a network error — is retried: 5 attempts in all, the next ones 30 s, 2 min, 10 min and 1 h after the previous failure.

Changes

Webhooks have no change history: a webhook is keyed by its event name rather than a path and method, so no recorded change can name it.