Exchange currencies
This recipe creates an OTC foreign exchange order, handles the permission-dependent approval path, and tracks the order until it settles or reaches another terminal state.
Before you start, you need a customer ID, a funded source account or wallet, and a destination account, wallet, or settlement instruction. Every POST request requires an Idempotency-Key; reuse a key only for an identical retry.
Flow overview
sequenceDiagram
autonumber
actor Client
participant API as Gravv API
actor Approver as Dashboard approver
participant Settlement as Settlement rail
Client->>API: Create OTC order
alt Caller can approve FX orders
API-->>Client: pending
else Approval is required
API-->>Client: waiting_approval
Approver->>API: Approve or reject in dashboard
alt Order approved
API-->>Client: pending
else Order rejected
API-->>Client: rejected
end
end
API->>Settlement: Execute and settle approved order
loop Until terminal status
Client->>API: Retrieve order
API-->>Client: pending, active, completed, rejected, cancelled, or expired
end
Create a market order to exchange the base currency into the quote currency. A limit order also requires target_rate.
curl --request POST \
--url https://api.gravv.xyz/v1/fx/orders \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: fx-order-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "85034797-3ea1-4ad8-a952-becd67d74acc",
"order_type": "market",
"pair": {
"base": "USD",
"quote": "ZAR"
},
"amount": "1000",
"source_type": "account",
"source_id": "74653c7b-ae84-45ab-8085-2d2493f86d81",
"destination_type": "ssi",
"destination_id": "b23ffd0e-d0fc-432e-acc9-c396194121b3"
}'
{
"data": {
"id": "4994339f-4a19-47ef-a86b-1005eff0a4d0",
"order_id": "OTC-0VA89I",
"order_type": "market",
"pair": {
"base": "USD",
"quote": "ZAR"
},
"amount": "1000.00000000",
"converted_amount": "16242.50000000",
"rate": "16.24250000",
"status": "waiting_approval"
},
"error": null
}
The initial status is permission-dependent. A caller with FX approval authority can receive pending; otherwise the order waits in waiting_approval for a dashboard decision.
When the order is waiting_approval, an authorized user reviews it in the Gravv dashboard. Approval and rejection are human dashboard actions and are not API-key operations. Approval moves the order to pending; rejection moves it to the terminal rejected state.
Retrieve the order using its order_id.
curl --request GET \
--url https://api.gravv.xyz/v1/fx/orders/OTC-0VA89I \
--header 'Api-Key: <API_KEY>'
{
"data": {
"order_id": "OTC-0VA89I",
"status": "completed",
"amount": "1000.00000000",
"converted_amount": "16242.50000000",
"amount_currency": "USD",
"converted_currency": "ZAR"
},
"error": null
}
Poll only when your integration needs an immediate update. Otherwise, reconcile using the order ID and the status returned by the API.
See Foreign Exchange for market and limit orders, supported pairs, cancellation, and status details.