Creating an off-ramp
Move crypto into a bank account with KiiChain Pay. Quote a rail, open the off-ramp, execute the on-chain transaction, and track the activity until the fiat lands.
An off-ramp converts crypto into fiat, paid out to a bank account. Unlike an on-ramp, the user (or your backend, via a delegated wallet) must execute an on-chain transaction to move the crypto into settlement. After that, the activity passes an AML check and provider processing before the fiat is sent to the destination bank account.
At a glance
Direction
Crypto → Fiat
Create endpoint
POST /tickets/v1/offramp
User acts
On-chain — executes the returned transaction
On-chain signing
Delegated Kii Wallet (server-side) or external wallet (self-sign)
You need
A KYC-verified account, an off-ramp products_provider_id, a bank withdraw_destination_id, and a delegated Kii Wallet (for the primary path)
Tracks via
display_status on the activity
Prerequisites
A KiiChain Pay account that has completed KYC, with its Kii Wallet delegated if you want KiiChain Pay to sign the on-chain step for you.
An API key with
tickets.tickets.writeand (for the delegated path)blockchain.transactions.execute; write calls must be signed.Your
account_id, your on-chain wallet address, and a bank withdrawal destination.
Set up a bank withdrawal destination
The fiat payout goes to a confirmed bank destination. If you don't have one yet, create it (see Discovering rails & IDs for the full flow):
GET /accounts/v1/rails/schemas?country={country}— read the bank rail's requiredpayloadfields.POST /accounts/v1/users/{userId}/accounts/{accountId}/withdrawal_destinations— register it with{ rail_code, rail_version, payload, name }.POST …/withdrawal_destinations/{destinationId}:confirm— confirm with theverify_codeyou receive.
Then list your destinations and pick the id of the "bank" one — that's your withdraw_destination_id. The examples assume KII_API_KEY, KII_ACCOUNT_ID, KII_ADDRESS (your 0x… wallet address), and KII_WITHDRAW_DEST_ID are set.
Step 1 — Get a quote
Find an off-ramp rail (a products-provider whose type is "offramp") and quote it for the crypto amount you want to sell. For an off-ramp the amount is crypto in atoms (smallest unit).
The response is a signed quote envelope with target_type: "offramp"; pass it back unchanged in the next step. Quotes expire — check expiration_date / exp.
Step 2 — Create the off-ramp
Create the activity with the quote, your account_id, user_chain_address, and the bank withdraw_destination_id. This is a signed write request.
The response holds the new ticket and the transactions you must execute on-chain to fund the off-ramp:
If the token needs an ERC-20 allowance, an approval transaction is prepended to the list. Execute the transactions in order.
Step 3 — Execute the transaction
KiiChain Pay does not sign for you at create time — the transactions come back unsigned. You execute them one of two ways.
With a delegated Kii Wallet (recommended)
Hand the returned transactions straight to the blockchain execute endpoint. KiiChain Pay signs and broadcasts them from your delegated Kii Wallet, with gas sponsored. This is a signed write request.
A hash of "0x00" in the array means that transaction failed to broadcast.
This path requires a delegated Kii Wallet. Without delegation the call errors — see Privy delegated access.
With an external wallet
If the user holds their own keys, don't call KiiChain Pay to sign. Take each evm transaction's chain_id, to, value, and data, then sign and broadcast it with your own signer (for example, viem's sendTransaction). KiiChain Pay observes the on-chain event and advances the activity.
You can re-fetch the outstanding transaction at any time while the activity is open with GET /tickets/v1/{ticketId}/pending_user_actions (it returns a transaction_payload).
Step 4 — Track to completion
Poll the activity and watch display_status.
After your transaction confirms, the activity runs an AML check, then provider processing, then pays out — display_status moves through processing to fulfilled when the fiat is sent to the bank account. If the AML check or provider rejects the transfer, the crypto is returned and the activity ends as refunded (or canceled / failed). While the activity is awaiting on-chain confirmation you can cancel it — GET /tickets/v1/{ticketId}/user_txs returns a cancel transaction when that action is available.
Full example
End-to-end off-ramp via a delegated Kii Wallet, using the kiiFetch signing helper from Generating API keys.
Related
Creating an on-ramp — the reverse: fiat → crypto.
Creating an FX swap — same create-and-execute shape, crypto → crypto.
Privy delegated access — server-side signing for the on-chain step.
Guides overview — discovering rails, destinations, and IDs.
Last updated