# Idempotency

> Retry message sends and number purchases safely with the Idempotency-Key header — no double texts, no double purchases.

Source: https://dev.ody.co/api/idempotency

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:

```bash
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: true` header. 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

TypeScript:

```ts
await ody.messages.send({ to: "+15125550123", body: "Your order shipped!", idempotencyKey: "order-1042-shipped" });
await ody.numbers.buy({ phoneNumber: "+15125550123", idempotencyKey: "onboard-acme-main" });
```
Python:

```python
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")
```
