Skip to main content

Currency conversions

Convert cross-currency fiat (and eligible ledger pairs) between accounts owned by the same customer — for example EUR → NGN on that customer’s ledger. This is not a book transfer (same currency) and not a corridor order quote (fiat ↔ crypto ramp). Prerequisite: Customers quickstart. Banking gate: products.deposit_account.status=ready. Both accounts must be status=active and owned by {customer_id}.

Auth and environments

Gates

If banking routes are called before ready, expect 409 with data such as deposit_account_status and reason: banking_profile_incomplete.

Indicative rates vs binding conversion

Use conversion preview for ledger FX insight and confirm. Do not treat corridor indicative rates as the convert price.

Happy path

1

Confirm banking ready

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

List accounts

Resolve source and destination fiat account_ids via GET …/accounts (different currencies; both owned by this customer)
3

Preview

POST …/conversions/preview with to_account_id + amountpreview_token, rate, expires_at
4

Confirm promptly

POST …/conversions with preview_token + idempotency_key before expires_at (often a few minutes)
5

Re-list balances

GET …/accounts on source and destination 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, amounts, and rate.
Typical success shape:
Save preview_token. Confirm before expires_at. If the quote is already stale at preview time, expect 422 with data.code: quote_expired — request a new preview.
Amounts below the rail minimum return 422 (for example data.min_amount / data.field: amount). Same source and destination account returns 422 on to_account_id.

3. Confirm

On live, confirm moves real balances. Sandbox: self-serve deposits may not credit usable balance for outbound converts. Contact Element Pay for a sandbox credit if you need to exercise preview → confirm (same pattern as deposit instructions / stablecoin sends).
Reuse the same idempotency_key on retries after network errors (replay returns the same conversion id). Do not reuse a preview token after a successful confirm — request a fresh preview for the next conversion.

Business rules

  1. Cross-currency only — source and destination currencies must differ; same-currency moves use book transfers.
  2. Same customer — both accounts belong to {customer_id} (not another pcus_* under the key).
  3. Preview → confirm on the same source account_id; respect expires_at (shorter than many other banking previews).
  4. Balance: available >= amount on the source account.
  5. Partner-neutral JSON: error message / data do not expose upstream PSP names. Ops may see upstream_http_status only.

Errors

Next