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):
- Re-sending the same key — within a single batch or across retries — is a
no-op, counted under duplicates. It never creates a second event or issue.
- Events without a key are stored as-is (at-least-once): a retry of an
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.