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

# Rate limits, errors and troubleshooting

> The error format, every error code, the rate limits, and what to do when a call fails.

## The error format

Every refusal is an HTTP status and a JSON body like this:

```json theme={null}
{
  "detail": {
    "code": "limit_exceeded",
    "message": "Exceeds your gold limit — 40.0000 g free of 1000.0000 g."
  }
}
```

* **Branch on `detail.code`**, never on `message`. Codes are stable; messages are for people and may change.
* Some codes add fields to `detail`, listed in the table below: `reason`, `order_id`, `order` or `errors`.
* Some answers carry a `Retry-After` header: the number of seconds to wait before retrying.
* If you meet a code that is not listed here, handle it by its HTTP status: retry `429` and `503` later with the same `Idempotency-Key`, and treat other `4xx` as a refusal.

## Rate limits

| Budget | Default | Counts |
| - | - | - |
| Reads | 300 per minute, per key | Every `GET`. |
| Orders, per key | 60 per minute and 10 per 10 seconds | Every `POST /orders`, replays included. |
| Orders, per account | 60 per minute | Production only. Every `POST /orders`, replays included, from all of the account's keys together, so a rotation overlap does not double it. |
| Failed authentications | 20 per minute, per source address | Every call refused with a `401`. |

These are the defaults; Bullionwale's limits may differ. Over a budget, the answer is `429` with a `Retry-After` header:

* `rate_limited`: the key's budget or, for production orders, the account's budget is used up.
* `auth_throttled`: too many failed authentications came from your address. Until it cools down, calls from that address are refused **even with a good key**, so fix a misconfigured key before it locks out your other systems.

Wait `Retry-After` seconds, then retry. For an order, retry with the **same** `Idempotency-Key`.

If order rate limiting is temporarily unavailable, orders are refused with `503 rate_limiter_unavailable` and `Retry-After`, and no order is placed. Reads keep working.

## Error codes

"Env." says where a code can occur: **both** environments, or **prod** (production only).

| Code | Status | Env. | Meaning | What to do |
| - | - | - | - | - |
| `missing_credential` | 401 | both | No `X-API-Key` header. | Send the key in `X-API-Key`. |
| `malformed_credential` | 401 | both | The value is not shaped like an API key. | Check that the whole key was copied, with no spaces or quotes. |
| `wrong_tenant` | 401 | both | The key belongs to a different broker. | Use a key Bullionwale issued for your account. |
| `wrong_environment` | 401 | both | A test key on a production path, or a live key on a test path. | Match the key to the base path. |
| `invalid_credential` | 401 | both | Unknown key or wrong secret. | Check the key; ask for a new one if needed. |
| `credential_revoked` | 401 | both | The key was revoked. | Ask for a new key. |
| `credential_rotated` | 401 | both | The key was replaced and its overlap ended. | Use the new key. |
| `credential_expired` | 401 | both | The key expired. | Ask for a rotation. |
| `api_access_disabled` | 403 | both | API access is off for your account. | Contact Bullionwale. |
| `account_inactive` | 403 | both | Your account is not active. | Contact Bullionwale. |
| `insufficient_scope` | 403 | both | The key lacks the scope this call needs. | Use a key with the scope, or ask for it. See [Scopes](/getting-access#scopes). |
| `production_trading_disabled` | 403 | prod | Production trading is not available to you right now. `detail.reason` is `deploy`, `global` or `account`. | See [Production access](/production-access#when-production-orders-are-refused). |
| `production_prerequisites_unmet` | 503 | prod | Production trading is paused by Bullionwale. Nothing was booked. | Retry later. Nothing to change on your side. |
| `auth_throttled` | 429 | both | Too many failed authentications from your address. | Wait `Retry-After`; fix the failing key. |
| `rate_limited` | 429 | both | A rate budget is used up. | Wait `Retry-After`; retry with the same `Idempotency-Key`. |
| `rate_limiter_unavailable` | 503 | both | Order rate limiting is temporarily unavailable, so orders are refused. Reads keep working. | Wait `Retry-After`; retry with the same `Idempotency-Key`. |
| `invalid_request` | 422 | both | The body or a parameter is invalid. `detail.errors` lists each problem and its location. | Fix the request. |
| `idempotency_key_required` | 400 | both | `POST /orders` without an `Idempotency-Key` header. | Send one. |
| `idempotency_key_reused` | 422 | both | This `Idempotency-Key` was used for a different order body. Nothing was booked. | Use a new key for a new order; check your records. |
| `order_not_found` | 404 | both | No such order on your account (or one the API does not show). | Check the id. See [Which orders you see](/orders-and-positions#which-orders-you-see). |
| `order_rejected` | 409 | prod | The hedge refused the order. Nothing was booked. `detail.order_id` and `detail.order` show it. | Decide whether to place a new order with a new key. |
| `unknown_symbol` | 404 | both | No such symbol. | Check `symbol_code`. |
| `symbol_not_trading` | 400 | both | Trading is off for this symbol. | Try later or another symbol. |
| `invalid_side` | 400 | both | `trade_type` is not `buy` or `sell`. | Fix the request. |
| `side_not_offered` | 403 | both | Bullionwale does not offer this side for market orders. | Contact Bullionwale. |
| `rates_not_ready` | 503 | both | Rates are not loaded yet. | Retry shortly with the same key. |
| `no_live_price` | 400 | both | The symbol has no live price right now. | Try later. |
| `unpriced` | 400 | both | The symbol could not be priced. | Try later. |
| `stale_rate` | 503 | both | The rate is stale. | Retry shortly with the same key. |
| `trading_halted` | 403 | both | Bullionwale has halted trading. | Try later. |
| `symbol_frozen` | 400 | both | The symbol's price feed is frozen. | Try later. |
| `quantity_rule` | 400 | both | The quantity breaks the symbol's size rule. | Change the quantity. |
| `tradeability_unverified` | 503 | prod | Whether the symbol can be traded could not be checked. | Retry shortly with the same key. |
| `symbol_unavailable` | 503 | prod | The symbol is unavailable. | Retry later with the same key. |
| `group_trading_disabled` | 403 | both | Trading is off for your account's trading group. | Contact Bullionwale. |
| `group_quantity_rule` | 400 | both | The quantity breaks your trading group's size terms. | Change the quantity. |
| `pricing_unavailable` | 503 | both | Your price could not be computed. | Retry shortly with the same key. |
| `limit_exceeded` | 400 | both | The order would take your open position in that metal past your weight allocation. | Reduce the quantity or your position. See [Positions](/orders-and-positions#positions-and-your-weight-allocation). |
| `out_of_stock` | 400 | prod | Not enough stock for this buy. | Reduce the quantity or try later. |
| `price_moved` | 409 | both | The live price moved beyond Bullionwale's tolerance from your `expected_price`. Nothing was booked. | Check the new price and send a new order with a new key. |
| `booking_conflict` | 409 | prod | Another booking on your account conflicted with this one. | Retry with the same `Idempotency-Key`. |
| `booking_unavailable` | 503 | prod | The order could not be recorded, so nothing was booked. | Retry with the same key. |
| `booking_busy` | 503 | prod | The booking waited too long behind your account's other bookings, so nothing was booked. | Wait `Retry-After`; retry with the same key. |
| `booking_not_completed` | 503 | prod | The booking failed and no booked order was found: nothing was booked yet. | Wait `Retry-After`; retry with the same key for the definitive answer. See [Outcomes after a failure](/idempotency#outcomes-after-a-failure). |
| `booking_outcome_unknown` | 503 | prod | The booking failed and its outcome could not be read. | Wait `Retry-After`; retry with the same key to get it. |

## Troubleshooting

<AccordionGroup>
  <Accordion title="Every call answers 404, with no code in the body">
    Check the host and the path: the API is served at `https://api.bullionwale.com` under `/api/trading/test/v1` and `/api/trading/v1`. A `404` that carries a `detail.code` (`order_not_found`, `unknown_symbol`) is a normal refusal.
  </Accordion>

  <Accordion title="401 wrong_environment">
    A `bwk_test.` key works only under `/api/trading/test/v1`, and a `bwk_live.` key only under `/api/trading/v1`. Check both the base path and the key your program loaded.
  </Accordion>

  <Accordion title="401 on a key that worked yesterday">
    The code says why: `credential_rotated` (use the new key), `credential_expired` (ask for a rotation) or `credential_revoked` (ask for a new key). See [Rotation, expiry and revocation](/credentials).
  </Accordion>

  <Accordion title="429 auth_throttled, even with a good key">
    Something on your network is sending a bad key repeatedly. Calls from that address are refused until the throttle cools down. Find and fix the misconfigured system, then wait `Retry-After`.
  </Accordion>

  <Accordion title="403 production_trading_disabled">
    Production trading is not available to your account right now. Check `production_trading_available` from `GET /me`, and see [When production orders are refused](/production-access#when-production-orders-are-refused).
  </Accordion>

  <Accordion title="A POST /orders timed out">
    Do not send a new order. Retry with the **same** `Idempotency-Key` and body, or look the order up first. See [Recovering an order](/idempotency#recovering-an-order-whose-outcome-you-do-not-know).
  </Accordion>

  <Accordion title="400 limit_exceeded although I have no open orders">
    Check `GET /positions`: `free` is what you can still add in that metal. On the test path the position is your test book. A trade that reduces your position is always allowed.
  </Accordion>

  <Accordion title="An order placed in the app is missing from GET /orders">
    App orders that are still being confirmed, or that were refused, are not shown until they are confirmed. See [Which orders you see](/orders-and-positions#which-orders-you-see).
  </Accordion>
</AccordionGroup>

When you contact Bullionwale about a failed call, include the time, the path, the HTTP status, `detail.code`, your `client_order_id` and the key id from `GET /me`. Never send the key's secret.


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