Idempotency

Source: src/lib/api/idempotency.ts.

Idempotency-Key: <any unique string — usually uuid>

Accepted on single-send POST endpoints:

  • POST /api/v1/emails
  • POST /api/v1/sms

Not applied to batch endpoints.

Behavior

  1. On receipt, checkIdempotency(key, orgId) looks up idempotency_keys where key matches, org matches, and expires_at > now.
  2. If hit → the cached response body and status code replay with an added header:
    Idempotent-Replayed: true
    
  3. On success, storeIdempotency(key, orgId, status, body) upserts with ON CONFLICT DO NOTHING and a 24-hour expires_at.

Scoping

  • Keys are scoped by orgId — two orgs can use the same key without collision.
  • Within an org, the same key replays the original response even if the request body differs. The app does not hash bodies or validate that subsequent requests match.

TTL

24 hours (IDEMPOTENCY_TTL_HOURS = 24). After expiry the key is reusable.

Schema

Column Type Notes
key text primary key
org_id text indexed
status_code text stringified HTTP status
response_body jsonb replayed verbatim
created_at timestamp
expires_at timestamp