---
title: "Follow, list and cancel orders"
description: "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.

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url 'https://api.gravv.xyz/v1/fx/orders?status=pending&items_per_page=100&page=1' \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

### 2. Read one

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url https://api.gravv.xyz/v1/fx/orders/6b65a6a4-8b81-48f6-b38a-088ca65ed389 \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

### 3. Orders waiting for a Dashboard decision

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url 'https://api.gravv.xyz/v1/fx/orders/pending-approvals?items_per_page=20' \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

```json title="Response"
{
  "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

<CodeGroup>
```bash title="cURL"
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'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

```json title="Response"
{
  "data": {
    "id": "451b4cf3-6123-4df7-b656-af7229d4beef",
    "status": "cancelled"
  },
  "error": null
}
```

<Warning>
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.
</Warning>

## 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

- [Place an OTC order](/platform/foreign-exchange/place-an-otc-order#track-an-order)
- [Approve or reject OTC orders](/platform/foreign-exchange/approve-or-reject-otc-orders)
