fiat_to_crypto order. You choose how each order is paid: from fiat you already hold in the merchant’s Pending Fund balance, or by a payer who sends a bank transfer for that one order. When the order completes, the crypto is credited to the merchant’s VelaFi wallet. From there you keep it, withdraw it, or have it sent to an external address automatically.
For the full field reference, see the On-Ramp guide and Create an On-Ramp Order.
Choose a funding model
How it works
Before you start
- API access. An API key, your server IPs on the whitelist, and a business token for the
X-BH-TOKENheader. See Authentication. - A verified merchant. The order’s
merchantIdmust be a merchant under your account that has passed verification. See Merchants. - An activated currency account. The merchant needs an active account for the fiat currency. See Activate a Merchant Account.
- Webhooks registered. Register
ORDER_WEBHOOK, plusFUNDING_WEBHOOKif you prefund andCRYPTO_WITHDRAW_WEBHOOKif you withdraw. See Webhooks. Your endpoint must return HTTP2xxwith the body{"callbackStatus":"SUCCESS"}, or the delivery counts as failed. See Delivery and Retries.
Build the flow
1
Prefunded only: fund the Pending Fund balance
Get the deposit details for the merchant’s currency account with Get Pending Fund Account (
GET /v2/merchant/addfunds), and send the fiat there. Each credited deposit triggers a FUNDING_WEBHOOK event with type DEPOSIT and status 2.Check the current balance with List Merchant Accounts (balance) before you create large orders.If you already collect payments into the merchant’s currency account, those deposits make up this balance. See Collect Local Payments with Virtual Accounts.2
Optional: lock the rate with a quote
Call Get a Crypto/Fiat Quote with A
from set to the fiat, to set to the crypto and createQuoteId=true. The price is fiat per 1 unit of crypto.quoteId is valid for 10 seconds in production (300 seconds in the sandbox), is single-use, and is bound to the country, fiat and crypto it was issued for. Request it right before you create the order. Without a quoteId, the order is priced when it is created.3
Create the order
Call If the request times out, look the order up by
POST /v2/order/fiat_to_crypto. Always send a unique clientId (up to 40 characters) so you can retry safely and find the order later.- Prefunded
- Pay-per-order
Set VelaFi checks the merchant’s balance for that currency when it creates the order. If the balance does not cover the order amount, the request is rejected with an insufficient-balance error and no order is created. If the balance covers it, the order is paid from the balance right after creation and moves to
paymentId to 70 (VelaFi Pending Fund).60 (Completed), unless it first needs review or documents (10, 11 or 31). The debit appears in Funding Records as a BUY_CRYPTO record.Response
clientId before you retry. See Idempotency and retries.4
Pay-per-order only: show the payment instructions
Call Get Order with
orderType=fiat_to_crypto and show the payer the contents of paymentInfo (for example the CLABE for SPEI) and the exact fiatAmount.When the payer’s transfer is credited, VelaFi applies it to open orders on the same currency account. A deposit that exactly equals an order’s amount is applied to that order first. Otherwise deposits are applied to the oldest open order. An order with a depositAlias is only paid by deposits to that virtual account. An order without one can be paid by any deposit on the currency account, including fiat that is already in the Pending Fund balance.5
Track the order to completion
Wait for
ORDER_WEBHOOK events, or poll GET /v2/order/detail?orderType=fiat_to_crypto&clientId={clientId}. The order is done when orderStatus is 60, and has failed when it is 70, 80 or 81. When you poll, an order rejected in review is shown as 80 and one rejected in risk review as 81; the webhook sends both as 70. See Order Statuses. The crypto (cryptoAmount) is then in the merchant’s wallet. Check it with Get Crypto Balance.6
Optional: send the crypto out of the wallet
You have two options:
- Automatic withdrawal per order. If VelaFi has enabled automatic on-ramp withdrawal for your account, add
networkandaddressto the create request. After the order completes, VelaFi withdrawscryptoAmountto that address and sendsON_RAMP_WITHDRAW_WEBHOOKwhen the withdrawal succeeds. In production,networkmust bePOLorSPL20. Send both fields or neither. Accounts without the feature are rejected with “You are currently not a user of the onRamp automatic withdrawal service.” See On-Ramp Withdrawal Event. - Withdraw it yourself. Add the destination to your withdrawal whitelist, then call Create a Crypto Withdrawal (
POST /v2/assets/withdraw) with your own uniqueclientId. Use Get Withdrawal Quota for validchainTypevalues and minimums.
CRYPTO_WITHDRAW_WEBHOOK when they reach a final status. For an automatic withdrawal, its clientId is the on-ramp orderId.Webhooks to handle
Events can arrive more than once and out of order, and intermediate statuses can be skipped. Deduplicate, and read the order with
GET /v2/order/detail when an event does not fit the state you hold. See Delivery and Retries.
Handle failures
The payment window
A pay-per-order order waits in40 only for a limited time. VelaFi sets the window for your account. It is not returned in the order detail, so ask your VelaFi contact for the value and show the payer a deadline based on createTime. When the window passes without a full payment, the order is cancelled. It is reported as orderStatus 70 in order detail and in ORDER_WEBHOOK. A cancelled order cannot be reopened.
If the payer pays after the order was cancelled, the transfer is still credited to the merchant’s Pending Fund balance (you receive a FUNDING_WEBHOOK DEPOSIT). It is not applied to the cancelled order. Create a new order for that amount, which is then paid from the balance, or pay the money out with Claim Pending Funds.
Reconcile
- Orders: Get Order by
orderIdorclientIdis the source of truth for each order:orderStatus,fiatAmount,fiatFee,cryptoAmount,orderPrice,failCodeandfailReason. Use List Orders with a time range for daily totals. It also lists orders not created through the API. - Fiat balance: List Funding Records shows each
DEPOSITandBUY_CRYPTO, for both funding models. List Fiat Flows gives the line-by-line ledger with running balances. - Crypto out: Get Crypto Withdrawal History by
clientId, untilstatusis6(successful),7(failed) or9(cancelled).
Test in the sandbox
- Use
https://api-test.velafi.com. Webhooks are not sent in the sandbox, so pollGET /v2/order/detail. - Fund a test merchant’s balance, or pay a pay-per-order order, with the fiat deposit simulator (
depositAliastargets a virtual account). See Sandbox Testing Tools. - In the sandbox, a
quoteIdlasts 300 seconds, and automatic withdrawal acceptsPOLorTSPL20asnetwork. - The simulators only produce successful deposits. You cannot simulate a returned payment. Test the expiry path by creating a pay-per-order order and not paying it.
Go-live checklist
- Every create request sends a unique
clientId, and timeouts are resolved by looking up theclientIdbefore retrying. - Prefunded flows check the balance and handle the insufficient-balance rejection without retrying the same request in a loop.
- Pay-per-order flows show
paymentInfo, the exact amount and a deadline, and create a new order after70. - Each payer has a virtual account (
depositAlias) if you run pay-per-order for several payers on one currency account. - The
ORDER_WEBHOOKendpoint verifies the signature, returns{"callbackStatus":"SUCCESS"}with HTTP2xx, and deduplicates onorderId+orderStatus. - A scheduled job reconciles open orders, funding records and withdrawals against the API.
- Withdrawal destinations are whitelisted, or automatic withdrawal is enabled and tested with
networkandaddress.