API
esc

Type to search.

Idempotency

Send an Idempotency-Key with every POST, PATCH or DELETE and a retried request replays the original response instead of running twice.

Networks fail between “the request was sent” and “the response arrived”. Without protection, a retry after such a failure creates a second product, queues a second billable task or submits a second import. The Idempotency-Key header removes that risk.

Terminal window
curl https://api.veeton.com/v1/tasks/beautifier \
-H "Authorization: Bearer $VEETON_KEY" \
-H "Idempotency-Key: 4d1b9f6e-6c2a-4c1e-9c3f-2a7e8b0d1f22" \
-H "Content-Type: application/json" \
-d @task.json

Any opaque string up to 255 characters works; a UUID per logical operation is the usual choice. Keys are scoped to your organization and expire after 24 hours.

What a key does

Situation Result
Same key, same request The stored response is replayed verbatim, with Idempotent-Replayed: true.
Same key, different method, path or body 422 idempotency_key_reused. Use a fresh key per operation.
Same key while the first request is still running 409 request_in_progress. Retry after it completes.
No key The request runs normally. The header is opt-in.

GET requests are inherently idempotent and are never tracked.

Retrying after an error

A 4xx is a real outcome and is replayed like any other: a rejected request is deterministic and replaying it costs you nothing.

A 5xx is not stored. The key is released, so retrying with the same key genuinely re-runs the request instead of replaying the failure. The flip side: if the operation had already taken effect before the error, a retry can produce a second one. That is the same trade-off Stripe makes, and the better half of it; the alternative is an operation you can never complete.

If a request stops responding entirely (a crash on our side before anything was recorded), the key frees itself a few minutes later. A later retry is never permanently blocked.