> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bullionwale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orders

> Place market orders for gold and silver, follow their status, and list your order history.

An order is a market buy or sell of one symbol, for a weight. You place it with `POST /orders`, follow it with `GET /orders/{order_id}`, and list your history with `GET /orders`. The API does not close or cancel orders: closing is done by Bullionwale.

| Call | Endpoint | Scope |
| - | - | - |
| [Place an order](#place-an-order) | `POST /orders` | `orders:write` |
| [List orders](#list-your-orders) | `GET /orders` | `orders:read` |
| [One order](#read-one-order) | `GET /orders/{order_id}` | `orders:read` |

Each path sits under the test base path `/api/trading/test/v1` or the production base path `/api/trading/v1`. Test orders are simulated and always `filled`; production orders are **real**. The production examples on this page use a live key and the production paths: check the availability notice on [Production access requirements](/production-access) before you use them.

## The order object

Both environments return these fields:

| Field | Meaning |
| - | - |
| `id` | The order's id (a UUID). Use it with `GET /orders/{order_id}`. |
| `environment` | `test` or `production`. |
| `symbol_code`, `trade_type` | What you sent. |
| `quantity` | The weight, as a string, in `unit`. |
| `unit` | `g` or `kg`: the symbol's measure. |
| `price` | The booked rate per the symbol's quoted measure (for example per 10 grams for gold, per kilogram for silver), in rupees, as a string. |
| `total` | The order's value in rupees, as a string. |
| `status` | See [Order statuses](#order-statuses). |
| `client_order_id` | Your reference, if you sent one. |
| `created_at` | When the order was created, as an ISO 8601 time with its UTC offset. |

Test orders add `deal_label` (`T-<n>`). Production orders add:

| Field | Meaning |
| - | - |
| `deal_no` | Bullionwale's deal number. |
| `status_detail` | Bullionwale's internal status name, for support conversations. Branch on `status`, not on this. |
| `source` | The channel the order came from: `api` for yours, or `web`, `mobile` and others for orders placed elsewhere. |
| `close_price` | The closing rate, once the order is closed. Otherwise `null`. |
| `realized_pnl` | The realized profit or loss in rupees, once the order is closed. Otherwise `null`. |
| `closed_at` | When the order was closed. Otherwise `null`. |

## Order statuses

A **test** order is always `filled`.

A **production** order has one of these statuses:

| `status` | Meaning |
| - | - |
| `pending` | Accepted, waiting for Bullionwale's hedge to confirm. Not a deal yet. |
| `open` | Booked at `price`. |
| `closing` | Bullionwale is closing it. |
| `closed` | Closed. `close_price`, `realized_pnl` and `closed_at` are set. |
| `rejected` | The hedge refused it. Nothing was booked. |
| `deleted` | Bullionwale removed it. |

A production order normally moves `pending` → `open` → `closing` → `closed`, or `pending` → `rejected`.

## Place an order

`POST /orders` places a market order at the current price. The `Idempotency-Key` header is required: 1 to 64 characters, a new UUID per order, reused unchanged on every retry of that order (see [Idempotency and safe retries](/idempotency)).

| Field | Type | Required | Meaning |
| - | - | - | - |
| `symbol_code` | string | yes | The symbol to trade, for example `GOLD_TRADE_999`. Up to 32 characters. |
| `trade_type` | string | yes | `buy` or `sell`. |
| `quantity` | number | yes | A **weight** in the symbol's measure: grams for gram-quoted symbols, kilograms for kilogram-quoted ones. Greater than 0, at most 4 decimal places. |
| `expected_price` | number | no | The price you showed or expect. If the live price has moved beyond Bullionwale's tolerance from it, the order is refused with `409 price_moved` instead of being booked. |
| `client_order_id` | string | no | Your own reference, up to 64 characters, echoed back on the order. Always send one: it is how you find an order whose response you never received. |

<CodeGroup>
  ```bash curl theme={null}
  curl -s -X POST https://api.bullionwale.com/api/trading/test/v1/orders \
    -H "X-API-Key: $BULLIONWALE_API_KEY" \
    -H "Idempotency-Key: 6a2e9c14-7b3d-4f58-a0c6-1d8e5b3f7a29" \
    -H "Content-Type: application/json" \
    -d '{"symbol_code": "GOLD_TRADE_999", "trade_type": "buy", "quantity": 10, "client_order_id": "bot-43"}'
  ```

  ```python Python theme={null}
  import os
  import uuid
  import requests

  BASE = "https://api.bullionwale.com/api/trading/test/v1"
  HEADERS = {"X-API-Key": os.environ["BULLIONWALE_API_KEY"]}

  idempotency_key = str(uuid.uuid4())  # store it with the order; reuse it on every retry
  r = requests.post(
      f"{BASE}/orders",
      headers={**HEADERS, "Idempotency-Key": idempotency_key},
      json={"symbol_code": "GOLD_TRADE_999", "trade_type": "buy",
            "quantity": 10, "client_order_id": "bot-43"},
      timeout=10,
  )
  print(r.status_code, r.json())
  ```
</CodeGroup>

```json 201 Created theme={null}
{
  "id": "b7d1e0f4-2c9a-4f63-8e1d-0a5c3b2f9e71",
  "deal_label": "T-12",
  "environment": "test",
  "symbol_code": "GOLD_TRADE_999",
  "trade_type": "buy",
  "quantity": "10.0000",
  "unit": "g",
  "price": "141250.00",
  "total": "141250.00",
  "status": "filled",
  "client_order_id": "bot-43",
  "created_at": "2026-10-14T15:01:05.120000+05:30"
}
```

The production request is the same, on `/api/trading/v1/orders` with a live key. What comes back first differs:

| Answer | Test | Production |
| - | - | - |
| `201` | The order, `filled`. | Booked: the order is `open`. |
| `202` | Never. | Accepted and `pending` while the hedge confirms it. [Follow it](#follow-a-pending-order). |
| `200` | A replay of an earlier request with the same `Idempotency-Key`. | The same. |
| `409 order_rejected` | Never. | The hedge refused it. Nothing was booked. |
| `503 booking_…` | Never. | The booking failed; retry with the same key (see [Outcomes after a failure](/idempotency#outcomes-after-a-failure)). |

Every other refusal (an unknown symbol, a halted market, a moved price, your weight allocation) is the same in both environments. See [Common refusals](#common-refusals).

## Read one order

<CodeGroup>
  ```bash curl theme={null}
  curl -s https://api.bullionwale.com/api/trading/v1/orders/3f0c6a52-8a3e-4b8e-9a52-6d2f1c7e9b10 \
    -H "X-API-Key: $BULLIONWALE_API_KEY"
  ```

  ```python Python theme={null}
  import os
  import requests

  BASE = "https://api.bullionwale.com/api/trading/v1"
  HEADERS = {"X-API-Key": os.environ["BULLIONWALE_API_KEY"]}

  order_id = "3f0c6a52-8a3e-4b8e-9a52-6d2f1c7e9b10"
  r = requests.get(f"{BASE}/orders/{order_id}", headers=HEADERS, timeout=10)
  print(r.status_code, r.json()["status"])
  ```
</CodeGroup>

```json 200 OK theme={null}
{
  "id": "3f0c6a52-8a3e-4b8e-9a52-6d2f1c7e9b10",
  "deal_no": 240117,
  "environment": "production",
  "symbol_code": "GOLD_TRADE_999",
  "trade_type": "buy",
  "quantity": "10",
  "unit": "g",
  "price": "141250.00",
  "total": "141250.00",
  "status": "open",
  "status_detail": "fixed",
  "source": "api",
  "client_order_id": "bot-42",
  "close_price": null,
  "realized_pnl": null,
  "created_at": "2026-10-14T15:01:05.120000+05:30",
  "closed_at": null
}
```

An order that is not on your account answers `404 order_not_found`.

## Follow a pending order

In production, `POST /orders` can answer `202 Accepted` with the order `pending` while Bullionwale's hedge confirms it. Then:

1. Call `GET /orders/{order_id}` every 1 to 2 seconds.
2. Stop when `status` is no longer `pending`: `open` means booked, `rejected` means nothing was booked, and, rarely, `deleted`.
3. Give up polling after about 30 seconds and check again later. Reads do not use your order budget.

**Never place the order again with a new `Idempotency-Key`** while you are waiting: that would be a second order. See [Idempotency and safe retries](/idempotency).

## List your orders

`GET /orders` takes `limit` (1 to 200, default 50), `offset`, `symbol_code`, `trade_type` and `since` (ISO 8601; a time without a zone is UTC), and returns `items` newest first plus `total`, the number of matching orders.

In production it also takes `status`: `pending`, `open`, `closing`, `closed`, `rejected`, `deleted` or `all` (the default). `all` leaves out deleted orders; ask for `status=deleted` to list those.

<CodeGroup>
  ```bash curl theme={null}
  curl -s "https://api.bullionwale.com/api/trading/v1/orders?status=open&limit=1" \
    -H "X-API-Key: $BULLIONWALE_API_KEY"
  ```

  ```python Python theme={null}
  import os
  import requests

  BASE = "https://api.bullionwale.com/api/trading/v1"
  HEADERS = {"X-API-Key": os.environ["BULLIONWALE_API_KEY"]}

  r = requests.get(f"{BASE}/orders", headers=HEADERS,
                   params={"status": "open", "limit": 1}, timeout=10)
  page = r.json()
  print(r.status_code, page["total"], [o["deal_no"] for o in page["items"]])
  ```
</CodeGroup>

```json 200 OK theme={null}
{
  "items": [
    {
      "id": "3f0c6a52-8a3e-4b8e-9a52-6d2f1c7e9b10",
      "deal_no": 240117,
      "environment": "production",
      "symbol_code": "GOLD_TRADE_999",
      "trade_type": "buy",
      "quantity": "10",
      "unit": "g",
      "price": "141250.00",
      "total": "141250.00",
      "status": "open",
      "status_detail": "fixed",
      "source": "api",
      "client_order_id": "bot-42",
      "close_price": null,
      "realized_pnl": null,
      "created_at": "2026-10-14T15:01:05.120000+05:30",
      "closed_at": null
    }
  ],
  "total": 3
}
```

### Which orders you see

In production, `GET /orders` returns your account's orders from **every** channel: the app, the web and the API. `source` says which. Orders you placed through the API also carry your `client_order_id`.

One exception: a `pending` or `rejected` order appears only if it was **placed through the API**. An order placed in the app that is still being confirmed, or that the hedge refused, is not shown in the app either, so the API answers `404 order_not_found` for it. It appears once it is confirmed, as `open`.

The test `GET /orders` lists only your test orders.

## Common refusals

| Code | Status | Meaning |
| - | - | - |
| `idempotency_key_required` | 400 | `POST /orders` without an `Idempotency-Key` header. |
| `idempotency_key_reused` | 422 | The `Idempotency-Key` was used for a different order body. Nothing was booked. |
| `insufficient_scope` | 403 | Placing needs `orders:write`; reading needs `orders:read`. |
| `unknown_symbol` | 404 | No such symbol. |
| `limit_exceeded` | 400 | The order would take your open position past your weight allocation. See [Positions](/api-reference/positions/overview#how-the-allocation-works). |
| `price_moved` | 409 | The live price moved beyond tolerance from your `expected_price`. Nothing was booked. |
| `order_not_found` | 404 | No such order on your account (or one the API does not show). |
| `production_trading_disabled` | 403 | Production only: production trading is not available to you right now. |

The full list, with what to do for each, is in [Errors](/errors#error-codes).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.