X-Api-Key with trades:create; cancel and replace require
trades:execute. Always send a UUID Idempotency-Key on writes. Matching is
asynchronous. Consume
exchange webhooks or private WebSocket topics for timely changes, and use order
reads for recovery, operator lookups, and periodic reconciliation.
Before You Place an Order
Perform these checks in your own system before sending the request:- Fetch
GET /partner/exchange/marketsand confirm the pair is listed. - Validate
side,order_type,quantity, andpriceagainsttick_size,min_base_lot, andmin_notional. - Confirm available balance with
GET /partner/wallets/balances/overview. Creation does not check balance; an unfunded order is accepted and later reported asrejected. - Generate and store a UUID
Idempotency-Keyand a uniqueclient_order_idfor this exact order intent. - Configure exchange webhooks or private WebSocket topics before submission.
Request Fields
Unknown fields are rejected.
POST_ONLY cancels the order instead of taking
liquidity when it would cross the book.
Create A Limit Order
Limit orders specify the maximum buy price or minimum sell price you are willing to accept.Create A Market Order
Market orders prioritize execution against available liquidity. Estimate the order first when you need a client quote or a slippage preview. The estimate walks the currently visible opposite-side depth and is non-binding.business_bps is your optional client spread (25 bps is 0.25%). For buys it is
added to the estimated average execution price; for sells it is subtracted. The
response returns both Stabyl’s estimated_average_price and your
client_quote_price, plus estimated_slippage_bps, covered quantity, and
sufficient_liquidity. This spread is quote-only: it does not change execution,
Stabyl fees, or the market order submitted afterward.
Submit the market order only after applying your own expiry and risk controls:
Create Response
The response confirms that Stabyl accepted the order request for processing. It does not mean the order is already filled.order_id. Use it for all later reads, cancels, replacements, and reconciliation. The response does not echo the order fields; read the order or wait for exchange.accepted to see them.
List Orders By Status
status (pending, accepted, partially_filled, filled, cancelled, rejected, expired), pair_id, limit (default 50, maximum 100), and offset. An unrecognised status value is ignored rather than rejected. The response contains orders and count for the page; there is no cursor or total. Use list filters for dashboards and background reconciliation. For a single order, prefer the detail endpoint, which also returns the order’s fills.
Get Order Detail
Cancel Order
{ "order_id", "status": "cancelling", "cancelled_at" }. Cancel is accepted only while the order is pending, accepted, or partially_filled; any other status returns 400. It is best effort for open quantity: if part of the order has already executed, the filled portion remains final and only remaining quantity can be cancelled. Confirm the outcome from exchange.cancelled or an order read.
Replace Order
limit orders in accepted or partially_filled status; a pending or market order returns 400. Send at least one of price or quantity. Omitting quantity keeps the remaining unfilled quantity, and an optional client_order_id names the replacement. The response is { "original_order_id", "new_order_id", "status": "replacing", "replaced_at" }. Store new_order_id: the original is cancelled and the replacement continues under the new ID. Always read the returned order and do not assume the original order is still active.
Status Handling
cancelling and replacing appear only in the cancel and replace responses
while the change is being applied; the order itself then moves to cancelled
or is superseded by the replacement.
Retry Rules
Order writes return
400 for an invalid pair, price, quantity, or status
transition, 401, 403, 404 for an unknown or foreign order, 429, and
503. They never return 409. Insufficient balance is not a write-time
failure; it surfaces later as a rejected order.