Guides
Reliability: idempotency and automatic retries
How the API behaves during outages, duplicates, and replays, and how to write a robust integration.
Updated November 12, 2026View as Markdown
A messaging integration must survive network failures, restarts, and duplicates. Here is what the API does for you, and what is left for you to do.
Send idempotency#
A send is not trivial: replaying it by mistake would send the same message to a customer twice. The Idempotency-Key header prevents that.
curl -X POST "$INBOX_API/messages" \
-H "Authorization: Bearer $INBOX_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: appointment-2026-11-14-customer-42" \
-d '{ … }'| Situation | Result |
|---|---|
| First request with this key | The message is accepted and recorded. |
| Same key, same request | No new message: you get the original message back, with the Idempotent-Replayed: true header. |
| Same key, different request | 422 idempotency_conflict. |
| Two simultaneous requests with the same key | One succeeds, the other is rejected (409): retry. |
{
"error": {
"code": "idempotency_conflict",
"message": "This idempotency key has already been used for a different request",
"requestId": "req_af73c415-1365-41e6-801f-5fc18b1ee2ec"
}
}Choose a key that describes the business intent (appointment-reminder-<appointment id>), not a random identifier regenerated on each attempt: that is what makes replay safe.
Sending is asynchronous#
202 Accepted means accepted, not delivered. The message is queued, then sent:
- Temporary Meta or network outage, rate limit: the message is retried automatically, up to 6 attempts with an increasing wait.
- Permanent rejection (template not found, recipient unreachable…): no pointless retry; the message goes straight to
failed, with Meta's code and reason. - Throughput: sends are throttled per number (50 messages per second by default): during a spike, they wait their turn without being lost.
- Restart or queue loss: a message that stays
queuedfor more than 5 minutes is picked up automatically by a maintenance task.
Statuses: never backward#
Meta can deliver its notifications twice or out of order. Bref Point Inbox applies a simple rule: a status only moves forward (queued → sent → delivered → read), and failed does not overwrite a message that is already read. Even a read that arrives before its delivered is accepted, and the missing step is filled in.
Webhooks: at least once#
Each event is delivered at least once, never "exactly once". Your receiver must therefore be idempotent:
- Verify the signature.
- Store the event
id(a table with a uniqueness constraint is enough). - If it already exists, respond
200without doing anything. - Otherwise, process it, then respond
200.
See Webhooks for the retry schedule and replay.
What's left for you to do#
- Set a timeout on your calls (10 to 30 seconds) and retry with the same
Idempotency-Keyon timeout, network error, or5xx. - Don't retry a
4xxerror without fixing the request: it will fail the same way. - Respond to your webhooks in under 10 seconds; hand long-running work off to a queue on your side.
- Monitor
GET /webhook-deliveries?status=failedand yourfailedmessages.