How do I avoid sending the same SMS twice?

Reuse one Idempotency-Key for identical SMS requests within three hours to guarantee exactly-once acceptance.

A connection can drop after Bird accepts an SMS but before your application receives the response. Retrying with a new key can create a second send because Bird treats it as a separate request.

How does the key work?

Set an Idempotency-Key header for each intended SMS send and reuse it when retrying the identical request. The exactly-once acceptance guarantee means matching retries within three hours must resolve to the same accepted send, even if you lost its response.

For example, an order confirmation keeps the same key across a timeout and its retry. A confirmation for a different order gets a different key.

Replayed responses include Idempotency-Replay: true, which lets your logs distinguish a replay from a newly processed request.

SMS keys are scoped to your workspace. Bird retains completed responses for three hours under its idempotency contract. After that window, the same key can execute a fresh request because its replay record has expired. A retry a day later therefore requires reconciliation of the original outcome before another send.

What are the failure responses telling me?

The error code distinguishes a changed request, an unfinished request and unavailable protection.

  • 409 with E01005 IdempotencyKeyReuse: the same key was used for a different request. Fix the key assignment before retrying, since this key belongs to the original request. Bird compares the method, endpoint, path and query parameters, and raw body. Even a JSON whitespace change makes the request different.
  • 409 with E01004 RequestInProgress: a concurrent request with the same key has not finished. Wait briefly and retry with the same key and request so the original can complete.
  • 503 with E01033 IdempotencyUnavailable: protection was unavailable before execution, so this attempt did not execute. Retry with backoff using the same key and request. This response does not establish the outcome of an earlier attempt.
  • Other 5xx responses or timeouts: retry with backoff using the same key and request. The exactly-once acceptance guarantee covers these retries within three hours. Stop when your retry budget is exhausted.

The idempotency header preserves the identity of the request across these retries.

Does the key guarantee no duplicates?

The guarantee is exactly-once acceptance for identical requests with the same key in the same workspace within three hours. Those retries must resolve to one accepted send, including after a lost response. Check the message status to confirm delivery.

After the three-hour retention window, the original key can identify a fresh operation. Reconcile an unknown original outcome before submitting again.

Keep your application event and send records so you can reconcile an uncertain outcome before sending again. Include the order or reference number in the message so the recipient can recognize which event it concerns.

What about a message the handset shows twice?

An idempotency key governs API retries; it does not control how a recipient's phone displays a message. A screenshot alone does not establish where a duplicate originated.

Compare the complete application send log with Bird’s message records. Multiple accepted message IDs can establish multiple sends. Finding only one ID in an incomplete log does not prove the duplicate happened downstream. Include the relevant IDs, destination and timestamps when asking support to investigate.

What should I do?

  1. Assign one key to each intended SMS send and reuse the identical request for its retries.
  2. Retry network errors, timeouts and 5xx responses with backoff, preserving the key and identical request within three hours.
  3. Fix changed-request conflicts and delay retries when the original request remains in progress.
  4. Keep exhausted or expired retries unresolved until you reconcile their outcome, before deciding whether another send is appropriate.

In short

  1. One key identifies one intended send.

    Reuse the same key and identical request within three hours. The guarantee covers one accepted send across those retries.

  2. A 409 can identify a changed or unfinished request.

    IdempotencyKeyReuse means the request changed. RequestInProgress means the original request is still running and needs a delayed retry.

  3. Unavailable protection blocks this attempt.

    A 503 IdempotencyUnavailable response means this attempt did not execute. It does not establish an earlier attempt's outcome.

  4. Acceptance protection has a retention window.

    Retry within three hours. After that window, check the original send before submitting again.

Build on the same network.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

Your next idea. Ready to connect.