Rate limits & errors

Per-key rate limit headers and the standard error envelope.

Requests are rate limited per API key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix epoch second); a 429 adds Retry-After.

Errors use a stable envelope:

{ "error": { "code": "validation_error", "message": "…", "details": {} } }

Common codes: validation_error (400), authentication_required (401), forbidden (403), resource_not_found (404), workspace_not_found (404), duplicate_resource (409), rate_limited (429), internal_error (500). Correlate support requests with the X-Request-Id response header.

Per-item errors on batch sends

A batch item can fail on its own without failing the request (see Retries and idempotency). Two different things can go wrong with one item, and they carry different statuses.

status: "rejected" means the item was never sent, because its idempotency_key could not be honoured. id is null, the response stays 202, and the item counts under rejected.

error.codeMeaningWhat to do
idempotency_conflictThe key was already used with different content, from, reply_destination_id or status_callback.Use a new key for the changed message.
idempotency_in_progressAnother request holding this key has not finished yet.Retry the item shortly.

status: "failed" means Beep attempted this recipient and it did not go. The item carries an error object and counts under neither accepted nor rejected — items is the complete record.

error.codeMeaningWhat to do
sender_busyThe carrier refused the attempt. Nothing was sent.Safe to send again, under a new idempotency_key.
sender_pausedSending is paused by an operator. Nothing was sent.Safe to send again, under a new key, once it resumes.
sender_unreachableBeep could not reach its sender. Nothing was sent.Safe to send again, under a new key.
sender_rejectedThe carrier refused this particular message.Do not repeat it unchanged — the same body gets the same answer.
sender_timeoutBeep stopped waiting. It may or may not have been sent.Do not re-send blindly. Reconcile by id first.
sender_not_attemptedThe batch stopped before reaching this item; nothing was sent for it.Safe to send again.
sender_outcome_unknownThe message was recorded but its hand-off is unproven.Do not re-send blindly. Reconcile by id first.

Retrying a failed item

Whether a retry is safe is a question about the item, not about the status code, and the two are not the same question.

A 503 on the whole request means the request was stopped — but if it was a batch, some recipients in it may already have gone; items names them. Read it before retrying.

A per-item retry under the same idempotency_key does not re-send. The key is bound to one message, and Beep answers a repeat by reporting what that message came to: failed with its recorded reason, suppressed, or sender_outcome_unknown if the outcome cannot be established. That is deliberate — it is what stops a retry from duplicating a message that did go out. A real re-send needs a new key, and you should only mint one for a code the table above calls safe.


Did this page help you?