Idempotency
Design payment creation to prevent duplicate money movement while the Roots idempotency contract evolves.
Prevent duplicate money movement by designing payment creation around a stable idempotency strategy.
See API availability before using a retry strategy in production.
Why idempotency matters
A network timeout does not tell you whether Roots created a payment. Retrying the same instruction without a confirmed idempotency contract can create duplicate money movement.
Use a stable internal payment reference for each intended instruction. The current payment schema includes an optional external_id field that you can store with the Roots payment ID for reconciliation.
{
"external_id": "payout_20260803_001",
"source": {
"kind": "account",
"id": "account_123"
},
"destination": {
"kind": "counterparty",
"id": "counterparty_123"
},
"amount": 1250.5,
"purpose": "supplier_payment"
}Build a safe internal workflow
- Generate one immutable internal reference for each intended payment.
- Persist the request payload and reference before sending the request.
- Store the Roots payment ID when Roots returns it.
- When a request outcome is uncertain, retrieve and reconcile before issuing another instruction.
- Never create a replacement payment solely because a client request timed out.
Target schema — confirm in API reference
Roots has not yet published a production idempotency mechanism. Do not assume that external_id is an idempotency key or that repeated values will be rejected.
Confirm the following before enabling automatic retries:
- The required idempotency header or request field.
- The key scope and retention period.
- Behavior when the same key carries a different payload.
- Duplicate-response behavior.
- Network-timeout recovery flow.
- Which operations support idempotency.
Next steps
- Read Errors for retry boundaries.
- Read Track payment status before replacing an uncertain payment.
- Read Reconcile balances and payments to match internal references to Roots records.
Updated about 2 months ago