Skip to main content

Book transfers

Move same-currency fiat between accounts under your partner API key (for example one customer’s EUR account to another customer’s EUR account). Source is always a customer-owned fiat account_id (pcus_*). Destination may be another customer’s (or legacy entity) account id reachable under the same key. Prerequisite: Customers quickstart. Banking gate: products.deposit_account.status=ready.

Auth and environments

Gates

Source account_id must belong to {customer_id}. Destination to_account_id must be under the same API key (may belong to another pcus_* or a legacy entity account). If banking routes are called before ready, expect 409 with data such as deposit_account_status and reason: banking_profile_incomplete.

Happy path

1

Confirm banking ready

Poll GET /partner/customers/{customer_id} until deposit_account.status=ready
2

List accounts

Resolve source fiat account_id and destination to_account_id via GET …/accounts
3

Preview

POST …/book-transfers/preview with to_account_id + amountpreview_token
4

Confirm

POST …/book-transfers with preview_token + idempotency_key (tokens expire quickly; use a fresh preview)
5

Re-list balances

GET …/accounts on both sides to confirm balances moved

1. Resolve accounts

Use ids returned by your API key (do not hardcode from this guide).

2. Preview

Preview and confirm must use the same source account_id. The preview_token seals source + destination internally.
Typical success shape (field names may vary slightly):
Save preview_token. Tokens expire quickly; confirm promptly or re-preview if needed.

3. Confirm

On live, confirm moves real fiat balances. Prefer sandbox for full preview → confirm loops only when both accounts already have usable balance (sandbox self-serve funding is often unavailable). Otherwise validate preview errors (for example insufficient balance → 422) without confirming.
Reuse the same idempotency_key on retries after network errors. Confirm success typically includes status: completed (or submitted), id, amounts, customer_id, and fee status final.

Business rules

  1. Same currency fiat → fiat only (e.g. EUR → EUR).
  2. Same partner API key: destination must be reachable under this key (another pcus_* or legacy entity account).
  3. Preview → confirm on the same source account_id; use a fresh preview if the token expired.
  4. Partner-neutral JSON: error message / data do not expose upstream PSP names.
  5. Balance: book transfers require available >= amount (exact balance is allowed). This differs from stablecoin sends, which need amount strictly below available (1 minor-unit headroom). Insufficient balance still returns 422 with data.available, data.amount, and data.currency when known.

Legacy routes

The same operations exist under /partner/entities/{entity_id}/accounts/.../book-transfers. Those paths are legacy. New integrations should use pcus_* customer paths only.

Errors

Next