Skip to main content
Orders need a trade-scope key. Keys you create from Settings have it.
With the Python SDK, call client.place_order(...) instead of building the JSON body and HMAC headers yourself. Use omnibook.ticks for pip conversion and grid checks.

Prices are pip ticks

A binary contract pays 10,000 pips ($1) if the outcome happens and 0 if it does not. Prices are integers from 1 to 9999, in pips (0.01¢), not whole cents. Buying YES at 4700 costs 47.00¢ per contract. Old ticks 1–99 are rejected (bad_price_tick). Convert display cents with tick = round(cents * 100) — 35.00¢ → 3500. The live rest grid is whole cents in the interior and 0.10¢ on the wings. Full rules: Ticks, pips, and subcents. Quantities are whole contracts. Direction is side × outcome × tick, see Order direction.

Place a limit order

The response reports what actually happened, not an acknowledgement. The call is held until the order is sequenced, so by the time you get a 201 the order has really rested or filled:
status is one of resting, partially_filled, executed, or canceled (with a reason).
Balance and fee changes are deliberately absent from this response. Placement runs on a lane that excludes ledger events. Read GET /v1/portfolio/balance afterwards, or subscribe to the private WebSocket channel.

client_order_id is your idempotency key

You choose it, and it must be unique per order. It is what makes retries safe.
On a timeout, retry with the same client_order_id.A 504 means the request timed out, not that the order was rejected, it may still have been sequenced. Retrying with the same client_order_id either returns the original outcome or places it once. At most one order results.Retrying with a new id after a timeout is how you accidentally place two orders.

Order types

For market buys, max_cost (in pips, decimal string) is required — it bounds what you can spend. $5.00 is "50000". Market orders also accept worst_tick to bound the price you will accept; it defaults to 9999 for buys and 1 for sells. Time in force for limit orders: gtc (rest until cancelled), gtt (needs expiry_ts in nanoseconds), ioc (fill what you can, cancel the rest), fok (all or nothing). Useful flags, all default false: post_only (never take), reduce_only (only shrink a position), cancel_on_pause.
Omit generation. A non-zero value is an exact-match epoch. If it does not equal the slot’s live gate epoch, the venue rejects with 519 / MARKET_STALE even while the round clock still has time left. Leaving the field off (or sending 0) means “current occupant of this market_id” — that is the reliable way to place. Refresh market_id from GET /v1/markets?status=trading at send time; do not cache it across minutes.

Cancel

Cancel-all takes no body. If you send one it is rejected with unexpected_body rather than cancelling everything, so a batch cancel that loses its /batch path segment fails instead of clearing your book. Rounds last 60 seconds, 5 minutes, or 15 minutes depending on the series, so anything still resting when the round freezes is cancelled for you. cancel_on_pause is worth setting if you do not want orders surviving a pause.

Unknown fields are rejected

The request schema is closed: an unrecognised field returns 400 unknown_field rather than being ignored. A typo’d post_onlyy fails loudly instead of silently not applying.

Then check your position

Balance fields are pips (decimal strings). 10000 is $1.00.

Complete script

Self-contained — finds a trading market, places a limit YES buy on-grid, prints the outcome: