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

  1. Generate one immutable internal reference for each intended payment.
  2. Persist the request payload and reference before sending the request.
  3. Store the Roots payment ID when Roots returns it.
  4. When a request outcome is uncertain, retrieve and reconcile before issuing another instruction.
  5. 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


Did this page help you?