In this article
Repeating POST can create new work. Define application deduplication separately, including key scope, lifetime, payload conflicts and in-progress behavior.
A client sends a request but loses its connection before receiving the result. The server may have rejected it, accepted work still running, or completed it already. These cases can look identical externally. Repeating generation is therefore not automatically safe. A service seeking deduplication needs an explicit application contract rather than identical text or coincidentally matching identifiers.
Start with method semantics
RFC 9110 distinguishes idempotent methods and limits on automatically retrying non-idempotent work. Generation POST does not become idempotent through an API compatibility label. Nor should Idempotency-Key support be attributed to an external platform without specific documentation.
Separate logical operations from transport attempts in your own design. Attempts have distinct times and outcomes but may represent one client intention. Preserve the original outcome when making another attempt because it defines remaining uncertainty about performed work.
Define key scope
For a request ledger, specify deduplication scope: tenant, endpoint, model or another explicit combination. Keys must not accidentally merge different clients’ requests. Define retention and post-expiry behavior; a single field does not create permanent memory.
A payload fingerprint can detect reuse with different content. Its composition is contractual: material parameters, JSON normalization and model changes all need rules. Different values must not silently become one request merely to suppress duplicate statistics.
Describe ledger states
Distinguish at least unknown, accepted, running, completed and failed operations. Define repeated-request behavior for each: return a saved result, wait, reject a conflict or another documented branch. This is a design example rather than a claim of an existing service capability.
OpenAPI can describe the interface and responses, but cannot make the ledger transactional or prove single execution. Test simultaneous-attempt races and recovery when a process fails between acceptance and recording the outcome.
Test proxies separately
The NGINX proxy reference documents upstream retry behavior and restrictions. Save effective settings because intermediate layers can add attempts independently of client logic. Retrying at two levels increases executions even if each local attempt limit is small.
Use a fake upstream with distinct attempt IDs and an accepted-work counter. Interrupt delivery after a known stage within a bounded fixture, then perform the chosen retry. Reconcile logical operations, attempts and executions. Receiving identical answers alone does not establish deduplication.
Preserve guarantee boundaries
A successful local test cannot establish exactly-once behavior across an entire distributed chain. State the verified scope and remaining failure windows. If the first attempt remains unknown, retain that uncertainty rather than reconstruct a convenient story after a second answer arrives.
Related guides cover fallback and limits and token reconciliation. They help separate user-visible results from actual attempts and prevent one external request ID from replacing work accounting. A useful final artifact includes the ledger policy, interruption point and observed counts so future implementations can repeat the same claim rather than inherit an undocumented promise.