PokeePokee Enterprise API

Idempotency keys

Make POST retries safe — same key returns the original response_id instead of starting a duplicate turn.

Network blips happen. If your POST to /v1/sessions/{id}/messages or /v1/responses (streaming) lands on the server but you never see the response headers, retrying without coordination would either start a duplicate turn (rare — session.busy 409s the dup on the session path) or leave you locked out with no way to discover the original response_id. The Idempotency-Key header closes that gap, the same way Stripe and OpenAI do.

How to use it

  1. Generate a stable key per logical operation — a UUID is conventional.
  2. Send the POST with Idempotency-Key: <your-key>.
  3. If anything goes wrong client-side (connection drop, timeout, app crash before reading the response), retry the same POST — same body, same key.
  4. The server recognizes the key and replays the original response_id. Same SSE stream from id: 0. No new turn started, no extra tokens billed.
curl -X POST "$POKEE_API/v1/sessions/$SID/messages" \
  -H "Authorization: Bearer $POKEE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"message": "summarize Q3 earnings"}'

Semantics

ScenarioResult
Same key + same bodyReturns the original response_id. If the original turn is still in flight or within the 120s resume grace, the SSE stream replays from the buffer.
Same key + same body, but original buffer evicted200 application/json with {"response_id", "status": "replayed", "note": "...evicted..."}. You have the id, but no events to replay.
Same key + different body422 Unprocessable Entity. The fingerprint over the body changed — use a fresh key for a new logical operation.
Same key on a different session422 (the fingerprint is over (session_id, body)).
Concurrent retries with same keySerialize on a per-key lock; the second gets the replay path automatically — only one turn ever starts.

Where it applies

EndpointSupported?
POST /v1/sessions/{id}/messagesYes
POST /v1/responses with stream=trueYes
POST /v1/responses with stream=falseNo — returns 400. Non-streaming requests are short-lived; retry directly.

Validation

  • 1 to 200 characters
  • ASCII-printable only (0x210x7e); no spaces, newlines, or control chars
  • Bad value → 400 Bad Request

Lifetime

  • Keys live for 24 hours (IDEMPOTENCY_TTL_SECONDS).
  • After that, the same key acts as if it had never been seen — a retry would start a fresh turn. Don't rely on long-tail replays for audit; if you need persistent operation tracking, log the response_id on your side.

Pairs well with

  • Resume — if your POST landed and you have the response_id from the response headers, resume directly. If you don't (header lost), retry the POST with the same idempotency key to get the response_id back.
  • Cancel — the cancel endpoint is keyed by response_id, so once you've replayed via idempotency you have everything you need to abort.

On this page