# Errors & retries

> What each HTTP error means, how failed deliveries are retried, and which failures raise an alert.

## HTTP errors

| Status | Meaning |
|--------|---------|
| `400`  | Validation details, unknown tenant, bad channel/kind pairing, bad `updated_since`. |
| `401`  | Missing or invalid token. |
| `403`  | Authenticated, but not with a client-credentials token (v2). |
| `413`  | Request body over 5 MB (v2 sends). |
| `429`  | Tenant or client daily quota reached. |

## The retry ladder

A delivery that fails for a transient reason is retried automatically: 5
attempts in total, roughly 60s, 120s, 240s, then 480s apart, before it is
marked `failed`. Rate-limit waits never use up attempts: waiting for your
own per-minute window is not a failure.

A **permanent** rejection fails at once with its reason on the delivery
(`last_error`), without using the ladder:

### SMS (Beem)
Bad credentials (100), unregistered source (101), bad body (103), no
balance (104), unapproved sender (105), and bad destination (102: one
wrong number, never an outage).
### WhatsApp
An expired token (190) and paused or disabled templates (132015, 132016).
Other bad requests are likewise permanent.
### Email
A refused recipient, failed SMTP authentication, or an empty body.
### Push
No registered devices for the user, a project-level refusal, or every
token rejected.

## Service alerts

!!! note "Outages email your team"
    Repeated channel-wide failures, such as a suspended WhatsApp token, an
    empty Beem balance or a wrong SMTP password, raise a service alert and
    email your client admin and tenant contacts. When the failures stop, a
    recovery notice closes the loop. Per-recipient failures (one bad
    address, one dead token) never page anyone.
