# Idempotency

> Retry requests safely with the Idempotency-Key header.

Source: https://www.ordstage.com/docs/idempotency/

Networks fail: a request can reach Ordstage while its answer never reaches you. To retry without doing the same
thing twice, send an `Idempotency-Key` header with every request that creates something.

> **Note** The examples use contacts, which arrive in an upcoming release. Today's bookings endpoints are
> idempotent by design; see [Bookings](#bookings).

```bash [curl]
curl -X POST https://api.ordstage.com/v1/contacts \
  -H "Authorization: Bearer $ORDSTAGE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Mona"}'
```

```js [JavaScript]
import { randomUUID } from "node:crypto";

const key = randomUUID(); // keep it with the operation, and reuse it for every retry of that operation
await fetch("https://api.ordstage.com/v1/contacts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ORDSTAGE_API_KEY}`,
    "Idempotency-Key": key,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Mona" }),
});
```

```python [Python]
import os
import uuid
import requests

key = str(uuid.uuid4())  # keep it with the operation, and reuse it for every retry of that operation
requests.post(
    "https://api.ordstage.com/v1/contacts",
    headers={"Authorization": f"Bearer {os.environ['ORDSTAGE_API_KEY']}", "Idempotency-Key": key},
    json={"name": "Mona"},
    timeout=30,
)
```

## How it works

- The key is any unique string up to 255 characters; a UUID is a good choice. Keys are separate per API key.
- The first request with a key runs normally. A **successful** answer is stored for 24 hours.
- Repeating the same request (same key, same endpoint, same body) within 24 hours returns the stored answer
  without running it again. The answer has the header `Idempotent-Replayed: true`.
- Reusing a key with a different body or endpoint answers `409 idempotency_conflict`.
- Sending a key again while the first request is still running answers `409 idempotency_in_progress`; retry a
  moment later.
- A request that fails (any non-`2xx` answer) is not stored, so you can fix it and retry with the same key.
- Endpoints that require the header answer `400 idempotency_key_required` without it. The
  [API reference](https://www.ordstage.com/docs/reference/) marks them.

## Bookings

The bookings endpoints don't need an `Idempotency-Key`: you send each booking and closure under **your own id**
in the path (`PUT /v1/calendars/{calendar_id}/bookings/{external_id}`), and sending it again updates the same
booking instead of creating another one. Retrying them is always safe.
