Skip to Content
Idempotency

Idempotency

Keel documents idempotency separately for the canonical permit flow and the execution routes.

At a glance

Route familyWhere idempotency goes
POST /v1/permitsJSON body idempotency_key
POST /v1/permits/{permit_id}/usageJSON body usage_idempotency_key
POST /v1/executionsIdempotency-Key header
POST /v1/executeIdempotency-Key header
POST /v1/proxy/*Idempotency-Key header

Permit idempotency

Route:

  • POST /v1/permits

Canonical field:

  • idempotency_key in the JSON body

Behavior:

  • scope is per project
  • same key plus the same semantic payload replays the prior permit response
  • same key plus a different semantic payload returns 409 conflict
  • if the client omits idempotency_key, Keel generates a server-side idempotency key for that permit
  • replay is still route-dependent: stale allow permits with inactive reservations can expire or revalidate instead of replaying the original allow body

Permit usage closeout idempotency

Route:

  • POST /v1/permits/{permit_id}/usage

Canonical field:

  • usage_idempotency_key in the JSON body

Behavior:

  • use the same key when retrying the same permit closeout
  • same key plus the same closeout values replays the existing closeout response
  • same key plus different closeout values returns 409 conflict
  • this is a narrower permit-first closeout contract, not proxy-strength execution replay binding

Execution idempotency

Routes:

  • POST /v1/executions
  • POST /v1/execute
  • POST /v1/proxy/openai
  • POST /v1/proxy/anthropic
  • POST /v1/proxy/google
  • POST /v1/proxy/xai
  • POST /v1/proxy/meta

Canonical field:

  • Idempotency-Key HTTP header

Behavior:

  • reuse the same header value when retrying the same execution request
  • if the header is omitted, the request still runs, but retries are treated as new executions
  • proxy routes document the strongest replay contract: same key plus the same payload replays the cached response, and same key plus a different payload returns 409 conflict
  • execution routes use the same header-based retry pattern, but you should still treat the header as part of the public route contract rather than assume identical semantics across every route family
  • /v1/executions and /v1/execute do not currently document the same proxy-strength request-hash replay binding as the proxy routes

Why the fields differ

Permit creation uses a body field. Execution routes use a header. Use the documented field for each route family.

Last updated on Edit this page on GitHub