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.

  1. An order that sells 2,000,000 NGN for 1,300 USDC is completed. Nothing is left to do.
  2. An order that sells 500 USDC for 747,750 NGN has been pending since 15:00. Gravv took the 500 USDC and has not delivered the naira yet. Leave it.
  3. 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.

Reference

Was this page helpful?