Why a retry can create two invoices

Billing requests an invoice for an order and stops waiting after 5 seconds. Compare two scenarios: the provider answers late, or the first request never reaches it.

A timeout doesn't tell you whether the invoice was created.

Sequence diagram: a retry creates a second invoice Billing asks the invoice provider to create an invoice for order 1042. The provider creates INV-1 but answers slowly. After 5 seconds billing stops waiting and sends the same request again. The provider treats it as new and creates INV-2, then answers with INV-2. The late answer with INV-1 arrives after 45 seconds. Result: two invoices for one order. Billing Invoice provider create invoice, order 1042 creates INV-1 timeout 5 s retry: create invoice, order 1042 creates INV-2 INV-2 INV-1 (after 45 s) 2 invoices for 1 order
Initial scenario: the retry creates a second invoice. Simulated provider, runs in your browser.
Explanation

What's going on

The key belongs to the order, not to an attempt, and is stored before the first call, so a crash and restart reuse it. A provider that supports idempotency keys returns the original result for a key it has seen.

Without retries there are no duplicates, but failed requests stay unresolved. A longer timeout only helps if the answer arrives before it expires.

In this model: one order, at most one invoice, as long as the provider remembers the key.

Assumptions

  • The simulated provider remembers keys and returns the original invoice for a repeated key within its retention window.
  • In scenario A the first answer always takes 45 seconds and the retry is answered immediately.
  • Many real providers don't support idempotency keys. A lookup before retrying helps, but can't settle a request that is still in flight. A reference for which the provider allows at most one invoice, or reconciliation afterwards, are the reliable options. Adding a header alone prevents nothing.