Skip to content

Idempotency-Key

Every unsafe method (POST, PUT, PATCH, DELETE) on the organization-scoped /api/v1 operations — those that run in an active organization context, such as projects, defects, test cases, runs, and plans — accepts an OPTIONAL Idempotency-Key request header. Send the same key on a retry and Probara replays the original response instead of re-executing the mutation — safe for network retries, client timeouts, and “did that click actually go through” double-submits. GET/HEAD requests ignore the header entirely.

Authentication (/api/v1/auth/*), user profile (/api/v1/profile, /api/v1/profile/avatar), and the project avatar upload (/api/v1/projects/{projectId}/avatar) endpoints do not support this header — it is silently ignored there.

Keys are scoped per organization and per acting actor: the same key value used by a different org, or by a different member within the same org, is treated as an independent key and never replays across that boundary.

  • Non-empty
  • No longer than 255 visible ASCII characters (no whitespace, control characters, or non-ASCII code points)

An invalid key responds 400 and the handler never runs.

Terminal window
# First attempt — executes normally and records the response under the key.
curl -sS -X POST \
-H "Authorization: Bearer $PROBARA_API_TOKEN" \
-H "Idempotency-Key: 8f14e45f-ceea-4a3c-b9a8-1a6b3d2f0e91" \
-H "Content-Type: application/json" \
-d '{"name":"Checkout flow"}' \
"https://probara.net/api/v1/projects"
HTTP/1.1 201 Created
Content-Type: application/json
{ "ulid": "01J...PROJ", "name": "Checkout flow", ... }

Retrying the identical request with the same key and body within the retention window returns the same status and body — still 01J...PROJ, no second project created — with an extra response header:

HTTP/1.1 201 Created
Idempotency-Replayed: true
Content-Type: application/json
{ "ulid": "01J...PROJ", "name": "Checkout flow", ... }
SituationResponse
First request with an unseen keyExecutes normally; response recorded for replay (JSON, status < 500, not 204, not binary)
Identical retry within the retention windowSame status and body as the original, plus Idempotency-Replayed: true
Duplicate arrives while the first request is still in flight409 with the standard error envelope (code: "conflict") and a Retry-After header
Same key reused with a different method, path, or body422 with code: "validation_failed"; nothing executes
Invalid key (empty or over 255 visible ASCII characters)400; nothing executes
First request failsThe claim is released; a later retry with the same key executes normally
Response is 204, non-JSON, or binaryPassed through unrecorded — a retry with the same key executes the handler again

Key records are kept for 24 hours. After the window elapses, the same key behaves as a fresh, unseen key: an identical request executes the handler again, and Idempotency-Replayed is absent from that response.

StatusCodeMeaning
400validation_failedIdempotency-Key is empty or longer than 255 visible ASCII characters
409conflictA request with the same key is still in flight; includes a Retry-After header
422validation_failedThe key was already used with a different method, path, or request body