Key Takeaways
- An idempotent send means the same logical message cannot bill the radio twice when your HTTP client retries.
- Send Idempotency-Key with POST /messages. Use a stable id from your domain (order, challenge, party), not a new UUID per retry.
- OTP: new user-facing code ⇒ new key. Same challenge retry ⇒ same key.
- Webhook handlers still dedupe on event id. Send idempotency does not replace that.
- You bring phones and airtime. Duplicate sends burn operator credit and plan volume.
Teams search android sms gateway idempotent send after a timeout: the client retried, the guest got two “table ready” texts, and OTP codes collided. HTTP is at-least-once unless you make the send logically once.
Live contract: Developer Center. Design around it: Android SMS Gateway API. You bring the phone and airtime. We meter devices and volume.
Why retries double-text
Load balancers, 504s, and mobile networks retry. The control plane may have accepted the first POST. Without a key, the second POST is a new job. The SIM sends twice. DLR looks “healthy.” The user is angry.
Timeouts are not failures until you have looked up the original message id. Retrying blind is how you buy two segments.
Idempotency-Key on send
The public sample send already shows the header:
curl -X POST "https://app.sms-gateway.app/api/v1/messages" \
-H "Authorization: Bearer $SMS_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1b0c8a-9d2e-4c77-9f5a-2b6d1e0f4a83" \
-d '{"to":["+14155552671"],"text":"Your verification code is 481920","type":"sms"}'Confirm exact semantics (TTL of the key, what happens on body mismatch) in docs — do not invent them here. HTTP retries are a client problem; see RFC 9110 for method safety, then still send a business-stable key.
Key design
| Event | Key | When to mint a new one |
|---|---|---|
| Order shipped notify | ship:{orderId} | Never for the same shipment event |
| OTP challenge | otp:{challengeId} | New challenge / new digits |
| Table ready | ready:{partyId} | Host explicitly taps ready again after a no-show cycle |
| Bulk row | camp:{id}:row:{n} | Never on worker retry |
OTP is a special case
Resend that issues new digits is a new challenge — new key. Network retry of the same challenge keeps the key so you do not send two live codes. OTP templates.
Webhooks still fire once-or-more
Deduplicate X-SmsGateway-Event-Id. Send idempotency does not make webhooks exactly-once. Webhook guide.
Bulk rows
Workers restart. Without per-row keys you re-send the prefix of the file. Bulk SMS.
Airtime you do not get back
Duplicates consume operator credit and platform send volume. Free: 300 SMS lifetime. Developer: 25,000/year. Starter/Pro/Business uncap platform volume, devices 2/5/15. Pause on Free/Developer at allowance. No unlimited carrier SMS.
Checklist
- Idempotency-Key on every production send.
- Keys from domain ids, stored next to the message id you got back.
- Timeout path: lookup by key/id before a second POST.
- Webhook event-id unique constraint.
Next steps
Break your client with a forced retry in staging and count SMS on the destination thread. One bubble is the test. PHP samples · C# samples.
Related product pages
Jump to the live product docs for this topic—not another long-form article.
- device and SMS volume pricingPlans and allowances
- Android SMS gateway product guideDefinition, product, and how to buy
- SMS API documentationLive endpoint reference
- download the Android gateway appGet the APK





