Skip to content

Idempotency

The public API supports an Idempotency-Key header on write endpoints (POST, PUT, PATCH). Use it for any write that’s safe to retry but unsafe to duplicate (checking out a checkin, starting a break, etc.).

  1. You generate a key per logical request — a UUID is ideal — and send it in the Idempotency-Key request header.
  2. The gateway records a tuple of caller identity plus idempotency key → the full response (status, headers we control, body).
  3. If the same key arrives again for the same endpoint from an equivalent caller, we return the recorded response and do not re-run the operation.
  4. Records expire 24 hours after the original request.

Example: a checkout retry that is safe to repeat. The siteId and checkinId come from the URL.

curl -X PATCH https://aware-api.invalid/api/v1/sites/54321/checkins/8f5b9a4d-3c2e-4b1f-9d8a-72e6c1f0a4b3/checkout \
-H "Authorization: Bearer $AWARE_ACCESS_TOKEN" \
-H "Idempotency-Key: 8f5b9a4d-3c2e-4b1f-9d8a-72e6c1f0a4b3" \
-H "Content-Type: application/json" \
-d '{"source": "USER", "timestamp": "2026-05-12T22:15:33Z"}'
  • Scope. Keys are scoped per authenticated caller so two unrelated tokens cannot collide on meaning.
  • Length. 1–255 characters. ASCII only.
  • Endpoint match. A key is bound to the endpoint it was first used on. Reusing it on a different endpoint returns 409 Conflict.
  • In-flight retries. If the original request is still in flight when a retry arrives, the retry gets 409 with type IdempotencyConflict. Once the first request completes, a retry with the same key replays the stored response.
  • GET requests don’t need it — they’re already safe to retry.

Generate the idempotency key at the edge of your system (the request handler that triggered the action), persist it alongside the work item you’re acting on, and reuse the same key across all retries of that work item:

const idempotencyKey = crypto.randomUUID()
await db.insertOutboundCheckout({ idempotencyKey, checkinId, payload })
await retry(() =>
fetch(`/api/v1/sites/${siteId}/checkins/${checkinId}/checkout`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${accessToken}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
}),
)

That way a crashed retrier still sees the same key on its next attempt.