A server saves an enquiry, but the response is lost. The browser cannot tell whether saving succeeded. Retrying is reasonable, yet an ordinary second request may create another record.
An idempotency key gives the server a way to recognize another attempt at the same logical operation.
Define the operation first
For a lead form, one key can represent one enquiry submission. It should not represent every enquiry from the same email address forever.
A useful contract is: unchanged retries reuse the key; a new enquiry uses a new key. If the user edits the payload after an uncertain outcome, define an explicit recovery process instead of silently attaching different data to the old operation.
The key is an opaque identifier. It should not contain an email address, telephone number, or message text.
Bind the key to its context
Store the key within the appropriate tenant or caller scope, alongside a request fingerprint and processing state. If an existing key arrives with a different payload, reject the mismatch.
Do not expose a saved response to an unrelated caller merely because they present the same key. Idempotency is not authentication.
Make the first write atomic
Two requests may arrive before either finishes. A lookup that says 'not found' in both requests is insufficient.
Use a unique constraint or equivalent atomic reservation. Specify how a request behaves when the operation is already in progress: it might receive a processing response and retry later.
For local database changes, the enquiry and its operation state should be committed consistently. Otherwise a crash can create an enquiry without a corresponding deduplication record.
Understand remote boundaries
An idempotent local endpoint does not automatically make the CRM API idempotent. A network failure can still occur after the remote record is created.
Pass a stable external reference or supported provider idempotency key downstream. If the provider offers no reliable mechanism, route uncertain outcomes into reconciliation rather than promising exactly-once creation.
Define retention and recovery
Keep keys long enough to cover the expected retry window. Explain what happens after expiry. A key that has been deleted can no longer protect against an old replay.
Test simultaneous requests, lost responses, changed payloads, worker crashes, and expired keys. Record expected outcomes before implementation.
The goal is a clear retry contract. A random identifier in a request header only becomes useful when the backend enforces that contract.
Top comments (0)