Skip to Content
APITellimused

Orders

All order endpoints require authentication. See Authentication.

Rate limit: v1-auth: 120 req / 60 s per IP

Sell-order inversion. Internally, a YES sell at price P is stored as a NO buy at price 100 - P. The API always returns orders in the user-facing form you submitted: side and price reflect what you intended, not what is stored.


GET /api/v1/orders

Lists your orders. Up to 200 orders are returned per call (no pagination cursor; use status to narrow the result).

Auth: Required

Query parameters

ParamTypeDefaultDescription
marketIdUUIDFilter to a specific market
statusstring"open""open" returns scheduled + open + partially_filled; "scheduled" returns only live-delay orders; "filled" returns fully filled; "cancelled" returns cancelled; "all" returns all statuses

Response

{ "data": [ { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "marketTitle": "Will Reform Party win the most seats?", "side": "yes", "price": 55, "quantity": 100, "filledQuantity": 40, "status": "partially_filled", "orderType": "buy", "cancelReason": null, "expiresAt": null, "releaseAt": null, "releaseInMs": null, "budgetCents": null, "createdAt": "2026-01-10T09:00:00.000Z", "sharesAhead": 230 } ], "meta": { "pageSize": 1 } }
FieldTypeDescription
idUUID stringOrder identifier
userIdUUID stringYour user id
marketIdUUID stringMarket the order is on
marketTitlestringMarket title (for display)
side"yes" | "no"Side you are buying or selling
priceintegerYour order price (1–99) in user-facing form
quantityintegerTotal shares ordered
filledQuantityintegerShares already matched
statusstringscheduled | open | partially_filled | filled | cancelled
orderType"buy" | "sell"Order type
cancelReasonstring | nullWhy it was cancelled; null if not cancelled
expiresAtISO 8601 | nullExpiry time; null = Good Until Cancelled
releaseAtISO 8601 | nullWhen a scheduled live order becomes eligible for matching; null for orders that were never scheduled
releaseInMsinteger | nullRemaining live delay computed by the server. Use this duration for countdowns instead of subtracting client wall-clock time from releaseAt
budgetCentsinteger | nullPersisted budget for a scheduled budget buy; null for quantity orders and after release
createdAtISO 8601When the order was placed
sharesAheadintegerShares ahead of this order in the queue

POST /api/v1/orders

Places a new order. On a non-live market, the matching engine runs before the response. On a live event market, the server accepts the order as scheduled and delays matching by the configured live-order delay (normally 3 seconds).

Auth: Required

Request body

{ "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 100, "orderType": "buy" }
FieldTypeRequiredDescription
marketIdUUIDYesTarget market
side"yes" | "no"YesSide to buy or sell
priceinteger 1–99 | nullConditionalLimit price. Required for buy orders without budgetCents. For market-sell orders set to null.
quantityinteger 1–10000ConditionalShares to trade. Required for sell orders and buy orders without budgetCents.
budgetCentsinteger > 0ConditionalEUR-cent budget for market-buy orders. Mutually exclusive with quantity.
orderType"buy" | "sell"NoDefault "buy"
idempotencyKeyUUIDNoSupply the same UUID to safely retry without double-placing. Valid for 24 hours.
expiresAtISO 8601 datetimeNoWhen the order auto-cancels. Must be in the future. Omit for Good Till Cancelled.
postOnlybooleanNoDefault false. When true, reject rather than execute as a taker if the order would cross at matching time. Incompatible with budget buys and market sells.

Buy orders: supply exactly one of quantity or budgetCents.
Sell orders: supply quantity. Set price = null for a market sell (fills at any available bid).

Response

{ "order": { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 100, "filledQuantity": 20, "status": "partially_filled", "orderType": "buy", "cancelReason": null, "expiresAt": null, "createdAt": "2026-01-15T14:32:00.000Z" }, "fills": [ { "id": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "buyOrderId": "d4e5f6a7-b8c9-0123-def0-234567890123", "sellOrderId": "c3d4e5f6-a7b8-9012-cdef-123456789012", "buyerId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "sellerId": "f6a7b8c9-d0e1-2345-f012-456789012345", "price": 55, "quantity": 20, "createdAt": "2026-01-15T14:32:00.000Z" } ], "cancelledOrders": [], "balance": { "total": 987600, "available": 987600 }, "feeCents": 110 }
FieldTypeDescription
orderobjectThe placed order in user-facing form
fillsarrayTrades generated by this order (may be empty if no matching liquidity)
cancelledOrdersarrayOrders cancelled as a side effect of this match (e.g. resting orders cancelled due to insufficient funds, expired orders, or overextended sell positions)
balance.totalintegerYour EUR-cent balance after the transaction
balance.availableintegerCurrently always equal to total; reserved for a future margin model
feeCentsinteger | nullTaker fee charged for this order, in EUR-cents. 0 if nothing filled. null on idempotent replay. See Fees.

balance.total already reflects the fee, so for a buy: spent = price × quantity + feeCents.

Live-market scheduled response

On a live event market, 201 means the order was accepted, not filled. The response has no fills or fee, the balance is unchanged, and the pending order is not visible in public depth:

{ "order": { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 100, "filledQuantity": 0, "status": "scheduled", "orderType": "buy", "cancelReason": null, "expiresAt": null, "releaseAt": "2026-01-15T14:32:03.000Z", "releaseInMs": 3000, "budgetCents": null, "createdAt": "2026-01-15T14:32:00.000Z" }, "fills": [], "cancelledOrders": [], "balance": { "total": 987600, "available": 987600 }, "feeCents": null }

At releaseAt, the engine validates the order again and matches it against the current book, not the submission-time snapshot. Limit-price protection still applies. The final status may be open, partially_filled, filled, or cancelled; release-time cancellation reasons include changed funds/position, market closure, trading pause, self-trade, post-only crossing, responsible-gaming limits, and insufficient liquidity for a budget buy.

Connect to GET /api/v1/user/stream for order_pending and order_released events, or poll this endpoint with status=scheduled/status=all. Cancelling a scheduled order is immediate.

An idempotent retry returns the original order’s authoritative current status. While it is still scheduled, releaseInMs is the actual remaining time; retrying does not restart the delay or emit another order_pending event.

Status code: 201 on new order, 200 on idempotent replay.

Errors

StatusBodyWhen
400{ "error": "...", "code": "INSUFFICIENT_BALANCE" }Not enough balance or position
400{ "error": "...", "code": "INSUFFICIENT_LIQUIDITY" }Budget buy with no matching liquidity
400{ "error": "...", "code": "SELF_TRADE_BLOCKED" }The order would match your own resting order on the opposite side. Cancel or amend that order first.
400{ "error": "Market is not open for trading" }Market status is not open
400{ "error": "Market not found" }Unknown marketId
503{ "error": "...", "code": "CONFLICT_RETRY" }Transient lock conflict. Safe to retry.

PATCH /api/v1/orders/:id

Amends a scheduled, open, or partially-filled order. You can change price, quantity, or both.

Auth: Required

Path parameters

ParamTypeDescription
idUUIDOrder to amend (must belong to you)

Request body

Supply at least one field:

{ "price": 60, "quantity": 80 }
FieldTypeDescription
priceinteger 1–99New limit price in user-facing form
quantityinteger 1–10000New total quantity (must be ≥ filled quantity)

Amendment rules:

  • Quantity decrease only: amended in place, queue position preserved.
  • Price change or quantity increase: cancel-replace: the resting order is cancelled and a new order is placed at the new price/quantity. Queue position is lost; outside the live-delay path, the new order is re-matched immediately.
  • Any change to a scheduled order: cancel-replace and start a fresh live-delay window.
  • Live-market reprice or quantity increase: the replacement becomes scheduled; it is not matched immediately.

Response

Quantity decrease only (in-place, queue position preserved):

{ "order": { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 80, "filledQuantity": 40, "status": "partially_filled", "orderType": "buy", "cancelReason": null, "expiresAt": null, "createdAt": "2026-01-10T09:00:00.000Z" }, "amended": true, "queuePositionChanged": false }

Price change or quantity increase (cancel-replace, queue position lost):

{ "order": { "id": "e5f6a7b8-c9d0-1234-ef01-345678901234", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 60, "quantity": 80, "filledQuantity": 0, "status": "open", "orderType": "buy", "cancelReason": null, "expiresAt": null, "createdAt": "2026-01-10T09:15:00.000Z" }, "fills": [], "amended": true, "queuePositionChanged": true, "cancelledOrderId": "d4e5f6a7-b8c9-0123-def0-234567890123", "feeCents": 0 }
FieldTypeDescription
orderobjectUpdated order
amendedbooleanfalse if nothing changed
queuePositionChangedbooleantrue when cancel-replace was used
cancelledOrderIdUUID | undefinedId of the cancelled order on cancel-replace
fillsarray | undefinedNew fills generated by the replacement order
feeCentsinteger | undefinedTaker fee charged for the replacement order, in EUR-cents. Present only on cancel-replace; 0 if it didn’t fill. See Fees.

Errors

StatusBodyWhen
400{ "error": "Cannot amend order with status: ..." }Order is not open or partially_filled
400{ "error": "Cannot reduce quantity below filled amount (N)" }New quantity < filled quantity
400{ "error": "Market is not open for trading" }Market closed during amendment
400{ "error": "...", "code": "INSUFFICIENT_BALANCE" }Insufficient funds for price/quantity increase
404{ "error": "Order not found" }Unknown id or not yours
503{ "error": "...", "code": "CONFLICT_RETRY" }Transient lock conflict. Safe to retry.

POST /api/v1/orders/cancel-batch

Cancels up to 100 orders in one call. Each cancel runs in its own transaction, so partial success is preserved. One bad id does not roll back the rest.

Auth: Required

Request body

{ "orderIds": [ "d4e5f6a7-b8c9-0123-def0-234567890123", "e5f6a7b8-c9d0-1234-ef01-345678901234" ] }
FieldTypeRequiredDescription
orderIdsUUID[]Yes1–100 order ids to cancel. Duplicates are deduplicated.

Response

{ "cancelled": [ { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 100, "filledQuantity": 40, "status": "cancelled", "orderType": "buy", "cancelReason": "user_cancelled", "expiresAt": null, "createdAt": "2026-01-10T09:00:00.000Z" } ], "failures": [ { "orderId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "code": "not_cancellable" } ], "balance": { "total": 992400, "available": 992400 } }
FieldTypeDescription
cancelledarrayOrders cancelled by this call, in user-facing form
failuresarrayOne entry per id that could not be cancelled
failures[].orderIdUUID stringThe id that failed
failures[].codestringnot_found (unknown id or not yours) | not_cancellable (already filled or cancelled) | internal (unexpected server error)
balanceobject | nullBalance after the batch; null if the post-cancel balance refresh failed

Status code: 200, including when every id is in failures.


DELETE /api/v1/orders/:id

Cancels a resting or scheduled order. Cancellation is immediate and never waits for the live-order delay. Open buy orders do not reserve balance, so the cancel leaves your balance unchanged. Balance changes only when an order fills.

Auth: Required

Path parameters

ParamTypeDescription
idUUIDOrder to cancel (must belong to you)

Response

{ "order": { "id": "d4e5f6a7-b8c9-0123-def0-234567890123", "userId": "e5f6a7b8-c9d0-1234-ef01-345678901234", "marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "side": "yes", "price": 55, "quantity": 100, "filledQuantity": 40, "status": "cancelled", "orderType": "buy", "cancelReason": "user_cancelled", "expiresAt": null, "createdAt": "2026-01-10T09:00:00.000Z" }, "balance": { "total": 992400, "available": 992400 } }

Errors

StatusBodyWhen
400{ "error": "Cannot cancel order with status: ..." }Order already filled or cancelled
404{ "error": "Order not found" }Unknown id or not yours