Idempotency
Every analysis request requires an Idempotency-Key. One key represents one logical message submission.
Key contract
Use 8–128 ASCII characters matching:
^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$
A UUID with an integration prefix is suitable:
mailgw-0b8c29c8-491a-4a8d-a832-58e5417e065f
The key is not the API credential. Do not include an address, subject, message ID, or other personal data in it, and do not reuse it indefinitely.
Observable behavior
- Create a new key for every new logical submission.
- Read the EML bytes once and retain that immutable buffer for all attempts.
- Reuse the same key and exactly the same bytes after a network failure, client timeout, or retryable response.
- The same scoped key and same bytes can replay the stored public response for 24 hours.
- The same key with different bytes returns
409 idempotency_conflict; do not retry that combination. - A completed replay does not account the same operation twice.
- A client timeout does not prove that Hermes did not execute the operation.
503 analysis_outcome_unknownmeans Hermes cannot safely confirm the original outcome. Keep the same key; never create another key automatically to bypass it.
Idempotency is scoped to the authenticated credential's organization, customer, and environment. Callers never select that scope in the request.
Retry decisions
| Outcome | Retry? | Same key and bytes? | Delay | If it persists |
|---|---|---|---|---|
| Network error or client timeout | Yes, bounded | Yes | Exponential backoff with jitter | Stop and contact support; explain that no terminal response arrived |
408 request_body_timeout | Yes, bounded | Yes | Exponential backoff with jitter | Check upload/network behavior, then provide request_id |
409 idempotency_conflict | No | Not applicable | None | Recover the original bytes or start a genuinely new operation with a new key |
429 | Yes, bounded | Yes | Use Retry-After when present; otherwise backoff with jitter | Reduce concurrency and provide request_id |
500 internal_error | Yes, bounded | Yes | Backoff with jitter | Stop; provide request_id without assuming another retry will succeed |
503 idempotency_in_progress | Yes, bounded | Yes | Use Retry-After | Stop and provide request_id |
503 analysis_outcome_unknown | Yes, later and bounded | Yes | Use Retry-After when present | Do not create a new key; contact support |
Other 503 | Yes, bounded | Yes | Use Retry-After when present; otherwise backoff with jitter | Stop and provide request_id |
Other 4xx | No automatic retry | Preserve for diagnosis | Correct the request or authorization first | Contact support if the correction is unclear |
Hermes sends Retry-After only when it can calculate a useful interval. Its absence is not permission to retry immediately.
The 24-hour replay window supports recovery; it is not long-term result storage. Persist the key, terminal status, analysis ID, and request ID in your own authorized system.