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.code | Meaning | What to do |
|---|---|---|
idempotency_conflict | The key was already used with different content, from, reply_destination_id or status_callback. | Use a new key for the changed message. |
idempotency_in_progress | Another 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.code | Meaning | What to do |
|---|---|---|
sender_busy | The carrier refused the attempt. Nothing was sent. | Safe to send again, under a new idempotency_key. |
sender_paused | Sending is paused by an operator. Nothing was sent. | Safe to send again, under a new key, once it resumes. |
sender_unreachable | Beep could not reach its sender. Nothing was sent. | Safe to send again, under a new key. |
sender_rejected | The carrier refused this particular message. | Do not repeat it unchanged — the same body gets the same answer. |
sender_timeout | Beep stopped waiting. It may or may not have been sent. | Do not re-send blindly. Reconcile by id first. |
sender_not_attempted | The batch stopped before reaching this item; nothing was sent for it. | Safe to send again. |
sender_outcome_unknown | The 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.
Updated 12 days ago