Documentation
Sign inGet started

Idempotency

Networks fail at the worst moments: you POST a send, the connection drops, and now you don't know whether the email went out. Idempotency lets you retry that request safely — send the same Idempotency-Key header again and Bird replays the original response instead of processing the request a second time.

How it works

Idempotency is opt-in. Add an Idempotency-Key header to any POST, PATCH, or DELETE request; requests without the header are processed normally with no deduplication. GET requests are naturally idempotent and ignore the header.
Exemple de code
curl -X POST https://us1.platform.bird.com/v1/email/messages \
  -H "Authorization: Bearer bk_us1_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "from": "hello@example.com",
    "to": ["user@example.com"],
    "subject": "Welcome!",
    "html": "<p>Thanks for signing up.</p>"
  }'
A key is any non-empty string up to 255 characters. A UUID v4 is the recommended format; a deterministic key derived from your own entities (e.g. welcome-user/usr_abc123) also works well when you want retries across process restarts to share a key. The Bird SDKs generate a UUID key automatically for every mutating request, so SDK users get safe retries without doing anything.
Keys are scoped to your workspace — two workspaces can use the same key string without colliding — and retained for roughly 3 hours. A retry after the retention window is processed as a fresh request, so the window comfortably covers typical retry schedules (seconds to an hour) but is not a permanent dedupe log.

Replays

When Bird sees a key it has already completed, it returns the cached response — same status code, same body — without re-running the request. Both 2xx and 4xx responses are cached and replayed: if your first attempt failed validation, retrying the identical request returns the identical error rather than burning another attempt.
Replayed responses carry one extra header so you can tell them apart from fresh processing:
Exemple de code
HTTP/1.1 202 Accepted
Idempotency-Replay: true

Failure modes

ScenarioResponse
Same key, same requestCached response replayed with Idempotency-Replay: true
Same key, different request body or endpoint409E01005 IdempotencyKeyReuse
Same key, original request still in flight409E01004 RequestInProgress
Empty key, or key longer than 255 characters400E01002 InvalidRequest
Reusing a key with a different request is treated as a client bug — Bird returns 409 immediately rather than silently handing you a response that doesn't match what you sent. Generate a new key for the new request. The comparison covers the method, endpoint, path and query parameters, and the raw request body, so even a whitespace change in the body counts as a different request.
RequestInProgress means a concurrent request with the same key hasn't finished yet — typically an aggressive client-side timeout retrying while the first attempt is still processing. The in-flight lock expires automatically within about 30 seconds, so wait briefly and retry. See Errors for the error envelope these come wrapped in.

What's not cached

5xx responses are never cached. A server error means Bird doesn't know whether the request took effect, and caching it would permanently block the retry from ever succeeding. Instead the key unlocks, and your retry is processed fresh. This is exactly the case idempotency exists for: retry 5xx responses and timeouts with the same key, and you'll either get the original successful response (if the first attempt actually completed) or a clean new attempt.
Email sends get an extra durable guarantee. For POST /v1/email/messages and the batch endpoint, acceptance is additionally deduplicated in durable storage, independent of the response cache. Even if the cache misses — a lock expired, a response was too large to cache — a retry with the same key replays the same accepted email IDs rather than accepting the send twice. Your retries never produce duplicate emails. See Sending email.

Practical guidance

  • Generate one key per logical operation, not per HTTP attempt — the whole point is that retries of the same operation share the key.
  • Retry on network errors, timeouts, and 5xx with exponential backoff, reusing the same key each time.
  • Treat 409 IdempotencyKeyReuse as a bug in your key generation, not something to retry.
  • Don't bother with keys on GET requests or on operations that are naturally idempotent in your domain — the mechanism is there for the cases where a duplicate would hurt.