Idempotency

Retry requests safely without repeating an operation.
View as Markdown

Network failures happen. A request can succeed on the server while the response is lost in transit, leaving your client unsure whether the operation ran. Retrying blindly is dangerous: a retried POST /sessions:dial would place a second real outbound call. An idempotency key makes a retry safe while its record exists: a finalized operation is not re-executed and the retry returns the original result.

Optional, but recommended for every mutation. It is supported by every POST, PUT, PATCH, and DELETE endpoint.

Sending a Key

Attach an Idempotency-Key request header with a value you generate — a UUID is ideal. Use one key per logical operation, and reuse the same key when retrying that operation.

1POST /v1/sessions:dial
2Authorization: Bearer <app_uuid>:<api_key>
3Idempotency-Key: 9f1c8e7a-2b3d-4f56-8a90-1c2d3e4f5a6b
4Content-Type: application/json
5
6{ "to": "+972527121102", "from": "+972747713001", "ring_timeout_sec": 30, "max_duration_sec": 3600 }

An in-progress record initially expires 1 hour after the request acquires the key. When the request finishes, the gateway stores the final response with a fresh 1-hour TTL, so the replay window runs from finalization. Replays do not refresh that TTL. After the record expires, reusing the same key starts a brand-new operation — for POST /sessions:dial that means a second real outbound call.

Allowed characters: letters, digits, dot, hyphen, and underscore. The value must be 1 to 128 characters. Omitting the header, or sending it with an empty value, disables idempotency for that request; any non-empty value that breaks the character or length rules is rejected with 400.

Response Behavior

ScenarioYou getMeaning
New keythe endpoint’s normal responseHandled once; its status and body are stored for replay.
Same key + same body, original finishedthe same HTTP status code and JSON body as the first callReplayed — not re-executed. Only the status and body are replayed; the original response headers are not reproduced, and the replay always sets Content-Type: application/json.
Same key + same request, accepted response availablethe original accepted responseReplayed — including the same Operation/resource identity when the endpoint returns one.
Same key + a different method, route, query, content type, or body422 Unprocessable EntityA key maps to one request. Use a new key.
Store unavailable before execution503 Service UnavailableThe request was not processed. Safe to retry.
Malformed key400 Bad RequestCheck the character/length rules above.

Reusing a Key

A key identifies one specific request within your authenticated app and must be unique across all supported endpoints. Always generate a fresh key for a new operation, even when calling a different endpoint.

The gateway binds the key to the HTTP method, canonical route, normalized query, Content-Type, and raw request body. If you retry with different whitespace, property ordering, or other byte-level body changes, it rejects the request with 422. Reuse the original request exactly as sent.

When Idempotency Is Unavailable

If the gateway cannot acquire or read the idempotency record before execution, it returns 503 without executing the operation. Retry the same request with the same key.

Best Practices

  • One key per operation. Generate a fresh key for each distinct action.
  • Persist the key before sending. Store it client-side first, so a crash-then-retry reuses the same key.
  • Reuse the same key for retries of the same operation. If the request outcome is unclear, retry the original request with its original key while the replay window is still open.
  • Treat a replay like the original. A replayed response is the real outcome of your one operation.