Skip to content
Recover payments without paying twice
/ArticleAugust 24, 2026Sophie Houser

When a payment request loses its response, the system has an unknown outcome. Treating that as failure and starting a new payment can pay twice. Treating it as success can record money that never moved. The recovery design needs durable intent, constrained financial acceptance and authoritative execution evidence. The example below describes a recovery protocol. It is pseudocode, not a tested provider adapter or a guarantee of exactly-once execution.

Record the command before execution

Persist an immutable business command with its approval, amount, currency, destination or original payment reference, and stable phase identities. Enforce business-intent uniqueness so submitting the same obligation under a new request ID does not evade replay protection. For an external money-out flow, a reviewed ledger model may move an approved payable into an operation-specific pending liability and available internal cash into a reserved account. Accept that transition only if its configured conditions succeed. Do not release reservations merely because execution times out. Do not apply this outbound accounting model unchanged to an inbound customer deposit.

recover(command):
  load durable command and last observed execution state
  if approval or financial acceptance is not established:
    recover acceptance; do not execute speculatively
  evidence = resolve_with_documented_provider_contract(command)
  if evidence is definitive success:
    complete missing accounting and local progress; do not pay again
  else if evidence is definitive failure with no movement:
    apply the reviewed failure transition
  else:
    retain unknown state and relevant reservations
    schedule bounded recovery or human investigation

resolve_with_documented_provider_contract is a placeholder. It requires real lookup, request-replay, retention, event and status contracts; it is not an existing FRAGMENT API method. A missing record or absence from an incomplete statement is not automatically definitive failure.

Two supported integration approaches to evaluate

With an external processor and FRAGMENT ledger, your application coordinates the processor adapter and ledger transitions. Verify event authenticity, deduplicate deliveries, reconcile conflicting observations against canonical records and use stable ledger-write keys for missing posting repair. Posting.

With documented FRAGMENT customer payments, Payment Types define accounting for supported payment flows and payments reconcile automatically to the ledger. Preserve that ownership: do not independently post the native settlement movement a second time. Your application still owns business approval, consent, operational state, exceptions and the recovery work not established by the service's contract. Refunds have pending and terminal states; accepting a refund request is not proof of customer receipt. Make Payments.

Reconcile against evidence you did not create

Compare payment identity, amount, currency and status with independently acquired processor records. Check completeness and freshness. Reconcile settlement separately with bank evidence. For external records, Custom Links let you supply account and transaction data when an appropriate native integration is unavailable. A linked ledger account references an external account, and reconcileTx associates accounting with a synced transaction. That match does not establish that your importer captured every external transaction. Keep source pagination, coverage windows, duplicates and ingestion health observable. Sync transactions, reconcile transactions.

For Custom Links, sync settled transactions with stable external identities at the documented scope. Do not import pending or declined attempts as settled evidence. The unreconciled-transaction query is eventually consistent: a recently empty result alone is not proof of complete reconciliation. Sync transactions, reconcile transactions. A processor-statement example needs at least these rows:

Independent recordLedger expectationException
Successful payment with no financial recordMissing accounting repaired onceNever execute payment again to fix the journal
Financial success with no matching complete-source evidenceInvestigate status and source coverageDo not automatically delete history or pay again
Same operation, different amount or currencyNo silent matchReview mismatch
Completed payout, no bank receipt evidenceClearing remains explainableTrack settlement separately

Linked accounts do not support posting conditions. Keep guarded internal availability separate and review how linked settlement consumes clearing balances without double counting. Consistency.

Prove recovery before unattended use

Kill the worker before the request, after external success but before local acknowledgement, and after accounting but before marking progress. Replay notifications and race two requests against the same capacity. Test unknown outcomes beyond the provider's replay window. The required evidence is one authorized external effect, one intended financial effect and an auditable recovery history; or an explicit blocked exception when resolution is unsafe. Passing a mock test proves only the modeled behavior. Sandbox API evidence is needed for integration, and sandbox behavior does not establish production-provider guarantees.

Implementation references

Use the current API contracts when implementing the architecture: