SMS

How do I avoid sending the same SMS twice?

Reuse one Idempotency-Key for retries of the same SMS request so Bird can replay a retained response without sending again.

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?

You set an Idempotency-Key header for each intended SMS send and reuse it when retrying the identical request. When Bird retains the original response, a matching retry returns that response without executing the send again.

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. The in-flight lock expires within 30 seconds. Expiry does not establish whether the original send took effect.
  • 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. Bird does not retain 5xx responses. A retry replays a retained successful response or can execute again if no response was retained.

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

Does the key guarantee no duplicates?

The key reduces duplicate sends, but it does not guarantee one execution.

A send can take effect before Bird retains its response. If response retention fails or the in-flight lock expires, a retry can execute the send again. The three-hour retention window also limits replay protection.

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 to retain any available replay protection.
  3. Fix changed-request conflicts and delay retries when the original request remains in progress.
  4. Reconcile uncertain sends, including those beyond the three-hour replay window, before deciding whether another send is appropriate.

In short

  1. One key identifies one intended send.

    Retries reuse the same key and request. A retained response replays within three hours.

  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. Response replay reduces duplicate risk without eliminating it.

    A send can take effect before its response is retained. An expired replay record also permits a fresh execution.

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.