Make retries safe with idempotency keys
An Idempotency-Key header makes retries safe: the same key with the identical payload charges once and serves the same result. Replays, conflicts, and how to choose keys.
Idempotency makes a retry behave like the first attempt. Send an Idempotency-Key header, and the identical request charges once however many times you send it. A key is any string of 1 to 200 printable ASCII characters. Keys are namespaced to your API key and never collide with another account's.
curl -X POST https://api.paxalabs.com/v1/tts \
-H "Authorization: Bearer $PAXA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-8146-confirmation" \
-d '{"text": "สวัสดีครับ ยินดีต้อนรับสู่ Paxa Labs", "voice": "khanomkrok", "model": "paxa-tts-flash-v2"}' \
--output speech.mp3// Reuse the same key when retrying the identical request: the charge
// happens once and the same audio is served again.
const idempotencyKey = `order-${order.id}-confirmation`;
const response = await fetch("https://api.paxalabs.com/v1/tts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAXA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({ text: "สวัสดีครับ ยินดีต้อนรับสู่ Paxa Labs", voice: "khanomkrok", model: "paxa-tts-flash-v2" }),
});Supported endpoints#
Seven billed HTTP endpoints accept the header: POST /v1/tts, the OpenAI-compatible speech endpoint, POST /v1/translate, POST /v1/ocr, POST /v1/extract, POST /v1/stt, and the OpenAI-compatible transcription endpoint. The live WebSocket does not accept it. Its billing is cumulative per connection, and reconnecting opens a new billing scope. The main use is streaming. A dropped stream retried under the same key replays without a second charge.
Replays#
The first request under a key records the charge. A retry with the same key and the identical payload is verified against that record and served without charging again. Its x-credits-charged header, or the body's usage.credits for transcription, OCR, extraction, and translation, reports the original charge. One request per key runs at a time, and concurrent duplicates answer 409 idempotency_in_flight.
Conflicts#
| Response | When | What to do |
|---|---|---|
| 409 idempotency_in_flight | Another request with this key is running right now. | Wait for it to finish, then retry to replay its outcome. |
| 409 idempotency_refunded | The original request failed and was refunded. | Send a new Idempotency-Key. |
| 422 idempotency_mismatch | The key was already used for a different payload. | Reuse a key only to retry the identical request. |
Choose a key#
Derive keys from identifiers you already have, for example order-8146-confirmation. One key means one piece of audio: a new attempt at different content needs a new key.
Note
Without the header, every request charges exactly once under its own internal id, tied to the x-request-id response header for support.