The destination must support a real-time rail. Off-ramping is destination-amount-driven and
the locked quote has a short validity window — slow rails (ACH, DOMESTIC_WIRE) can be used but the
end-to-end UX is no longer “instant”. Use one of these for true real-time settlement:
Off-ramping (stablecoin → fiat) uses a destination-amount-driven flow with a locked quote.
Two practical implications worth knowing up front:
You specify what the end-user receives (e.g. destination.amount: 100 USD, or
1000 CAD). Superbank quotes the source crypto amount needed to deliver that — fees and
FX baked in.
The deposit wallet is per-payment and short-lived. Each settlement returns a unique
payment_instructions.wallet_address valid for 15 minutes. After that the quote
expires and you’ll need a new settlement request.
Your end-user requests to off-ramp through your UI or API. They specify the destination bank
account and how much fiat they want to receive.Persist the destination bank details for the next step.
Send an Idempotency-Key header. Recommended today, required
in a future API version. Generate a UUID v4 per logical operation
and include Idempotency-Key: <uuid> on the POST. Same key
replayed → we return the original response, no duplicate settlement.
See the Idempotency guide for
retention, scope, error codes, and dispatcher pattern.
Create a settlement request by sending a POST to /v0/settlement-requests. The response’s
payment_instructions block carries the locked quote (amount, exchange_rate, fee) and
the per-payment wallet_address you’ll send the source stablecoin to.As with on-ramping, we recommend supplying external_id (your internal identifier) and optional
metadata — both are echoed back on every read and webhook, and external_id is filterable on
the list endpoint.
destination.amount vs the top-level amount. For STABLECOIN_TO_FIAT, set amount on the
destination object — that’s what the end-user will receive. The top-level amount field is
for STABLECOIN_TO_STABLECOIN and FIAT_TO_STABLECOIN where source and destination are the same
currency.
destination.country_code is required. ISO 3166-1 alpha-2 (e.g. US, CA, DE). The
quote engine rejects fiat destinations without it.
source.wallet_address is your sending wallet — the one you’ll broadcast the on-chain
transfer from in Step 3. Superbank records it for KYC/AML correlation; it isn’t where the
funds end up.
The rate, fee, and validity window are all surfaced in payment_instructions so you can
render exactly what your end-user will be charged before they confirm.
Example B — USDC on Ethereum → CAD via LOCAL (cross-currency, instant)
Cross-currency: source is USDC on Ethereum, destination is CAD via Interac (routed as LOCAL).
The quote includes both the CAD-lane fee and the locked FX rate.
Step 3: Send the source stablecoin to payment_instructions.wallet_address
Broadcast an on-chain transfer of exactly payment_instructions.amount of
payment_instructions.currency from the wallet you specified in source.wallet_address to
payment_instructions.wallet_address.
Send the exact payment_instructions.amount from the wallet in source.wallet_address.
The quote is locked against that figure. Underpayment will fail to settle. Overpayment may
settle but the difference isn’t recoverable through this flow.
The deposit wallet is a placeholder in sandbox.payment_instructions.wallet_address
comes back as something like 0xExampleAddress1234567890098765432 regardless of the
source chain. See Testing in sandbox below for how to drive the
end-to-end flow without an on-chain transfer.
Once SETTLEMENT_COMPLETED arrives, close the settlement by calling REQUEST_COMPLETED with the
on-chain transaction hash of your Step 3 deposit. This is the audit reference Superbank records
to tie the settlement to its on-chain leg.
The sandbox lets you exercise the full off-ramp flow end-to-end without ever
moving real crypto on-chain.
The deposit wallet is a placeholder in sandbox.payment_instructions.wallet_address
comes back as something like 0xExampleAddress1234567890098765432 regardless of
the source chain. Sending real funds to it is impossible — skip the on-chain
transfer (Step 3 above) and advance the flow with the sandbox transition
endpoint instead.
Step 3: Transition the payout to PROCESSING → COMPLETED
Use the sandbox payment-transition endpoint. Each PATCH fires the same
payment.updated and settlement_request.updated webhooks your production
handler will see.
Quote expired. If more than 15 minutes pass between settlement creation and your on-chain
deposit (valid_until), the quote expires. Create a new settlement request — same
destination, new payment_instructions with a fresh rate.