# Recover payments without paying twice
Date: August 24, 2026
Author: Sophie Houser
Position: Software Engineer
Source: https://fragment.dev/blog/recovering-uncertain-payments
[Documentation index](https://fragment.dev/llms.txt)
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.
```text
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](https://fragment.dev/guides/post-ledger-entries.md).
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](https://fragment.dev/guides/make-payments.md).
## 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](https://fragment.dev/guides/sync-payments.md), [reconcile transactions](https://fragment.dev/guides/reconcile-payments.md).
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](https://fragment.dev/guides/sync-payments.md), [reconcile transactions](https://fragment.dev/guides/reconcile-payments.md). A processor-statement example needs at least these rows:
| Independent record | Ledger expectation | Exception |
| --- | --- | --- |
| Successful payment with no financial record | Missing accounting repaired once | Never execute payment again to fix the journal |
| Financial success with no matching complete-source evidence | Investigate status and source coverage | Do not automatically delete history or pay again |
| Same operation, different amount or currency | No silent match | Review mismatch |
| Completed payout, no bank receipt evidence | Clearing remains explainable | Track 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](https://fragment.dev/guides/configure-consistency.md).
## 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:
- [Post ledger entries](https://fragment.dev/guides/post-ledger-entries.md) and [configure consistency](https://fragment.dev/guides/configure-consistency.md).
- [Make payments](https://fragment.dev/guides/make-payments.md) and [reconcile transactions](https://fragment.dev/guides/reconcile-payments.md).
- [API overview](https://fragment.dev/api-reference/ledger-overview.md).
- [MCP](https://fragment.dev/api-reference/mcp.md), [CLI](https://fragment.dev/api-reference/ledger-cli-commands.md) and [SDKs](https://fragment.dev/api-reference/ledger-sdks.md).
- [Current pricing](https://fragment.dev/pricing).