---
title: "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](/platform/settlement-instructions/overview).

## Order types

* **Market order:** executes at the current rate after any required approval.
* **Limit order:** waits until the rate reaches your `target_rate` and any required approval is complete.

## Create an order

Use the [Create order](/api-reference/fx/post-v1-fx-orders) 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](/platform/foreign-exchange/get-exchange-rates#get-all-currency-pair-rates) to confirm a pair is supported before you create an order.

### Market order

```bash title="create a market order request"
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:

```json title="create a market order response"
{
  "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:

```bash title="create a limit order request"
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, by `destination_id`.
* `wallet`: a crypto wallet, by `destination_id`.
* `ssi`: a saved [settlement instruction](/platform/settlement-instructions/overview), 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](/api-reference/fx/get-v1-fx-orders-order-id) using its `order_id`:

```bash title="get an order request"
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](/api-reference/fx/get-v1-fx-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):

```bash title="list orders request"
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](/api-reference/fx/post-v1-fx-orders-order-id-cancel):

```bash title="cancel an order request"
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](/platform/foreign-exchange/approve-or-reject-otc-orders). Otherwise, track it from `pending` through execution and settlement.

