Skip to main content
A stablecoin ramp is symmetric: on-ramp takes fiat in and delivers stablecoin to a wallet; off-ramp takes stablecoin in and delivers fiat to a bank. Both lean on the same v3 trade-and-settle calls, with the chain selection handled entirely by which verified withdrawal account you target.

When to reach for this

  • A fintech offering “USD → USDC on Solana” in-app
  • A merchant accepting USDC and settling to fiat on their bank cut-off
  • A treasury moving between fiat reserves and on-chain working capital
For a side-by-side comparison of all four patterns, see Integration patterns.

Setup

1

Verify the withdrawal account(s)

For an on-ramp, verify the stablecoin wallet on the chain you want to deliver to. For an off-ramp, verify the bank account that should receive the fiat. Both happen in the OpenFX dashboard. See Verified accounts for the walkthrough.
2

Confirm the chain

The network field on a stablecoin withdrawal account binds the chain. USDC on Solana and USDC on Ethereum are separate ledgers — see Supported networks for the full stablecoin × chain matrix. Pick the chain your end-user actually expects to receive on.
3

Subscribe to webhooks

Both flows benefit from the deposits event (so you react the moment funds arrive) and the withdrawals event (so your customer’s “your USDC is on Ethereum” message fires the second the on-chain tx confirms). Each webhook’s data is the resource object, so the terminal state is in data.status. See Webhooks setup.

On-ramp: fiat → stablecoin

1. Detect the fiat deposit

The customer’s wire arrives. OpenFX detects it (Deposit lifecycle) and either fires a webhook or you find it on GET /v3/fx/deposits. Match it to your internal user via the senderReference your customer was told to put in the wire memo.

2. Quote USD → USDC

cURL

3. Execute the trade

cURL
After execution, USD has decreased and USDC has increased in your balances. The chain doesn’t matter yet — USDC is one balance until you withdraw.

4. Withdraw to the customer’s chain-specific wallet

The withdrawalAccountId selects both currency (USDC) and chain (Solana). You don’t pass a network field — it’s bound to the account.
The withdrawal reaches COMPLETED once the chain reaches the configured confirmation count. The response carries network and transactionHash so you can surface the chain explorer link to your user. See Supported networks for per-chain request examples (Ethereum, Solana, Tron, BSC, etc.).

Off-ramp: stablecoin → fiat

1. Receive the stablecoin deposit

The customer sends USDC to your OpenFX deposit address. The deposit record’s network tells you which chain it landed on; transactionHash is the on-chain reference for support tickets.
Wait for status: "COMPLETED" — that’s when the funds are spendable. A stablecoin deposit appears as PENDING the moment OpenFX observes the on-chain transfer, then COMPLETED once it clears (or ERROR if it doesn’t). See Deposit lifecycle.

2. Quote USDC → USD

Same shape, opposite direction:

3. Execute the trade

Same POST /v3/fx/trades as the on-ramp. After execution, USDC has decreased and USD has increased.

4. Withdraw to the customer’s bank account

The rail (Fed Wire vs SWIFT vs SEPA vs SPEI) is bound to the bank account. See Settlement times for cut-offs.

Choosing the right chain on on-ramps

When your UX lets a user pick the chain to receive on, the choice matters: The full chain matrix per stablecoin (USDC, USDT, EURC) is at Supported networks.

Common mistakes

  • Treating “USDC” as one chain. A withdrawal to a Solana wallet can’t be sent on an Ethereum withdrawalAccountId — they’re separate addresses, separate ledgers. Confirm the verified withdrawal account’s network matches the user’s expectation before withdrawing. Sending to the wrong-chain address is not recoverable.
  • Quoting before the deposit clears. A PENDING deposit isn’t usable balance yet. Wait for COMPLETED (or for the webhook) before issuing the quote.
  • Polling chain explorers instead of GET /v3/fx/withdrawals/{id}. OpenFX’s own state machine is the source of truth; the explorer’s view can lag (or, for some chains, race ahead before OpenFX considers it confirmed).
  • Quoting first, then realizing the wallet isn’t verified. Set up the verified withdrawal account before the user’s first on-ramp; the quote → trade → withdrawal chain assumes the account is already in place.

What’s next

Supported networks

Stablecoin × chain matrix + per-chain request bodies.

Settlement times

Fiat-rail cut-offs by currency.

Deposit lifecycle

How deposits get from observed → credited.

Cross-border payments

The fiat-only sibling of this flow.