Skip to main content

Submitting orders

Order Entry is the professional/institutional submission surface. It accepts a batch of signed actions and routes them into the same sequencer, risk checks, matching engine, execution stream, and recovery model as every other lane. Two transports carry the same batch:

EndpointBodyUse
POST /api/v1/order-entry/ordersJSONApp backends, bots, debuggable submission
POST /api/v1/order-entry/orders/compactByte bodyMarket makers, quote engines, lower-overhead batches

Both submit the identical signed-action batch and return the same acknowledgement model. The byte lane is not a separate matching engine and is not FIX — it is an HTTP POST with a byte payload. For how to choose a lane, see Order Entry Lanes. For connectivity, hosts, credentials, and the exact signing scheme, see Authentication and Action Signing.

Legacy route names

The names "MM", "BSL", and "binary" are legacy aliases for Order Entry. The following routes remain live for already-wired clients but should not be used by new integrations: POST /api/v1/bsl/orders/batch, POST /api/v1/bsl/orders/compact, POST /api/order-entry/binary, POST /api/v1/mm/orders/batch.bin, and the /api/v1/bsl/orders/replace, /api/v1/bsl/orders/cancel-replace, /api/v1/mm/orders/replace, /api/v1/mm/orders/cancel-replace facades.

Signed-action batch shape

The batch wraps an array of signed action envelopes. Each envelope is a canonical action payload plus its signature. The same shape is used by both the JSON and compact endpoints; the compact endpoint sends it as bytes.

{
"version": 1,
"actions": [
{
"payload": {
"account": "0x1111111111111111111111111111111111111111",
"nonce": 42,
"ts": 1781190000000,
"action": {
"SpotPlaceOrder": {
"market": 7,
"side": "Bid",
"price": 998400,
"qty": 1000,
"timeInForce": "post_only"
}
}
},
"signature": {
"scheme": "EcdsaSecp256k1",
"bytes": "0x..."
}
}
],
"idempotencyKey": "batch-9001"
}

The account signature is the primary authority for every action. The byte lane does not replace action signing. clientOrderId, when used, must be inside the signed action payload so the engine can reconcile by client id deterministically.

Supported actions

The endpoint accepts signed action envelopes after the same public action validation as the rest of the API:

ActionUse
SpotPlaceOrderSingle spot order
OutcomePlaceOrder / PlaceOrderSingle prediction-market order
CancelCancel by order id
AmendOrderQuantity reduction while keeping priority
SpotQuoteReplaceSpot quote refresh
QuoteReplacePrediction-market quote refresh
PlaceConditionalOrderConditional order where enabled
PlaceAlgoOrderAlgo order where enabled

Internal actions — deposit credits, settlement credits, market creation, and resolution — are rejected on the Order Entry path.

Result mode

Send X-BSL-Result-Mode (the SDK responseMode option maps to this header) to choose how much of the engine result is returned inline:

ValueMeaning
ackSequencer accepted the request boundary. Lowest response overhead.
durableDurable/WAL boundary reached.
fullEngine-applied result included when available.

An ack confirms the configured ingress boundary, not final fill state. Use full when the strategy needs the engine-applied result in the HTTP response; use ack for high-rate flows that reconcile from the private execution stream.

JSON batch

POST /api/v1/order-entry/orders
Content-Type: application/json
X-BSL-Result-Mode: full
Idempotency-Key: strategy-42-batch-9001
{
"version": 1,
"actions": [
{
"payload": { "...": "signed ActionPayload" },
"signature": { "scheme": "EcdsaSecp256k1", "bytes": "0x..." }
}
],
"idempotencyKey": "strategy-42-batch-9001"
}

Use the JSON batch when a debuggable request body matters more than overhead.

Compact/binary batch

POST /api/v1/order-entry/orders/compact
Content-Type: application/x-senticore-order-entry-batch
Accept: application/x-senticore-order-entry-batch-response, application/json
X-BSL-Result-Mode: full
X-Senticore-Order-Entry-Key: <order-entry-lane-key>
Idempotency-Key: quote-refresh-1

The compact lane is for low-overhead submission and deterministic acknowledgement. The body is the byte-encoded order-entry batch.

If operations has assigned a dedicated lane key, include it as X-Senticore-Order-Entry-Key. For a builder rotate-key credential, the lane-key value is credential.apiKeyId — never put apiSecret or apiPassphrase in this header. The lane key is not a public shared secret; some signed-submit paths allow a missing lane key during private beta, but do not rely on that for production. The legacy X-MM-Key header is accepted only as a compatibility alias.

Byte framing and encoding

The compact submission is an HTTP POST body. It is not a FIX session and it does not use client-managed TCP sequence frames; FIX is documented separately because it needs a provisioned TCP/TLS endpoint, CompIDs, Logon credentials, and sequence recovery (see FIX).

Accepted content types:

Content typeStatus
application/x-senticore-order-entry-batchPreferred
application/x-senticore-mm-batchLegacy compatibility
application/x-senticore-binaryCompatibility
application/octet-streamCompatibility

A request without a content type is treated as a binary/byte submission by the server-side decoder.

Encoding. The TypeScript, Python, and Rust SDKs encode the batch JSON as UTF-8 bytes and submit it with the preferred content type:

{"version":1,"actions":[...],"idempotencyKey":"client-batch-1"}

The server first tries its internal cold binary decoder, then falls back to this SDK JSON byte shape.

Limits. Read GET /api/v1/bsl/limits (legacy alias GET /api/v1/mm/limits) rather than hard-coding limits. The response reports max actions per batch, low-latency max actions, max binary body bytes, timestamp skew, rate windows, and backlog limits.

Windowed nonces for concurrency

Nonces use a windowed replay-protection model: any unused nonce in [nonceFloor, nonceFloor + nonceWindow) (currently nonceWindow = 256) is accepted. Gaps and out-of-order are allowed — a batch's legs and concurrent batches may use arbitrary unused in-window nonces in any order. You do not need contiguous nonces, gap-filling, ack round-trips, or nonce reservations; the old "nonce gap" rejection no longer exists.

Per-leg rejects are independent and carry nonceFloor / nonceWindow plus a code (nonce_below_floor / nonce_outside_window / nonce_replayed). Re-pick a fresh in-window nonce for the rejected leg only. See Order Concurrency & Nonces for the full model.

Cancel-replace

Cancel-replace amends price, quantity, or order flags without manually issuing separate cancel and place calls. Separate operations can expose a strategy to stale-quote risk or temporary loss of queue position; cancel-replace gives one operation with one acknowledgement path.

For new integrations, use a signed QuoteReplace (prediction markets) or SpotQuoteReplace (spot) action inside the batch. A leg's cancel_order_id removes a stale quote leg in the same signed action:

  • A leg with cancel_order_id and qty: 0 is cancel-only.
  • A leg with cancel_order_id and a non-zero qty cancels and re-places.
  • A leg without cancel_order_id is place-only.
{
"version": 1,
"actions": [
{
"payload": {
"account": "0x1111111111111111111111111111111111111111",
"nonce": 42,
"ts": 1781190000000,
"action": {
"SpotQuoteReplace": {
"market": 1,
"legs": [
{
"cancel_order_id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"side": "Bid",
"price": 999900,
"qty": 100000,
"time_in_force": "post_only"
}
]
}
}
},
"signature": { "scheme": "EcdsaSecp256k1", "bytes": [1, 2, 3] }
}
],
"idempotencyKey": "replace-bid-1"
}

Replaceable fields

FieldReplaceableNotes
PriceYesMust satisfy tick size
QuantityYesMust satisfy lot size and collateral checks
Time-in-forceLimitedSome transitions require cancel and new order
SideNoUse cancel and new order
MarketNoUse cancel and new order
AccountNoUse cancel and new order

Failure behavior

Replace is one result boundary. Do not infer that the original order is gone from request acceptance alone — if the replacement is rejected, the original order remains active unless the response explicitly says it was cancelled. In full mode reconcile the order state from the engine result:

StatusClient action
filledPosition and exposure changed immediately.
partially_filledContinue quoting with updated leaves quantity.
restingNew order is live on the book.
canceledCancel side completed.
rejectedInspect rejectCode; do not assume the old order is gone unless the result says so.

The FIX equivalent is OrderCancelReplaceRequest (35=G); see FIX Order Entry.

Bulk operations

Bulk operations let liquidity providers and HFT quote engines update many quotes with one request. Submit a batch of signed actions exactly as above — QuoteReplace and SpotQuoteReplace are the preferred quote-refresh actions — and rely on windowed nonces to pipeline concurrent batches.

Atomicity is action-level, not a separate matching engine:

  • Frame, auth, timestamp, and schema failures reject the whole batch before enqueue.
  • Accepted actions enter the normal sequencer path; per-action rejects are independent.
  • Terminal state is reconciled from receipts, private streams, or account reads.

Cancel by clientOrderId, mass-cancel per session, and cancel-on-disconnect should use the same session and private stream for reconciliation. For high-frequency quoting, do not treat HTTP 200 on a non-full request as a terminal order state — ack means the request boundary was accepted; the execution stream or gap-fill is the source for fills, cancels, and rejects.

Acknowledgement and timing

The response contains ok, accepted sequence ids (seqs), derived order ids, result mode, ACK mode, rate-limit metadata, timing headers, and optional per-order actionResults depending on the response mode.

Every response includes timing fields so clients can locate latency:

FieldMeaning
gatewayReceivedTsServer ingress timestamp.
authDoneTsAuth and credential gate completed.
riskDoneTsRisk or credit approval completed when applicable.
sequencedTsRequest entered sequencing.
engineAppliedTsEngine terminal event timestamp when available.
durableTsDurable acknowledgement timestamp when requested and reached.
responseSentTsResponse emission timestamp.

The durationsUs object carries microsecond breakdowns for auth, routing, risk, enqueue, ack resolution, response emission, and total server time.

Idempotency

Use both the HTTP Idempotency-Key header and the body idempotencyKey field for retriable batches. The server hashes the body and response mode; retrying the same key returns the existing response when the request hash matches. Retrying a key with a different body is a client error — treat it as a client bug and reconcile before submitting new risk. Idempotency-Key is the HTTP retry-dedup key; clientOrderId is the strategy correlation id. See Idempotency.

Failure model

Rejects use stable numeric reason codes that map to the public Error Model: tick-size violation, insufficient collateral, stale nonce, duplicate client order id, and account-permission failures. On SHARD_BUSY or QUEUE_LIMIT, back off or reroute quoting for that market. During private beta some rejection paths still return string messages while machine-readable codes are expanded; preserve the raw error body in logs.

Client rules

  • Use ack for high-rate quote refreshes that reconcile from the stream.
  • Use full for IOC/FOK, cancel, and replace.
  • Use durable only when persistence acknowledgement matters more than latency.
  • Treat Idempotency-Key as the retry-dedup key and clientOrderId as the strategy correlation id.
  • The durable truth is the sequencer/execution stream — the first HTTP acknowledgement is not the final order state.