trigger_price. When it does, Bullionwale books it as a market order at that moment’s price, if your weight allocation still has room for it then. You place it with POST /limit-orders, follow it with GET /limit-orders/{limit_order_id}, list your limits with GET /limit-orders, change it with PATCH /limit-orders/{limit_order_id} and cancel it with DELETE /limit-orders/{limit_order_id}. For a walkthrough, see the Limit orders guide.
Each path sits under the test base path
/api/trading/test/v1 or the production base path /api/trading/v1:
Test limit orders are simulated and never execute: they are checked exactly like real ones, then rest until you cancel them. Production limit orders are real, and production trading is switched off today: every production write answers
403 production_trading_disabled (see Production access requirements). Reads keep working in both environments.
Limit orders are offered per platform. Where they are not offered, every call on this page answers 404.
The limit order object
Both environments return these fields:
Production limit orders add:
Statuses
A production limit order moves
pending → triggered or pending → cancelled. When Bullionwale hedges it, it is confirming first while it is being placed, and again while it is being cancelled. A test limit order is only ever pending or cancelled.
Edit and cancel only a pending limit order. A confirming one answers 409 limit_order_confirming: read it again after a few seconds. A triggered or cancelled one answers 409 limit_order_not_pending.
How a limit order triggers
Production limit orders are checked against the live price every few seconds:
“Your price” is the price you see in Market data, with your account’s pricing applied. When it triggers, the order is booked at that moment’s price, not at
trigger_price: if the price moved past your trigger between two checks, a buy books at the lower price and a sell at the higher one.
Your weight allocation is not reserved while a limit order rests. It is checked when the order triggers, together with the other conditions a market order must meet then: trading on for the symbol and for your account, the quantity rules, and stock. If any of them fails at that moment, the limit order is cancelled, not kept waiting, and cancel_reason says why, for example not enough free limit when the price triggered. Place it again once the reason is resolved. While it rests, blocked_reason warns you in advance when one of these would stop it.
Some conditions only make it wait, without cancelling it: no live or confirmed price for the symbol, a frozen price, or a trading halt. It keeps resting and triggers once the price is live again.
Place a limit order
POST /limit-orders takes an Idempotency-Key header (required: 1 to 64 characters, a new UUID per limit order, reused unchanged on every retry; see Idempotency and safe retries). Keys for limit orders are separate from keys for market orders, and are remembered per account.
Placement runs the same symbol, side, trading-halt, quantity and pricing checks as a market order, except your weight allocation and stock, which are checked when it triggers.
201 Created
400 Bad Request
/api/trading/v1/limit-orders with a live key. What comes back differs:
202 Accepted
409 Conflict
Read one limit order
GET /limit-orders/{limit_order_id} returns one of your limit orders with its current status. One that is not on your account, or not in this environment, answers 404 limit_order_not_found. This example places a test limit order and reads it back:
Python
triggered, read the order it became with GET /orders/{order_id}, using its order_id.
List your limit orders
GET /limit-orders takes status (pending, triggered, cancelled or all, the default), 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 limit orders. status=pending is the resting queue, confirming limit orders included.
In production it lists your account’s limit orders from every channel: the app, the web and the API. source says which were placed through the API, and only those carry your client_order_id. In test it lists your test limit orders.
200 OK
Edit a limit order
PATCH /limit-orders/{limit_order_id} takes a new trigger_price, a new quantity, or both. A body with neither is refused with 422 invalid_request. The new values face the placement’s rules: the price must still wait (400 limit_would_execute), the quantity must meet the quantity rules, and a larger quantity must fit your weight allocation now (400 limit_exceeded; in test, against your test book). It answers the limit order with its new values.
PATCH sets absolute values, so sending the same edit twice leaves the same result. It takes no Idempotency-Key.
200 OK
Cancel a limit order
DELETE /limit-orders/{limit_order_id} cancels a pending limit order and answers it, cancelled. In production:
503 Service Unavailable
cancelled, or the order is booked first and the cancel answers 409 limit_order_not_pending. After a 409, read the limit order: if it is triggered, order_id names the order that was booked.
409 Conflict
Python
Events
Production limit orders send the webhook eventslimit_order.placed (it is resting, after any confirmation), limit_order.triggered (it was booked; the event names the order) and limit_order.cancelled. Test limit orders send none. See the Event catalog.
Common refusals
The full list, with what to do for each, is in the Error reference.