Begin with the uncertain outcome

Imagine a mobile user submits a collection record. The server accepts it, but the response never reaches the phone. From the user’s point of view, the request failed. From the system’s point of view, the action already happened.

A retry is a reasonable response to that uncertainty. Without a deliberate contract, however, the retry may create a second record. The interface and the API need a shared understanding of which attempts belong to the same action.

Give the action an identity

One design approach is to assign a stable identifier to a logical action and reuse it for retries. The server can associate that identifier with a request fingerprint and an outcome. A second attempt with the same identity should not silently become a second business event.

Scope the identifier to the correct user or account boundary. A reused identifier with a different payload should be treated as a conflict, not accepted as an equivalent request. Concurrent attempts also need an atomic decision; a check followed by an unrelated insert can still race.

Define more than the happy path

Decide how the API handles an operation that is still running, one that completed, and one that failed before its effect was committed. The contract also needs a retention policy: after an identifier expires, a retry may no longer be recognized.

Database writes and an outgoing message can create another partial-failure boundary. A transaction or an outbox pattern may be appropriate, depending on the system. The important question is what evidence remains when only part of the operation succeeds.

Give the interface an honest state

“Saved on this device,” “waiting to sync,” and “accepted by the server” describe different facts. If the interface collapses them into one success message, the user has no useful way to respond when synchronization stalls.

Offer an understandable retry or review path. Avoid making users invent new records because an existing one appears stuck. An operational view should expose enough context for a person to reconcile a disputed action.

Test the point where certainty disappears

Exercise a lost response after a committed write, concurrent duplicate requests, a reused key with a changed payload, and an expired identifier. Verify business effects as well as status codes.

HTTP method semantics provide a starting point: idempotency concerns the intended server effect of repeated identical requests. A method name alone cannot implement that promise for your application. The final contract must be enforced by the server and explained to its clients.

Reference: MDN: Idempotent HTTP methods. This note offers a design approach; it is not a claim of a measured client outcome.

Backend & API development