Follow, list and cancel orders
Watch open FX orders, know what each status means for the money, and cancel only an order waiting for approval.
Use this recipe to watch open FX orders, read what each status means for the money, and cancel only an order that is waiting for approval.
Who it is for. An operations team that watches open conversions every day and must answer "where is my money?" for each one.
Status. Available.
Money example
At 17:00 your operations screen shows three orders.
- An order that sells 2,000,000 NGN for 1,300 USDC is
completed. Nothing is left to do. - An order that sells 500 USDC for 747,750 NGN has been
pendingsince 15:00. Gravv took the 500 USDC and has not delivered the naira yet. Leave it. - An order to sell 100,000 NGN for USDC, placed by a junior user in the Dashboard, is
waiting_approval. Gravv has taken nothing yet. An approver decides in the Dashboard, or you cancel it.
Before you start
A scoped key needs fx:order_cancel to cancel, and fx:order_approve to list orders waiting for approval. Reading needs no permission.
Find out what is required
GET /v1/fx/orders/{order_id} is the source of truth.
| Status | Meaning | Money | Final |
|---|---|---|---|
waiting_approval |
Placed in the Dashboard by a user without approval rights | Not taken yet | No |
pending |
An API-key order, or an approved one | Sell side taken or being taken. Bought side not delivered yet | No |
completed |
The bought currency was delivered | Done | Yes |
cancelled |
Cancelled while waiting for approval, or the debit failed and nothing moved | Nothing taken | Yes |
rejected |
Declined by an approver or by Gravv | Nothing delivered | Yes |
Steps
1. List open orders
The list returns the newest orders first. status is the only filter that works, and it must be lower case, so status=PENDING returns nothing. The list ignores date, side and search filters.
curl --request GET \
--url 'https://api.gravv.xyz/v1/fx/orders?status=pending&items_per_page=100&page=1' \
--header 'Api-Key: <API_KEY>'
const response = await fetch("https://api.gravv.xyz/v1/fx/orders?status=pending&items_per_page=100&page=1", {
method: "GET",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
},
});
console.log(response.status, await response.json());
import os
import requests
response = requests.get(
"https://api.gravv.xyz/v1/fx/orders?status=pending&items_per_page=100&page=1",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
},
)
print(response.status_code, response.json())
2. Read one
curl --request GET \
--url https://api.gravv.xyz/v1/fx/orders/6b65a6a4-8b81-48f6-b38a-088ca65ed389 \
--header 'Api-Key: <API_KEY>'
const response = await fetch("https://api.gravv.xyz/v1/fx/orders/6b65a6a4-8b81-48f6-b38a-088ca65ed389", {
method: "GET",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
},
});
console.log(response.status, await response.json());
import os
import requests
response = requests.get(
"https://api.gravv.xyz/v1/fx/orders/6b65a6a4-8b81-48f6-b38a-088ca65ed389",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
},
)
print(response.status_code, response.json())
3. Orders waiting for a Dashboard decision
curl --request GET \
--url 'https://api.gravv.xyz/v1/fx/orders/pending-approvals?items_per_page=20' \
--header 'Api-Key: <API_KEY>'
const response = await fetch("https://api.gravv.xyz/v1/fx/orders/pending-approvals?items_per_page=20", {
method: "GET",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
},
});
console.log(response.status, await response.json());
import os
import requests
response = requests.get(
"https://api.gravv.xyz/v1/fx/orders/pending-approvals?items_per_page=20",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
},
)
print(response.status_code, response.json())
{
"data": {
"items": [
{
"id": "451b4cf3-6123-4df7-b656-af7229d4beef",
"quote_id": "GRVOTC_0F1E2D",
"status": "waiting_approval",
"from_currency": "NGN",
"to_currency": "USDC",
"pair_code": "NGN_USDC",
"rate": "0.00065",
"source_amount": "100000",
"destination_amount": "65",
"order_type": "market",
"created_at": "2026-10-13T16:40:00Z"
}
],
"items_per_page": 20,
"page": 1,
"total_items": 1,
"total_pages": 1
},
"error": null
}
Orders you place with an API key never appear here.
4. Cancel only a waiting_approval order
curl --request POST \
--url https://api.gravv.xyz/v1/fx/orders/451b4cf3-6123-4df7-b656-af7229d4beef/cancel \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: 5b0ea969-a406-442d-b2dd-9c4f2a486f33'
const response = await fetch("https://api.gravv.xyz/v1/fx/orders/451b4cf3-6123-4df7-b656-af7229d4beef/cancel", {
method: "POST",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Idempotency-Key": "5b0ea969-a406-442d-b2dd-9c4f2a486f33",
},
});
console.log(response.status, await response.json());
import os
import requests
response = requests.post(
"https://api.gravv.xyz/v1/fx/orders/451b4cf3-6123-4df7-b656-af7229d4beef/cancel",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Idempotency-Key": "5b0ea969-a406-442d-b2dd-9c4f2a486f33",
},
)
print(response.status_code, response.json())
{
"data": {
"id": "451b4cf3-6123-4df7-b656-af7229d4beef",
"status": "cancelled"
},
"error": null
}
Do not cancel a pending order. Gravv has taken its sell side, or is taking it. While the debit runs, the API refuses the cancel with order source debit is still in flight. Once the debit has finished, the API accepts a cancel, but the cancel does not return the money. Contact support instead.
What can go wrong
| Response | Why | Fix |
|---|---|---|
400 order not found |
The id is unknown, belongs to another business, or is not a UUID | Use the order_id from your create call or the list |
400 order_id is required |
The path segment is empty | Add the id |
400 transaction not found on cancel |
The id on the cancel route is unknown | Check the id |
400 order cannot be cancelled in status: completed |
The order is already final, so there is nothing to cancel | No action is needed |
400 order source debit is still in flight |
The debit is running | Do not cancel. Wait for completed |
400 caller is not permitted to approve or reject orders |
The scoped key lacks fx:order_approve |
Use a key with that permission, or the Dashboard |
| Date filters return everything | The list ignores them | Filter by status, and filter dates on created_at yourself |
Webhooks you will receive
Gravv sends no webhooks for FX orders. Poll the order.
Testing in sandbox
Listing and reading work on sandbox data. You can create a waiting_approval order only from the Dashboard. You cannot place an API-key order until your sandbox business has an OTC rate.