Idempotency
Retry message sends and number purchases safely with the Idempotency-Key header — no double texts, no double purchases.
A network failure after you POST a text or a number purchase leaves you not knowing whether it happened. Retrying blindly risks texting a customer twice or buying two numbers. An Idempotency-Key makes the retry safe.
#Supported endpoints
| Endpoint | Why |
|---|---|
POST /messages | Never double-text a customer |
POST /numbers | Never double-buy (and double-bill) a number |
#How it works
Send any string up to 200 characters, unique per logical operation:
Shell
curl https://api.ody.co/v1/api/messages \
-H "Authorization: Bearer $ODY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-shipped" \
-d '{"to":"+15125550123","body":"Your order shipped!"}'- The first response for that key is stored for 24 hours, scoped to your workspace.
- Any retry with the same key inside that window gets the stored response replayed verbatim, plus an
Idempotency-Replayed: trueheader. Nothing is sent or bought again. - After 24 hours, the key is forgotten and a request with it is treated as new.
#Choosing keys
Derive the key from your business event
Use something like order-1042-shipped or onboarding-<customerId>-main-line, not a random UUID per attempt. The whole point is that every retry of the same operation shares the key.
- Different operations need different keys. Reusing one key for two different texts replays the first response for the second.
- Store the key with the job that performs the send, so a crashed worker that restarts reuses it.
#In the SDKs
await ody.messages.send({ to: "+15125550123", body: "Your order shipped!", idempotencyKey: "order-1042-shipped" });
await ody.numbers.buy({ phoneNumber: "+15125550123", idempotencyKey: "onboard-acme-main" });client.messages.send(to="+15125550123", body="Your order shipped!", idempotency_key="order-1042-shipped")
client.numbers.buy(phone_number="+15125550123", idempotency_key="onboard-acme-main")Last updated Wed Oct 14 2026 00:00:00 GMT+0000 (Coordinated Universal Time)Something wrong on this page? Tell us