Skip to main content
Order endpoints require API key authentication. See Authentication for HMAC signing.

Order Model

Hit accepts low-level order payloads built from outcome token amounts. Do not send priceUint. The server sets it, and the request validator rejects a body that carries it. Amounts use 6 decimals:
For limit orders: Limit order prices must be valid multiples of the market tickSize.

Client-Signed Orders

Maker and signer are both your wallet, and the signature type is 0. maker, signer and signatureType are part of the signed message but are not sent in the body: Hit sets them from your account. See Place a Client-Signed Order.

Place an Order

The examples buy 50 shares for 31 USDC, which is a 0.62 limit price.

Place a Client-Signed Order

To sign orders yourself:
  1. Sign as your wallet: maker and signer are both your wallet’s address, and the signature type is 0.
  2. Read the market with GET /markets/{id_or_slug} and pick the exchange from the market’s negRisk, not the event’s: the neg-risk exchange when it is true, the standard exchange otherwise.
  3. Sign the complete EIP-712 Order with your wallet’s private key, over nonce 0 unless a nonce-stale refusal on that exchange has given you another one.
  4. Send the order with API key authentication.
The signed message and the request body are not the same set of fields: The examples add to the request and units helpers from Place an Order. Set HIT_MARKET_ID to the market and HIT_WALLET_PRIVATE_KEY to the private key of your HIT Wallet. Keep the key secret: anyone who has it controls your funds. The same exchange addresses are also served by GET /api/v1/contracts. A signed order whose nonce is not the one Hit holds for your wallet on that exchange is refused with 400, errorCode: "nonce-stale" and serverNonce, the nonce Hit holds. Sign the order again over serverNonce and send that value as nonce. Keep sending it with every order you sign for that exchange: an order sent without nonce is checked against 0. The standard and neg-risk exchanges keep separate nonces. The nonce only moves if your wallet itself calls incrementNonce() on the exchange. POST /orders/batch reports the same refusal for each entry it applies to, as that entry’s code together with its serverNonce.
The examples need viem for TypeScript and eth-account for Python.

Taker Delay

Some markets hold marketable orders for a short delay before matching. An order is marketable when it would match against an order already on the book, which makes it a taker order. Orders that rest on the book without matching are not delayed. Read the delay for any market from its speedBumpDelayMs field in market data. Read speedBumpDelayMs rather than hard-coding these values. The table shows where delays apply today, and more market types may get one in future. You cannot cancel an order while it is delayed. On the /user WebSocket namespace, an order-speed-bump-pending event tells you an order was delayed before matching. See WebSockets.

Retrying a Failed Order

POST /orders answers 503 when your order could not be signed, submitted or admitted. Nothing is created when it does, so re-sending the identical body cannot duplicate the order. Each of these 503s carries a Retry-After header and repeats the same figure in the body as retryAfterSeconds. A 503 whose error is CREDENTIAL_UNVERIFIABLE is not one of them. Your API key could not be checked, so the order was not attempted. It carries no Retry-After header: re-send the request, signed again with a fresh hit-timestamp. See Authentication Failures. Read error before errorCode. It is the discriminator, and only one of its two values carries an errorCode at all. SIGNING_UNAVAILABLE has no errorCode. It has four causes: the signing provider being unavailable, rate-limiting Hit or having no slot in Hit’s signing-admission queue; the request budget being exhausted before your order was submitted; the duplicate guard’s store being unavailable; and, on POST /orders/batch only, the locking infrastructure being unavailable. Three of those four — the request budget, the duplicate guard’s store, and the batch locking infrastructure — reach orders you signed yourself, so do not treat this status as something that only happens to orders Hit signs for you. Every batch takes its per-account lock whether or not anything in it needs signing. ORDER_ADMISSION_UNAVAILABLE carries an errorCode, one of six values: The first four mean your collateral could not be read. engine-busy is a stronger statement than the others: the command was not decided, not recorded and not partially applied, because the venue was at one of its own internal bounds. idempotency-unverifiable means the duplicate check could not be answered, so the venue refused rather than risk a second live order for one key.
When you retry engine-busy or idempotency-unverifiable, re-send the identical body and do not change salt. The idempotency key is derived from the order’s contents, so a new salt is a different order and defeats the deduplication these codes exist to protect.
None of these means your order is invalid or your balance is insufficient. A genuinely insufficient balance is a 400, and retrying it will not help. POST /orders/batch reports the same six reasons per entry rather than as a 503. They arrive as that entry’s code inside a normal 201, with no Retry-After header, because other entries in the same request may have been created. That per-entry code set is open-ended: it is whatever the venue supplies for the entry, plus local fallbacks such as bad-request, internal-error, not-attempted, nonce-stale and order-archived. Do not assume the list is closed, and treat a value you do not recognise the way you treat internal-error. The batch route can still answer a request-level 503 with error: "SIGNING_UNAVAILABLE", and then nothing in the batch was created.

List Orders

Filters: When status is omitted, GET /orders returns all non-cancelled statuses. Passing status=CANCELLED returns 400. Use GET /orders/paginated for paginated results and cancelled history. Its omitted-status default is active orders only (PENDING and EXECUTING). total is opt-in and capped; use cursor, hasMore and nextCursor for efficient deep pagination. Your own writes are already visible to these reads. A create or cancel this API has acknowledged appears on your next GET /orders, GET /orders/paginated or GET /orders/{id}, so you do not need to poll until it shows up or sleep between writing and reading. The read waits for the read model to catch up, bounded at 1 second by default. If that bound expires you still get an answer, built from what has been written so far, which may be missing your most recent write; re-read in that case rather than re-sending the write. GET /orders/events reads a different table and is outside this guarantee.

Cancel Orders

Cancel one order:
Cancel a batch:
Cancel all orders in a market:
Cancel all orders in an event:
Cancellations fail in different shapes depending on the route: A 503 from POST /orders/{id}/cancel or POST /orders/cancel means nothing was cancelled, and you can re-send the identical request. On every one of these routes, a 503 whose error is CREDENTIAL_UNVERIFIABLE means your API key could not be checked and the request was not attempted, so nothing was cancelled. It carries no Retry-After header. Re-send the request, signed again with a fresh hit-timestamp. POST /orders/batch-cancel takes 1 to 50 version-4 UUIDs. It answers 500 when the venue replied with an error, 408 when no reply arrived within 30 seconds, 503 when the message broker failed, and 409 when another cancel-shaped batch is already in flight. None of the first three carries a Retry-After header or an errorCode. 408 and the broker’s 503 are lost-response cases: the orders may or may not have been cancelled, so re-read them before re-issuing. 409 is usually plain contention, but it is also returned when the lock service fails after your cancel was already published, so re-read on that one too rather than assuming nothing happened. POST /orders/cancel-all and POST /orders/cancel-event answer 200 when every order in scope is off the book and 207 when at least one is still resting. Both statuses carry the same body, so test for a 2xx rather than for one status. Read results, which has one entry per order the request covered. success says whether this request cancelled the order, so an entry can be false for an order that was already filled or cancelled. Decide from code:
The request helper above returns only the body, and throws on any status that is not a 2xx. To tell 200 from 207, read response.status in your own helper before parsing the body. If a 207 carries no entry that is still resting, read your open orders before re-sending. A 503 whose error is ORDER_SERVICE_UNAVAILABLE carries an outcome: nothing-cancelled means the request never started and can be re-sent as it is; unknown means it may or may not have cancelled, so read your open orders first. One cause of nothing-cancelled is that the sweep could not read its list of your orders (order reads at capacity, no database connection free in time, or no way to confirm the list includes every order you were acknowledged for), so it acted on none of them. That 503 and the ORDER_ADMISSION_UNAVAILABLE one described under Admission Errors can both still carry results for orders the venue reached before the failure.

Migrating from the market fields

The cancel-all and cancel-event responses used to carry five market-level fields beside results: clearedMarkets, failedMarkets, notAdmitted, markets and cancelled. These fields were removed in markets-v0.0.149. The response now carries results alone, so a client that still reads any of those fields finds them absent. Read results and the status instead. results entries carry no market ID. If you need to know which market an order was in, use your own order records or GET /orders/{id}. Full response shapes are in the Orders API reference.

Positions and Activity

These endpoints also accept API key authentication: