Skip to main content
Network failures happen mid-request — you sent a POST /v1/webhooks and the connection dropped before the response arrived. Did the webhook get created? Retrying blind risks creating it twice. The Idempotency-Key header solves this: retry safely, and HASP guarantees the mutation only happens once.

Using it

Send an Idempotency-Key header on any JSON POST, PATCH, or PUT request:
Generate the key client-side — a UUID or any sufficiently random string works. Reuse the same key when retrying the same logical operation; use a fresh key for a new one.

What happens on replay

The header is entirely optional. Requests without it behave exactly as they did before this primitive existed.

Scope and boundaries

Applies to: JSON request bodies on mutating POST/PATCH/PUT routes across /v1 and the Data API. The key is scoped per organization + route + key value, so two different orgs — or two different routes — can reuse the same key value without colliding. Does not apply to:
  • Multipart/form-encoded requests (e.g. POST /v1/files). Deduping would require buffering the entire upload into memory to hash it; HASP does not pay that cost, so these requests always execute, key or no key.
  • The AI inference endpoints/v1/messages, /v1/messages/count_tokens, /v1/chat/completions, /v1/ai/chat. An Idempotency-Key sent to these is silently ignored. Their response content may carry re-identified PHI, and persisting that into the idempotency store would put it outside the governed, retention-and-crypto-shredding-aware storage path the rest of HASP’s PHI handling relies on.
  • GET/DELETE requests. GET is already safe to retry; DELETE idempotency is handled by the resource’s own soft-delete semantics (a second DELETE on an already-deleted resource is a no-op, not an error).
Secrets returned once are never replayed as plaintext a second time. If the original request’s response included a one-time secret (an API key’s plaintext, a webhook’s secret, a credential’s token), a replay returns that field redacted (null) rather than handing the secret out again — consistent with those endpoints’ “shown once, never persisted” guarantee. The mutation itself still dedupes correctly; only the secret re-disclosure is suppressed.

Choosing a key

A UUID v4 is the simplest choice and what most HTTP clients generate by default. Whatever you use, derive it from something that uniquely identifies the logical operation in your system — e.g. an internal job ID or order ID — rather than generating a fresh key on every attempt, or retries stop being idempotent by definition.
See the Error Reference for the IDEMPOTENCY_CONFLICT error shape.