Reliability

Idempotency-Key

Make every mutating Throttle request safe to retry by attaching an Idempotency-Key header. Throttle will replay the original response if you retry within 24 hours, even if the network blew up midway through the first attempt.

When to use it

Always, on every POST, PATCH, and DELETE from a server you can't fully trust the network between (i.e. all of them). It costs nothing when the request succeeds first try, and saves you from double- charging, double-creating, or double-cancelling on retry.

  • Generate a fresh key per logical operation. A UUID v4 is the canonical choice.
  • Reuse the same key when retrying the same operation (timeout, 5xx, connection reset).
  • Do not reuse a key for a different operation. Throttle will reject the second call with 409 idempotency_key_reused.

Usage

Sending an Idempotency-Key
// Generate a UUID v4 per logical operation; reuse it on retry.
import { randomUUID } from 'node:crypto';

const idempotencyKey = randomUUID();

await fetch('https://api.usethrottle.dev/api/v1/carts', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.THROTTLE_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': idempotencyKey,
  },
  body: JSON.stringify({
    applicationId: process.env.THROTTLE_APPLICATION_ID,
    currency: 'USD',
  }),
});

How replay works

Throttle hashes the canonicalised request body (SHA-256, key-sorted) alongside the key. On the second arrival within 24 hours:

  • Same key + same body → original response replayed byte-for-byte with an extra Idempotency-Replay: true response header. The handler does NOT run again.
  • Same key + different body → 409 idempotency_key_reused. Surfaces the integrator bug instead of double-charging.
Replay response
# Second request with the same key + same body returns the
# first response byte-for-byte. The header below tells you it's a replay.
HTTP/1.1 201 Created
content-type: application/json
idempotency-replay: true

{ "id": "9f6e...", ... }
409 idempotency_key_reused
// 409 idempotency_key_reused — same key, DIFFERENT body.
// Generate a new key for new operations; reuse only on retry.
{
  "error": {
    "code": "idempotency_key_reused",
    "message": "Idempotency-Key was already used with a different request body. Generate a new key for new operations."
  }
}

Scope

  • Per workspace, per (method, path). The same key can be reused across endpoints without colliding — Throttle scopes the cache by tuple (workspaceId, key, method, path).
  • TTL: 24 hours. After 24h, the same key can be used again without replay.
  • GET / HEAD requests ignore the header. They're already idempotent.
  • 5xx responses are not cached. A transient server error doesn't pin a failure response to your key.
Pick stable keys, not new ones per retry
The whole point is that the SAME key is reused. Generating a new UUID on every retry defeats the cache and risks double-charging. Persist the key in your job queue / outbox alongside the request payload.