Idempotency & safe retries

Idempotency applies to ingest (POST /api/v1/ingest). The read API is GET-only and naturally safe to retry.

Idempotency keys

Attach a stable idempotencyKey (or eventId) to each event you send. Guardian Logs deduplicates on (source, idempotencyKey):

no-op, counted under duplicates. It never creates a second event or issue.

unkeyed event may create a duplicate.

If both idempotencyKey and eventId are present, idempotencyKey wins; eventId is used only when idempotencyKey is absent. Keys are 1–200 chars.

Because dedupe is scoped to the source, the same key value used by two different sources refers to two different events — which is what you want, since each credential maps to one source.

Example

curl -X POST "https://guardianlogs.com/api/v1/ingest" \
  -H "Authorization: Bearer $GUARDIAN_INGEST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "events": [
    { "message": "boom", "idempotencyKey": "order-42-failed" },
    { "message": "boom", "idempotencyKey": "order-42-failed" }
  ] }'

The second event is a duplicate of the first:

{
  "ok": true,
  "batchId": "clw9k2xm0000abcd1234efgh",
  "received": 2,
  "accepted": 1,
  "duplicates": 1,
  "rejected": 0,
  "results": [
    { "index": 0, "status": "accepted" },
    { "index": 1, "status": "duplicate" }
  ]
}

Retry policy for senders

On network error, timeout, 429, or 5xx, retry with exponential backoff and jitter (e.g. 1s, 2s, 4s, capped), reusing the same idempotency keys so re-sends collapse into no-ops. Do not retry 400, 401, 403, or 413 — fix the request or credential instead.

Choose keys that are stable for a logical event (e.g. a request id, or "<order>-<stage>") and identical across every retry of that event.

See also: ingest.md · rate-limits.md · errors.md.