Skip to main content
POST
Create an Off-Ramp Order
The crypto-to-fiat off-ramp lets your users convert cryptocurrency into local fiat, which is then paid out to the beneficiary identified by userPaymentId. Before calling this endpoint, ensure the target beneficiary has been registered via POST /v2/payments and has status: 1 (valid). Specify the amount in either crypto (cryptoAmount) or fiat (fiatAmount); if you send both, fiatAmount takes precedence. To lock the rate, pass a quoteId; without one, the order is priced at the current rate when it is created. The crypto is taken from the merchant’s crypto balance (see Funding the order).

Endpoint

Use https://api-test.velafi.com/v2/order/crypto_to_fiat for sandbox testing.

Request Headers

Request Body Parameters

string
required
Full country name for the off-ramp (e.g., "Mexico", "Argentina"). Must match the country associated with the chosen userPaymentId.
string
required
Ticker symbol of the cryptocurrency to convert (e.g., "USDT", "USDC").
string
required
ISO 4217 fiat currency code the beneficiary will receive (e.g., "MXN", "ARS", "BRL").
integer
required
The numeric ID of the beneficiary (user payment method) to receive the fiat payout. Retrieve this from GET /v2/payments.
string
Your own order reference ID, up to 40 characters. It must be unique across all fiat_to_crypto and crypto_to_fiat orders on your account; a second create request with the same clientId is rejected. It is returned in Get Order responses and can be used instead of orderId to look the order up. See Idempotency and retries.
integer
required
Numeric ID of the merchant the order belongs to. The crypto is debited from this merchant’s balance. Requests without a valid merchantId are rejected.
decimal
Amount of cryptocurrency to convert (e.g., 1000.00). Ignored when a positive fiatAmount is also sent.
decimal
Amount of fiat currency the beneficiary should receive (e.g., 21000.00). Provide fiatAmount or cryptoAmount; if you send both, fiatAmount takes precedence.
string
Optional free-text note attached to the order.
string
Quote ID from the Quote API to lock in a specific exchange rate. Omit to use the live spot rate.

Response Fields

integer
Response status code. 200 indicates success.
string
Human-readable response message.
object
Order result object.

Example

Funding the order

The crypto for an off-ramp order comes from the merchant’s crypto balance for the crypto and merchantId in the request. Check the balance with Crypto Balance and top it up through the merchant’s deposit address.
  • Balance covers the order: VelaFi debits the crypto from the balance when it creates the order.
  • Balance is too low: the request is rejected with an insufficient-balance error, unless post-funded off-ramp is enabled for your account (enablement can differ by fiat currency).
With post-funded off-ramp enabled, an underfunded order waits in status: 32 (awaiting crypto deposit). If the order first needs compliance review (status: 10 or 11), it moves to 32 once approved. While it is in 32, order detail returns orderExpireTimestamp, the funding deadline as a Unix timestamp in seconds. VelaFi checks the merchant’s balance every minute; when several orders are waiting on the same merchant and crypto, the balance is applied to them oldest first. Once the balance covers an order, VelaFi debits the crypto and the order moves to status: 40, or 31 if supporting documents are required. If the deadline passes first, the order is canceled (status: 70).
For a crypto_to_fiat order in status: 50 (paid), POST /v2/order/confirm completes the order (status: 60).

Idempotency and retries

Use clientId to make order creation safe to retry.
  • clientId is optional. When you send it, it must be at most 40 characters and unique on your account across all fiat_to_crypto and crypto_to_fiat orders, for all of your merchants.
  • A create request that reuses an existing clientId is rejected with a repeated-submission error, and no new order is created. The response does not return the original order; look it up instead.
  • A clientId stays bound to its order permanently, including after the order is canceled. Use a new clientId for a new order.
  • Look up an order by clientId with GET /v2/order/detail?orderType=crypto_to_fiat&clientId={clientId}.
If a create request times out or returns no response:
  1. Call GET /v2/order/detail with the same orderType and clientId.
  2. If the order is found, the original request succeeded. Do not create it again.
  3. If it is not found, retry with the same clientId. If the first request did create the order in the meantime, the retry is rejected as a duplicate instead of creating a second order.
A quoteId can be consumed by a create request that is then rejected. Request a new quote before you retry.