Webhooks

Receive real-time notifications when email events occur.

Event types

  • message.received — A new inbound email arrived
  • message.sent — An outbound email was accepted for delivery
  • message.delivered — An outbound email was delivered to the recipient
  • message.bounced — An outbound email bounced, permanently or temporarily
  • message.complaint — A recipient marked the email as spam

Every message.bounced event has a bounce_type:

  • permanent: the address can't receive mail. It is added to your suppression list, and sends to it are refused.
  • transient: a temporary failure, such as a full mailbox. The address is not suppressed and may work later.
  • undetermined: the bounce wasn't classified. Robotomail treats it as permanent and suppresses the address.

bounce_subtype gives the provider's more specific reason, such as MailboxFull, or null. See Event payloads.

Delivery & retries

Webhook payloads are POST requests to your endpoint URL (must be HTTPS). Each delivery includes a JSON body with the event type, timestamp, and relevant data.

A delivery succeeds when your endpoint returns a 2xx status within 10 seconds. Anything else is a failed attempt and is retried: other status codes, including 3xx (redirects are not followed) and 4xx, timeouts, network errors, and hostnames that don't resolve or resolve to a private address. Returning a 4xx does not stop retries.

Each delivery gets up to 6 attempts: the first, then 5 retries, waiting 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours after each failed attempt. The last attempt comes about 14 hours 36 minutes after the first. If it also fails, the delivery is marked FAILED.

Each delivery that fails all 6attempts adds 1 to the webhook's failureCount, and any successful delivery resets it to 0. Failures preparing or signing the payload are retried on the same schedule but never count: if the last attempt fails that way, failureCount is unchanged. When failureCount reaches 10, an ACTIVE webhook's status becomes FAILED. A FAILED or PAUSED webhook receives no new events. A retry that comes due while the webhook is FAILED or PAUSED is dropped: the delivery is marked FAILED and is not sent later, even after the webhook is re-enabled. If you re-enable the webhook before a retry comes due, that retry still runs.

To re-enable a FAILED or PAUSED webhook, send PATCH /v1/webhooks/:id with {"status": "ACTIVE"}, after fixing the endpoint if it was failing. This resets failureCount to 0.

Signature verification

Every webhook delivery includes an X-Robotomail-Signature header containing an HMAC-SHA256 signature of the request body. Verify it against the webhook secret returned when you created the webhook.

See the Webhooks API reference or the Receive & reply guide for verification examples. The secret is only returned once at creation time.

Custom headers

You can attach custom HTTP headers to a webhook that are included in every delivery request. This is useful for passing authentication tokens, routing keys, or other metadata your endpoint requires.

Pass a headers object when creating or updating a webhook. Up to 10 headers are allowed (key max 256 chars, value max 1024 chars). Header names must be valid HTTP tokens — spaces, colons, and other non-token characters are rejected. Values must not contain control characters (prevents CRLF injection). Headers with the X-Robotomail- prefix are reserved and will be rejected. Dangerous headers (Host, Content-Length, Content-Type, Transfer-Encoding, Connection, Keep-Alive, Upgrade, TE, Trailer) are also blocked. To clear all custom headers, pass null in a PATCH request.

Webhook scoping

Webhooks can be account-level (triggered for events on any mailbox) or mailbox-scoped (triggered only for events on a specific mailbox). Scoped API keys can only create mailbox-scoped webhooks for mailboxes in their scope.