Hodoflow has two distinct duplicate-suppression contracts and ordinary retry guidance. Do not reuse one surface's behavior as a promise for another.
JSON:API unsafe writes
Send a unique Idempotency-Key on POST, PUT, PATCH, or DELETE requests
under /api/json. The key is scoped by tenant and service-account principal.
The request fingerprint includes method, path, and raw body.
Idempotency-Key: dashboard-create-20260731-001
- First request: reserves the key and runs normally.
- Same key and same request: replays the stored response with
idempotency-replayed: true. - Same key and different request: returns
409 idempotency_key_reused. - Concurrent duplicate while the first is running: returns
409 idempotency_key_in_progress. - A
5xxresponse is not retained, so a transient failure remains retryable.
Completed responses are retained for 24 hours by default; deployments can configure the window. Generate keys from a stable business operation ID, not a random value on every retry. Never put a credential or tenant secret in a key.
Webhook delivery deduplication
Webhook ingestion uses a stable sender delivery identifier from
Idempotency-Key or a supported provider header. It retains accepted delivery
identity for seven days. A duplicate receives 202 with
{"status":"duplicate"} and no new run ID.
When no stable header exists, Hodoflow falls back to a time-bucketed hash of the trigger token and raw body. That protects short retries but is not a substitute for a provider delivery ID. See Retries and troubleshooting.
Retry matrix
| Result | Retry? | Action |
|---|---|---|
| Network timeout before any response | Yes | Retry with the same idempotency/delivery key |
429 |
Yes | Wait the Retry-After duration, then retry |
500 or 503 |
Usually | Exponential backoff with jitter and a bounded attempt/time budget |
401 |
Once after exchange | Discard cached token, exchange, retry once; then alert |
403 |
No | Correct scopes or run-as permissions |
404 |
No unchanged | Correct path/ID or object access |
409 idempotency conflict |
No | Reconcile key reuse; do not generate a new key blindly |
413 or 422 |
No unchanged | Correct body size or validation failure |
Reads are naturally repeatable, but still need bounded backoff. GraphQL
factQuery is read-only and does not use JSON:API response replay. A GraphQL
validation or complexity error is permanent until the document or variables
change.
Operational rules
- Cap attempts and total elapsed time.
- Add jitter so many workers do not retry together.
- Respect the credential-wide rate budget.
- Preserve method, path, body bytes, and idempotency key across retries.
- Record
x-request-id, status, attempt, and non-secret operation identity. - Never log bearer tokens, client secrets, trigger URLs, or sensitive bodies.
Practice the contract in Perform an idempotent write.