The Problem: Transport Is Not Outcome
An HTTP request can end with an uncertain result. A timeout or interrupted connection tells the client that it lacks a complete response. It does not establish whether the provider completed the operation.
A payment orchestration layer should record that attempt as UNKNOWN state and retain responsibility for the next decision. This creates a durable ledger entry for the unresolved attempt.
The ledger is not a claim about provider behavior. It records that the client lacks enough evidence to classify the operation as successful, failed, or safe to repeat.
Hypothetical example: a service submits a payment request and receives no usable response before its local timeout. It records UNKNOWN state, the operation identity, and available request context.
It does not present the operation as failed merely because the transport conversation ended. Recovery must preserve uncertainty until a later check produces more evidence.
The workflow has two separate questions. When should the system look again? What evidence is required before it submits another operation?
This separation matters because resubmission can create a second operation if the first one actually completed. Timing and safety therefore need separate fields and separate decisions.
Three Concepts
The first concept is UNKNOWN state. UNKNOWN state is a durable recovery status used when the client cannot establish the provider outcome from the transport result.
UNKNOWN state keeps uncertainty visible. It prevents an automatic retry from becoming the default interpretation of a missing response.
The second concept is Retry-After guidance. MDN documents the HTTP Retry-After header as guidance on how long to wait before another request.
In this design, Retry-After guidance controls timing. It does not, by itself, prove that an earlier operation failed, succeeded, or is safe to repeat.
The third concept is Outcome reconciliation. Outcome reconciliation is the step that seeks evidence about the provider outcome before resubmission.
It can use a status lookup or another reconciliation path appropriate to the system. Its purpose is to obtain outcome evidence, not to infer an outcome from elapsed time alone.
These concepts are related but not interchangeable. UNKNOWN state describes what the orchestrator knows. Retry-After guidance describes when to check. Outcome reconciliation seeks evidence about what happened.
The Adjacent Connections
UNKNOWN state and Retry-After guidance are connected, but they answer different questions: UNKNOWN state records uncertainty, while Retry-After guidance addresses when another request should be attempted.
Retry-After guidance and Outcome reconciliation are connected because Retry-After guidance can postpone the next check, while Outcome reconciliation supplies evidence about what happened.
UNKNOWN state and Outcome reconciliation are connected because UNKNOWN state preserves the unresolved case, while Outcome reconciliation seeks evidence about the provider outcome.
These connections define an ordered workflow. First, record UNKNOWN state when the result is unresolved. Next, apply Retry-After guidance to schedule a later check.
Then route the operation through Outcome reconciliation. Reconciliation supplies evidence for a separate safety decision; it does not automatically authorize resubmission.
Hypothetical example: a provider response gives Retry-After guidance. The orchestrator schedules a later check instead of treating the header as permission to issue a duplicate operation immediately.
Ledger Schema and Retention-Aware Resubmission
A minimal ledger record can make these distinctions operational. One schema has operation_id, idempotency_key, state, request_context, and first_attempt_at.
Add last_observed_at, retry_after_at, reconciliation_status, key_age_at_decision, provider_retention_note, and next_action.
operation_id identifies the business operation being recovered. idempotency_key identifies the key used for the earlier attempt, if one was used.
state records UNKNOWN state or a later workflow state. request_context preserves the information needed to identify the attempt and perform an appropriate reconciliation action.
first_attempt_at supports age calculations. last_observed_at records the latest transport or reconciliation observation without treating that observation as a confirmed provider outcome.
retry_after_at stores a suggested follow-up time when Retry-After guidance is available. It is timing data, not proof that the earlier operation failed.
reconciliation_status records whether the system has sought outcome evidence and what result that check produced. It should not be overloaded to mean that resubmission is safe.
key_age_at_decision records the age considered by the safety review. provider_retention_note records the relevant documented provider policy and any uncertainty about its applicability.
next_action makes the worker's intended follow-up explicit. Examples include wait, reconcile, review safety, stop after a confirmed outcome, or resubmit after an explicit approval rule.
A simple state flow can be written as transitions. SUBMITTED becomes UNKNOWN state when the client lacks a usable response and cannot establish the provider outcome.
UNKNOWN state becomes RECONCILIATION_DUE when the recorded timing condition permits another check. The transition does not imply that the original operation failed.
RECONCILIATION_DUE becomes OUTCOME_KNOWN when the reconciliation path supplies evidence sufficient to classify the provider outcome. The evidence should be recorded with the observation.
RECONCILIATION_DUE can instead become SAFETY_REVIEW when reconciliation does not establish an outcome. This branch preserves uncertainty rather than silently converting it into failure.
SAFETY_REVIEW considers outcome evidence, key age, and provider retention policy. It may select stop, continue checking, or resubmission according to an explicit rule.
There should be no implicit transition from UNKNOWN state directly to resubmission merely because a timer fired. A timer can make a check due; it cannot create outcome evidence.
Hypothetical example: a worker opens an UNKNOWN record after its retry_after_at. It performs reconciliation, records the result, and evaluates the provider's retention policy before selecting next_action.
This schema also supports auditability. A later reviewer can distinguish what the client observed, when it checked, what timing guidance it applied, and why it considered resubmission.
Idempotency can reduce accidental duplication, but its safety properties depend on the provider's documented retention policy. A client must not treat its local key as proof of indefinite provider retention.
Stripe documents a provider-specific rule for API v1: idempotency keys may be removed after they are at least 24 hours old. This is a policy statement about Stripe API v1.
Stripe also documents that reusing a key after the original has been pruned generates a new request. The old key can therefore stop representing the original deduplication context under that documented policy.
The design consequence is not that every late resubmission is forbidden. It is that a late resubmission requires an explicit safety decision.
That decision should consider the available outcome evidence, the age of the key, and the provider's retention policy. Local storage of the key is only one input.
Timing and safety should remain separate fields. A Retry-After value can say when the system may perform another check.
It cannot establish that the provider still recognizes an idempotency key. Likewise, key presence in the client record cannot prove that the provider still retains the prior result.
Hypothetical example: an operation remains UNKNOWN after the earliest point when the provider says a key may be pruned. The original key is still available locally, but the workflow does not treat that copy as proof of provider matching.
Instead, the workflow sends the case to SAFETY_REVIEW. That review decides whether the evidence and documented retention behavior make resubmission acceptable under the system's rule.
If resubmission is selected, the ledger should record the reason, the policy considered, and the relationship to the unresolved attempt. This preserves the distinction between a deliberate new request and a presumed duplicate.
The same discipline applies when no Retry-After guidance is available. The absence of timing guidance does not prove failure, and the presence of a key does not prove deduplication.
Practical Recovery Rule
A compact implementation rule is: unresolved transport result becomes UNKNOWN state; Retry-After guidance determines when to check again; Outcome reconciliation determines whether the provider outcome is known; retention policy informs whether resubmission is safe to consider.
The rule deliberately avoids turning waiting into evidence. The passage of time can satisfy timing guidance, but it does not establish what happened to the earlier operation.
Outcome reconciliation is the evidence-producing step. A separate safety decision then evaluates whether the evidence, key age, and provider policy support a later resubmission.
It evaluates the remaining evidence and the documented idempotency retention window before selecting a next action. The decision can be to continue checking, stop, or consider resubmission under the explicit rule.
The late-outcome ledger has a narrow purpose: preserve uncertainty long enough for a retention-aware decision. It separates transport state, timing guidance, outcome evidence, and resubmission safety.
That separation makes recovery easier to reason about. It reduces the risk that a timing header or an old key will be mistaken for proof of a safe retry.
Sources
https://docs.stripe.com/api/idempotent_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After

