Place an OTC order
An OTC order exchanges one currency for another and settles the proceeds to an account, wallet, or saved settlement instruction. Its initial status depends on the caller's permissions: pending when the caller can approve FX orders, or waiting_approval when a dashboard decision is required.
📘 Order vs spot trade
Use a market order for the current available rate. Use a limit order when execution should wait for a target rate. Either order can settle to an account, wallet, or saved settlement instruction.
Order types
- Market order: executes at the current rate after any required approval.
- Limit order: waits until the rate reaches your
target_rateand any required approval is complete.
Create an order
Use the Create order endpoint. Each order requires the following fields:
| Field | Type | Description |
|---|---|---|
order_type |
string | market or limit |
pair |
object | the currency pair, as { "base": "USD", "quote": "NGN" } |
amount |
string | amount of the base currency to exchange, greater than zero |
target_rate |
string | required for limit orders; the rate at which the order should execute |
side |
string | optional, buy or sell. Defaults to sell |
source_type |
string | optional, account or wallet: where the funds come from |
source_id |
string | optional, the account or wallet ID |
destination_type |
string | optional, account, wallet, or ssi: where the proceeds go |
destination_id |
string | optional, the account, wallet, or settlement instruction ID |
Use Get all currency pair rates to confirm a pair is supported before you create an order.
Market order
curl --request POST \
--url https://api.gravv.xyz/v1/fx/orders \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: 979879887678789_attempt_1' \
--header 'content-type: application/json' \
--data '
{
"order_type": "market",
"pair": { "base": "USD", "quote": "NGN" },
"amount": "1000",
"source_type": "account",
"source_id": "5d9e677f-f071-4881-a861-7cdcebacd9d5",
"destination_type": "ssi",
"destination_id": "a14ec356-f33d-4384-ba68-4d9bfa19765b"
}
'
The order returns its order_id and its permission-dependent initial status:
{
"data": {
"id": "8f1d2c0e-2b7a-4f3e-9c1a-7d2b6e4f9a01",
"order_id": "OTC-1737031200-AB12",
"order_type": "market",
"side": "sell",
"pair": { "base": "USD", "quote": "NGN" },
"amount": "1000",
"amount_currency": "USD",
"converted_amount": "1550000",
"converted_currency": "NGN",
"rate": "1550",
"status": "waiting_approval",
"destination_type": "ssi",
"destination_id": "a14ec356-f33d-4384-ba68-4d9bfa19765b",
"created_at": "2026-06-20T10:29:16.000Z",
"expires_at": "2026-06-20T10:44:16.000Z"
},
"error": null
}
Limit order
A limit order adds a target_rate. It executes once the rate reaches that value, after approval:
curl --request POST \
--url https://api.gravv.xyz/v1/fx/orders \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: 979879887678789_attempt_2' \
--header 'content-type: application/json' \
--data '
{
"order_type": "limit",
"pair": { "base": "USD", "quote": "NGN" },
"amount": "1000",
"target_rate": "1600",
"source_type": "account",
"source_id": "5d9e677f-f071-4881-a861-7cdcebacd9d5",
"destination_type": "account",
"destination_id": "c2f9f2d0-1234-4abc-9def-0123456789ab"
}
'
Where proceeds settle
Set destination_type to control where the converted funds go:
account: an internal account, bydestination_id.wallet: a crypto wallet, bydestination_id.ssi: a saved settlement instruction, by its ID. Use this to settle to an external bank account or wallet you've saved ahead of time.
Order status
An order moves through these statuses:
| Status | Description |
|---|---|
waiting_approval |
waiting for an authorized dashboard user to approve or reject |
pending |
accepted and queued for execution |
active |
funds are charged and the order is executing |
completed |
executed and settled |
rejected |
a reviewer rejected the order |
cancelled |
cancelled before execution |
expired |
not approved before it expired |
Track an order
Check a single order with Get order using its order_id:
curl --request GET \
--url https://api.gravv.xyz/v1/fx/orders/OTC-1737031200-AB12 \
--header 'Api-Key: <API_KEY>'
List your orders with List orders. You can filter with status, order_type, side, search, start_date, and end_date, and page with page and items_per_page (default 20, max 100):
curl --request GET \
--url 'https://api.gravv.xyz/v1/fx/orders?status=waiting_approval&items_per_page=20' \
--header 'Api-Key: <API_KEY>'
Cancel an order
Cancel an order that hasn't executed with Cancel order:
curl --request POST \
--url https://api.gravv.xyz/v1/fx/orders/OTC-1737031200-AB12/cancel \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: fx-cancel-<UUID>'
Next step
If the order returns waiting_approval, see Approve or reject OTC orders. Otherwise, track it from pending through execution and settlement.