Skip to main content

Place Orders

(tradingPairId: string, side: OrderSide, quantity: string, price: string, options?) => Promise<CreateOrderResponse>
Place a limit order with a specific price. Defaults to GTC (Good Till Canceled) time-in-force.Parameters:
  • tradingPairId: string - Trading pair UUID (get via sdk.market.getTradingPairBySymbol('BTC/USDC'))
  • side: “BUY” | “SELL” - Order side
  • quantity: string - Order quantity
  • price: string - Limit price
  • options?: Optional settings
    • tradingMode?: "SPOT" | "MARGIN" (default: "SPOT")
    • useMasterBalance?: boolean - Use master account balance (for sub-accounts)
    • expirationDate?: string - ISO 8601 date for GTC orders
    • timeInForce?: "GTC" | "IOC" | "FOK" - Time in force (default: "GTC")
      • GTC (Good Till Canceled): Order stays active until filled or canceled
      • IOC (Immediate or Cancel): Fill immediately, cancel unfilled portion
      • FOK (Fill or Kill): Fill completely or reject entirely
      • GTD is declared in the protos but never implemented — the server rejects it. For an order that expires at a set time, send GTC with expirationDate.
    • postOnly?: boolean — maker-only guarantee. The order is rejected instead of matching if it would cross the book at admission (BUY at/above the best ask, SELL at/below the best bid) — REST 400 / gRPC InvalidArgument carrying the structured error code POST_ONLY_WOULD_CROSS (REST error-envelope code field; gRPC google.rpc.ErrorInfo reason). Match on the code; the "post-only order would cross" message substring is a legacy fallback. LIMIT with GTC only — rejected on MARKET orders and when combined with IOC/FOK. Persisted with the order and echoed back as postOnly: true on order reads. See Post-Only Orders
    • leverage?: string — decimal string, e.g. "10"; required for normal margin orders, omit only for reduce-only
    • reduceOnly?: boolean — order can only shrink existing exposure
    • marginAccountId?: string — optional legacy override; omit for normal perp orders
    • positionSide?: "LONG" | "SHORT" | "NONE" — deprecated. side is the authoritative direction; if supplied, positionSide must agree (BUY↔LONG, SELL↔SHORT)
    • clientOrderId?: string — a correlation handle you choose (≤64 chars from A-Za-z0-9._:-, whitespace trimmed, blank treated as absent). Echoed back on order detail/list reads and on every orders WebSocket event. Uniqueness is enforced only among your resting orders (409 CLIENT_ORDER_ID_CONFLICT); an order that never rests — MARKET, IOC/FOK, or a LIMIT that fills on arrival — does not take the handle. It is not an idempotency key: only a retained explicit idempotencyKey makes the same create safe to replay within 24 hours. Without that key, or after it expires, resubmitting after a lost response can execute a second time — reconcile against the order stream (sdk.ws.userOrders), not the order list, which is replica-backed and can omit an order that did land. See Client Order IDs
    • selfTradePreventionMode?: "CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP" — how the engine resolves this order meeting one of your own resting orders (your whole wallet family, across applications and sub-accounts). Overrides the wallet default set via sdk.profile.setSelfTradePreventionDefault; omit it to inherit that, or the platform default CANCEL_MAKER. The taker’s mode governs the whole step — resting orders’ modes are never consulted. Echoed back on order reads and orders WebSocket events as the value you requested, absent when you sent none. See Self-Trade Prevention
    • idempotencyKey?: string — durable submission key (1–64 characters from A-Za-z0-9._:-). The SDK generates one for this call when omitted. Retain and reuse an explicit key with the same payload to recover across calls or restarts within 24 hours; a new key can execute a new order. See Safe Retries
Perps are one-way — side sets the direction. Attach TP/SL at entry with takeProfit/stopLoss (margin entry orders only; legs activate when the order fills and cancel if it is cancelled or expires unfilled), or attach to the open position with sdk.positions.attachPositionTpSl. A trailingStop leg (ParentTrailingStopLegParams: trailBps, activationPrice?, quantity? / closePosition?, slippageToleranceBps?, expiresAt?) attaches the same way but arms only when the order fully fills. trailingStopOrderId is present only when the trailing stop materializes: the order fully fills on arrival or leaves a resting remainder. A partial fill whose remainder is cancelled (an IOC or MARKET order) creates no trailing stop and omits the id. See Trailing Stop.Perp example:
(tradingPairId: string, side: OrderSide, quantity: string, options?) => Promise<CreateOrderResponse>
Place a market order. Fills execute inside a mandatory 1,000 bps (10%) server-side price band (see Market-order price protection): a market order can partially fill with the remainder cancelled, or be rejected when no liquidity sits inside the band. Triggered TP/SL market legs use a wider 1,200 bps (12%) band.Parameters:
  • tradingPairId: string - Trading pair UUID (get via sdk.market.getTradingPairBySymbol('BTC/USDC'))
  • side: “BUY” | “SELL” - Order side
  • quantity: string - Order quantity
  • options?: Optional settings
    • tradingMode?: "SPOT" | "MARGIN" (default: "SPOT")
    • slippageTolerance?: number - tightens the 1,000 bps price band (e.g. 0.01 for 1%); cannot widen it
    • leverage?: string — decimal string; required for normal margin orders, omit only for reduce-only
    • reduceOnly?: boolean — order can only shrink existing exposure
    • marginAccountId?: string — optional legacy override; omit for normal perp orders
    • positionSide?: "LONG" | "SHORT" | "NONE" — deprecated; side is authoritative
    • clientOrderId?: string — correlation handle echoed on order reads and orders WebSocket events (≤64 chars from A-Za-z0-9._:-); not an idempotency key. See Client Order IDs
    • selfTradePreventionMode?: "CANCEL_MAKER" | "CANCEL_TAKER" | "CANCEL_BOTH" | "SKIP" — how the engine resolves this order meeting one of your own resting orders (your whole wallet family, across applications and sub-accounts). Overrides the wallet default set via sdk.profile.setSelfTradePreventionDefault; omit it to inherit that, or the platform default CANCEL_MAKER. The taker’s mode governs the whole step — resting orders’ modes are never consulted. Echoed back on order reads and orders WebSocket events as the value you requested, absent when you sent none. See Self-Trade Prevention
    • idempotencyKey?: string — durable submission key (1–64 characters from A-Za-z0-9._:-). The SDK generates one for this call when omitted. Retain and reuse an explicit key with the same payload to recover across calls or restarts within 24 hours. See Safe Retries
Perp example:
(orders: BatchCreateOrderParams[]) => Promise<BatchCreateOrdersResponse>
Create 1–100 orders. Every item is processed independently and keeps its input position in results; one failure does not roll back successful siblings.BatchCreateOrderParams includes tradingPairId, orderType, side, and quantity, plus the single-create margin and execution options except attached takeProfit / stopLoss / trailingStop, which batch items do not support. price is required for LIMIT; timeInForce is valid only for LIMIT; postOnly requires LIMIT + GTC. Each item also accepts clientOrderId?, idempotencyKey? and selfTradePreventionMode?. selfTradePreventionMode is covered by BatchCreateOrderItemSchema, unlike clientOrderId. BatchCreateOrdersSchema validates the whole array before anything is sent, so one item’s unknown mode throws ValidationError and no item executes — the per-item results[].error.code === "INVALID_SELF_TRADE_PREVENTION_MODE" is a raw REST/gRPC caller’s shape, never an SDK caller’s. A FOK item under CANCEL_BOTH that meets one of your own orders does reach the engine and fails as that item with SELF_TRADE_NOT_ALLOWED; neither rolls back its siblings. The SDK generates a separate key for each item that omits one. Retain explicit per-item keys when an ambiguous result must be retried across calls; a key protects only its own item and does not make the batch atomic.Returns: { totalRequested, totalSucceeded, totalFailed, results }. Each result contains orderId, optional matchResult, and optional error: { code, message }; absence of error means success.The TypeScript SDK validates the batch envelope and every field covered by BatchCreateOrderItemSchema before sending; it throws ValidationError (exported by @0xmonaco/types, not @0xmonaco/core) for those client-schema failures or more than 100 items. clientOrderId is typed but is not covered by that client schema, so an invalid handle reaches the server and returns as the item’s results[].error.code === "INVALID_CLIENT_ORDER_ID". Raw REST/gRPC callers receive REST 400 / gRPC InvalidArgument for whole-request errors; REST 401 / gRPC Unauthenticated when authentication is missing; and REST 500 / gRPC Internal for an internal failure. A raw batch with no item key can also return whole-request REST 503 / gRPC Unavailable after a deadline or transport failure; its outcome is unknown, and without retained keys it cannot be safely retried. Other item-level validation and placement failures remain in results. Because the TypeScript SDK keys every item, an internal deadline expiry instead returns overall REST 200 / gRPC OK with results[].error.code === "SERVICE_UNAVAILABLE" on that item. Inspect every result, reconcile its state, and reuse the same explicit item key before retrying.See Batch Create and Safe Retries.

Order Management

(orderId: string, options?: { remainingQuantityTarget?: string }) => Promise<CancelOrderResponse>
Cancel an order. Called with just an orderId, it fully cancels the order.Pass options.remainingQuantityTarget for a partial cancel: the resting order is reduced in place to that remaining quantity, keeping its queue position — unlike replaceOrder, which retires the order and rests a new one at the back of the book even for a pure size-down. The released delta unlocks exactly as a cancel does (spot unlock / margin reserve).The target is “leave this much resting”, not an amount to remove, so a retried request converges instead of compounding. It must be a positive multiple of the market’s quantity step and strictly below the order’s current remaining quantity — emptying an order is a full cancel’s job, and growing one is a replaceOrder. The reduction emits a non-terminal OrderPartiallyCancelled event on the orders WebSocket channel (the order is still resting); see WebSockets.
(orderIds: string[]) => Promise<BatchCancelOrdersResponse>
Cancel multiple specific orders by their IDs.Parameters:
  • orderIds: string[] - Array of order IDs to cancel
Returns:
  • totalRequested: number - Total number of orders requested to cancel
  • totalCancelled: number - Count of successfully cancelled orders
  • totalFailed: number - Count of failed cancellations
  • results: BatchCancelResult[] — each with orderId, optional cancelledAt, optional error: { code, message }. cancelledAt is the matching engine’s cancel stamp at millisecond precision — it matches, to the millisecond, the cancelledAt a later read of the order returns
Example:
Note: Some cancellations may fail while others succeed; failures don’t roll back successful cancellations. Use totalFailed === 0 for an overall-success check.A batch is capped at 100 order IDs per request; a longer array is rejected with API 400 (At most 100 orders per batch request). batchCancelAll enumerates active orders server-side, with a separate cap of 20,000 matching active orders.
(tradingPairId?: string) => Promise<BatchCancelOrdersResponse>
Cancel all active orders, optionally filtered by trading pair.The request is capped at 20,000 matching active orders. Above that cap, it cancels nothing and returns REST 400; narrow the request by trading pair or cancel explicit batches of at most 100 IDs. This all-or-nothing cap check happens before any cancellation.Parameters:
  • tradingPairId (optional): string - Trading pair UUID to filter cancellation. If omitted, cancels all active orders globally.
Returns: Same shape as batchCancel (totalRequested, totalCancelled, totalFailed, results: BatchCancelResult[])Throws:
  • REST 400 / gRPC InvalidArgument when the pair UUID is invalid or more than 20,000 matching active orders would be cancelled
  • REST 401 / gRPC Unauthenticated when authentication is missing or invalid
  • REST 403 / gRPC PermissionDenied when a delegated session omits the required pair scope or lacks permission
  • REST 429 / gRPC ResourceExhausted when the risk-reduction budget is spent — mass exit costs one item per call, however many orders it cancels, and the call must fit both your account’s budget and your account family’s shared one. Honor the interval the transport carries: REST puts it in the body’s details.retryAfter, gRPC attaches a google.rpc.RetryInfo detail to the status
  • REST 500 / gRPC Internal for an internal matching-engine failure
  • REST 503 / gRPC Unavailable for a transient matching-engine or transport failure
Example:
(orderId: string, newOrder: { price?: string; quantity?: string; useMasterBalance?: boolean; postOnly?: boolean; clientOrderId?: string; selfTradePreventionMode?: SelfTradePreventionMode }) => Promise<ReplaceOrderResponse>
Modify an existing order’s price or quantity. quantity is the order’s new total, not a fresh size: on a partially filled order the replacement rests total - filled and locks collateral for that remainder only (FIX cancel/replace convention: LeavesQty = OrderQty - CumQty), so the total must exceed the filled amount — replacing a 96/100-filled order with quantity: "200" rests 104 and reads as 96/200 filled. Omitting quantity keeps the order’s total. The replacement inherits the original’s fill history — filled quantity, VWAP, and realized fee/payment aggregates carry onto the new order — so summing those aggregates across a replacement chain double-counts (per-order and trade-level reads are unaffected). Margin reduce-only replacements are exempt: their quantities stay close sizes, measured against the live position and placed as given, so neither the subtraction nor the must-exceed-filled rule applies. Pass postOnly to re-state maker-only intent for the replacement — it is never inherited from the original order. A single replaceOrder validates postOnly (and every other check) before cancelling the original, so a post-only crossing rejection leaves the original resting, untouched. See Post-Only Orders. A replacement is a new order with a new id, so clientOrderId is also not inherited — restate it to keep the handle. selfTradePreventionMode behaves the same way: the replacement carries its own value and inherits nothing from the original, falling back to your wallet default when omitted. See Self-Trade Prevention.Two kinds of order cannot be replaced at all. A TWAP slice child is refused — cancel the parent instead — and so is the LIMIT leg a take-profit or stop-loss fired into, any order carrying conditionalOrderId: a replacement would rest under a new id the conditional order does not point at, severing the link in both directions. Both are INVALID_ORDER rejections, the conditional one naming the conditional order, and in both cases the original stays resting. Cancelling a triggered leg is unaffected.
(orders: BatchReplaceOrderParams[]) => Promise<BatchReplaceOrdersResponse>
Replace 1–100 resting orders in one request. Cancel-first: the matching engine cancels every item’s original before placing any replacement, in request order, so a two-sided quote can shift across its own resting prices in one call — see Batch Replace for the failure semantics that follow from that ordering.BatchReplaceOrderParams carries orderId plus the optional price, quantity, useMasterBalance, postOnly, clientOrderId and selfTradePreventionMode. Although each is optional at the type level, BatchReplaceOrderItemSchema requires at least one of price or quantity per item — an item that only restates selfTradePreventionMode or postOnly throws ValidationError before sending. quantity is the order’s new total, exactly as in replaceOrder. A replacement is a new order with a new id, so postOnly, clientOrderId and selfTradePreventionMode are never inherited — restate each one you want to keep. There is no timeInForce input: the replacement inherits the original’s, and since only an already-resting order is eligible that is always GTC/GTD — so a replacement is never IOC/FOK and the FOK + CANCEL_BOTH self-trade rejection cannot arise here. A successful item is not necessarily resting either: CANCEL_TAKER, CANCEL_BOTH, or a SKIP remainder crossing one of your surviving orders can cancel the replacement immediately, so read the order’s status rather than inferring it from the result.Returns: { totalRequested, totalSucceeded, totalFailed, results }. Each BatchReplaceResult carries the required originalOrderId, plus optional newOrderId, updatedFields, matchResult and error: { code, message } — note it is originalOrderId, not orderId, so a result is keyed by the order you replaced rather than the one you got back.As with batchCreate, the SDK validates the whole array against BatchReplaceOrdersSchema before sending, so an unknown selfTradePreventionMode throws ValidationError and no item executes; the per-item INVALID_SELF_TRADE_PREVENTION_MODE is a raw REST/gRPC caller’s shape.The same two exclusions as replaceOrder apply per item: a TWAP slice child and a LIMIT leg carrying conditionalOrderId are both refused with INVALID_ORDER, and the refused item’s original stays resting.

Conditional Orders (Perp TP/SL)

Conditional orders sit dormant until mark price crosses a trigger, then submit the underlying order. Create TP/SL and trailing stops by attaching legs at entry via takeProfit/stopLoss/trailingStop on placeLimitOrder / placeMarketOrder, or to an open position via sdk.positions.attachPositionTpSl. Standalone creation has been removed; existing conditionals can be fetched by ID, listed, and cancelled.
(conditionalOrderId: string) => Promise<ConditionalOrder>
Fetch a single conditional (TP/SL) order by its UUID. The takeProfitOrderId, stopLossOrderId and trailingStopOrderId fields returned by attachPositionTpSl (and on an entry order’s CreateOrderResponse) are conditional order UUIDs queryable via this method. A trailing stop reads conditionType: "TRAILING_STOP" and additionally carries trailBps, activationPrice?, watermarkPrice? (best mark since arming, from which triggerPrice is derived; absent on a stop that armed immediately until the first mark after arming; an activationPrice stop is seeded at that level the moment it arms) and trailArmedAt? (absent while waiting for activationPrice); state stays ACTIVE both while waiting for activation and while tracking (an entry-attached one is PENDING_PARENT until its order fully fills).Returns: ConditionalOrder — the same type produced by listConditionalOrdersOnce state is TRIGGERED, the response carries triggeredOrder?: TriggeredOrderSummary — what the order this conditional fired into has done so far, read from that order’s own row at request time: orderId, status, filledQuantity, and optional averageFillPrice, totalTakerFees, filledAt and terminalReason. It is absent while the conditional waits on its trigger, absent on a FAILED conditional, and absent on the conditional_orders WebSocket frames — snapshot and live alike. A FAILED conditional has no summary because it never recorded a triggeredOrderId to join on, and it may have no close row either: a close the engine placed and the book then rejected persists as an order row carrying conditionalOrderId, but one refused before placement — a validation failure such as a bad quantity step — produces no order at all. Read failureReason on the conditional rather than looking for a close.status is copied verbatim from the close’s own row, so treat it as the full OrderStatus union and switch with a default branch rather than against a fixed list. What you will actually see: SETTLED once a fully filled leg has settled, and FILLED in the window before that — a filled order is a real persisted state on its way to SETTLED, not a value this field skips; SUBMITTED / PARTIALLY_FILLED for a LIMIT leg still resting; CANCELLED when the remainder was cut, which includes a MARKET or IOC leg that filled part of its quantity, so a CANCELLED close can carry a nonzero filledQuantity (read terminalReason); and EXPIRED for a LIMIT leg that lapsed.Compare triggeredOrder.averageFillPrice against triggerPrice rather than assuming they match. The trigger fires when the mark crosses the level and the leg then trades against the book, and the mark is a reference price rather than the book’s midpoint, sampled on a worker tick — so the two prices are independent. A market close usually fills worse than the trigger, by the spread it crosses plus the depth its size consumes, but there is no guaranteed minimum gap and a fast move can leave it better. Values for the same state are numerically equal to what getOrder returns, but the two reads are not guaranteed to see the same state: this summary is a repository read of the order row, while getOrder is cache-first and the read cache is fed by the live engine stream, so it can be ahead of the database by the persistor’s lag. A filledQuantity, averageFillPrice or fee total that disagrees between the two is usually that lag, not a bug — read getOrder when you need the close’s very latest state. Even for the same state the printed scale can differ, so never compare the raw strings with ===: compare as exact decimals, normalizing the scale or using a decimal library, rather than through Number(), which is inexact. See Trigger Price Is Not Fill Price.Example:
(conditionalOrderId: string) => Promise<CancelConditionalOrderResponse>
Cancel an active conditional order.Returns: { conditionalOrderId, status, message }
(params?: ListConditionalOrdersParams) => Promise<ListConditionalOrdersResponse>
List conditional orders for the authenticated user. Cursor (pageToken) pagination is the default; the deprecated page selects legacy page-number mode.Parameters (all optional):
  • marginAccountId?: string
  • tradingPairId?: string
  • state?: ConditionalOrderState
  • pageToken?: string — pagination cursor:
    • omitted — the SDK starts a cursor walk (pageToken=""), unless the deprecated page was passed
    • "" — start a cursor walk from the newest conditional order
    • a previous nextPageToken — resume the walk from that cursor
  • page?: number — deprecated: legacy page-number pagination; ignored whenever pageToken is present
  • pageSize?: number — max 100 in page-number mode, up to 1000 when pageToken is present
Returns ListConditionalOrdersResponse:
  • orders: ConditionalOrder[]
  • total: number — in legacy page-number mode, bounded by the pagination reach: exact up to pageSize × 10,000 rows and saturating there, so a caller with more matching conditional orders than page-number mode can page through reads the cap, not its lifetime total. 0 in cursor mode, which runs no COUNT.
  • nextPageToken: string — cursor for the next page; minted only while a further page exists, empty on the final cursor page and in legacy page-number mode. Follow it until it comes back empty; build “load more” UIs on it rather than “page N of M”.
  • page: number — deprecated: current page in legacy mode only; 0 in cursor mode
  • pageSize: number
Errors: 400 (invalid query parameters, a malformed pageToken, or a pageToken replayed against different filters than the ones that minted it), 401 (auth required), 429 (read rate limit — retry after retryAfter), 500.Rows carry triggeredOrder on the same terms as getConditionalOrder above: present once state is TRIGGERED and the close can be read, absent otherwise.
Lifecycle updates stream over the conditional_order_update websocket event. Those frames never carry triggeredOrder — read the close’s outcome from REST.

TWAP Orders

A TWAP (time-weighted average price) order executes a large order as a schedule of market child orders spread across a time window, averaging price over time instead of paying market impact in a single print. You submit one parent order and the matching engine plans, places, and tracks the child slices. See TWAP Orders for the execution model (slicing, randomization, catch-up, hard stop). All five methods are authenticated and reject delegated-agent sessions.
(tradingPairId: string, side: OrderSide, quantity: string, options: CreateTwapOrderOptions) => Promise<CreateTwapOrderResponse>
Create a TWAP parent order. quantity must be at least twice the pair’s minimum order size so it can be sliced.options (CreateTwapOrderOptions):
  • Window (required, exactly one): durationSeconds (number, or an int64 string the SDK normalizes to a JSON number; server default bounds 60 s – 30 days) or endTime (RFC 3339 UTC with a Z suffix — a non-UTC offset is rejected, not converted). startTime (RFC 3339 UTC) is allowed only alongside endTime. Client-side Zod validation enforces the exactly-one-of rule before the request is sent.
  • limitPrice?: string — parent-level cap; BUY children never execute above it, SELL never below.
  • slippageToleranceBps?: number — per-slice protective band (default 100, max 500).
  • randomize?: boolean — seeded ±30% size / ±30% timing jitter (default true).
  • executionStyle?: "TAKER" | "PASSIVE" (default "TAKER"). TAKER fires a banded MARKET child at every slot. PASSIVE rests a post-only LIMIT GTC child at the same-side touch, chases the touch with throttled reprices, and sweeps only the remainder as a banded MARKET child at the slot deadline — maker fills pay the pair’s maker fee with no application fee. Passive parents plan on a 60 s target slice interval instead of ~5 s, under the same 2,880-slice cap. See Passive Execution.
  • reduceOnly?: boolean — margin only; children inherit and clamp to the live position.
  • tradingMode?: "SPOT" | "MARGIN" (default "SPOT"). Margin parents also take marginAccountId?, riskBucketId?, marginMode?, and leverage? (required for normal margin TWAPs).
  • useMasterBalance?, strategyKey?: optional.
  • clientTwapId?: string — idempotency key, ≤36 chars, unique per user + application; a duplicate is rejected with 409.
  • Conditional activation (optional): triggerPrice? (string) and triggerDirection? ("ABOVE" | "BELOW") are both-or-neither and make the parent wait, PENDING, until the reference price reaches the level. A conditional parent takes durationSeconds only — startTime/endTime are rejected — because its window floats from the trigger instant. conditionalExpiry? (RFC 3339 UTC, Z suffix only) bounds the wait, is valid only alongside a trigger, must be in the future, and both defaults to and is capped at 30 days from creation. Client-side Zod enforces the both-or-neither, duration-only, expiry-requires-trigger, and expiry-range rules before the request is sent; the Z-suffix rule is enforced server-side. See Conditional TWAP.
Returns CreateTwapOrderResponse: twapOrderId, status, message, state (always PENDING at create), resolved marginAccountId / riskBucketId, plannedSlices, firstSliceAt, endTime.Errors: 400 (invalid window bounds, quantity too small or too large to slice, margin field mismatch, per-user active-TWAP cap reached, a trigger already satisfied at creation, a conditional create on a margin market that has no oracle mark yet, a reduceOnly margin parent whose risk bucket does not exist or is closed — a missing bucket keeps the usual remedy, while a bucket the request named explicitly and that is closed answers Risk bucket is closed; this TWAP order cannot reopen it — transfer collateral to the risk bucket first. A non-reduce-only margin parent is not refused in either case: it provisions the missing bucket, or funds the named closed one, at creation — or a validation refusal from that first-use provisioning, returned as First-use risk bucket provisioning failed: {detail}), 401 (auth required or delegated-agent session), 409 (duplicate clientTwapId), 429 (a parent costs one order-creation item against your account budget and your account family’s shared one; the retry interval arrives as details.retryAfter over REST and as a google.rpc.RetryInfo detail over gRPC), 500 (internal server or matching-engine failure, including an internal fault inside first-use bucket provisioning, sanitized to First-use risk bucket provisioning failed — that exact text is the gRPC status message, while REST wraps it as Internal server error: First-use risk bucket provisioning failed), and 503 / gRPC Unavailable (the matching engine is unreachable, or the create’s reply was lost in transport).Treat that 503 as an unknown outcome rather than a failure: the parent may already have been accepted, and for a first-use margin parent the isolated bucket’s seed is deliberately kept rather than released, because releasing it under a parent that exists would strand the schedule. Reconcile before retrying — list your TWAP parents, or resubmit with the same clientTwapId, which answers 409 if the original landed.Example:
(twapOrderId: string) => Promise<TwapOrder>
Fetch the owner’s TWAP parent read model with live progress: executedQuantity, executedNotional, averageFillPrice, progress (0–1), plannedSlices / slicesPlaced / slicesSkipped, nextSliceAt, state (PENDING / ACTIVE / COMPLETED / CANCELLED), and terminalReason (including end-of-window shortfall, and trigger expired for a conditional parent whose trigger never fired). Monitor the slice counters, not the state, for degraded execution. The read model also echoes executionStyle ("TAKER" | "PASSIVE") and, for a conditional parent, triggerPrice, triggerDirection, conditionalExpiry, and triggeredAt — read the armed window off the parent’s startTime / endTime rather than the create response, whose values are provisional until the trigger fires. (startAt / endAt are the twap_orders WebSocket payload’s names for the same pair; the REST read model uses startTime / endTime.)
(params?: ListTwapOrdersParams) => Promise<ListTwapOrdersResponse>
List the caller’s TWAP parents. Cursor (pageToken) pagination is the default; the deprecated page selects legacy page-number mode.Parameters (all optional):
  • state?: TwapOrderState
  • tradingPairId?: string
  • pageToken?: string — pagination cursor:
    • omitted — the SDK starts a cursor walk (pageToken=""), unless the deprecated page was passed
    • "" — start a cursor walk from the newest TWAP parent
    • a previous nextPageToken — resume the walk from that cursor
  • page?: number — deprecated: legacy page-number pagination; ignored whenever pageToken is present
  • pageSize?: number — max 100 in page-number mode, up to 1000 when pageToken is present
Returns ListTwapOrdersResponse:
  • orders: TwapOrder[]
  • total: number — in legacy page-number mode, bounded by the pagination reach: exact up to pageSize × 10,000 rows and saturating there, so a caller with more matching TWAP orders than page-number mode can page through reads the cap, not its lifetime total. 0 in cursor mode, which runs no COUNT.
  • nextPageToken: string — cursor for the next page; minted only while a further page exists, empty on the final cursor page and in legacy page-number mode. Follow it until it comes back empty; build “load more” UIs on it rather than “page N of M”.
  • page: number — deprecated: current page in legacy mode only; 0 in cursor mode
  • pageSize: number
Errors: 400 (invalid query parameters, a malformed pageToken, or a pageToken replayed against different filters than the ones that minted it), 401 (auth required), 429 (read rate limit — retry after retryAfter), 500.
(twapOrderId: string) => Promise<CancelTwapOrderResponse>
Cancel a TWAP parent. Atomic and immediate — child orders are IOC and never rest, so there is nothing to unwind; quantity already executed stands.Returns: { twapOrderId, status, message }
(twapOrderId: string) => Promise<GetTwapOrderTcaResponse>
Fetch the post-execution TCA (transaction cost analysis) report for a terminal TWAP parent — available once the parent is COMPLETED or CANCELLED. The report scores realizedAvgPrice (executedNotional / executedQuantity, gross of fees) against two references over the active window (windowStartAt to windowTerminalAt, the actual terminal time — never the planned end): the arrival price at the window start and the window-TWAP benchmark, both from the single series named by benchmarkSource (risk_mark_1m for marked pairs, ohlcv_1m_close fallback). slippageVsArrivalBps and performanceVsBenchmarkBps are signed bps at 4 decimal places — positive always means the execution beat the reference (BUY filled below it, SELL above it).Returns GetTwapOrderTcaResponse: always-present structural fields (twapOrderId, tradingPairId, state, side, totalQuantity, executedQuantity, shortfallQuantity, window bounds), plus six optional analytics fields that are omitted — key absent, not null — when that field cannot be computed honestly, each on its own condition: realizedAvgPrice comes straight from the fills and is absent only when nothing executed; arrivalPrice, benchmarkTwapPrice, and benchmarkSource are absent when no reference series qualified or the window sealed no minute bucket; slippageVsArrivalBps / performanceVsBenchmarkBps are absent when either of their inputs is. A parent that filled but had no qualifying reference series still reports realizedAvgPrice, just no scores — handle the absent-key case on every analytics field.Errors: 400 (invalid TWAP order ID format, or the parent has not reached a terminal state yet), 401 (auth required or delegated-agent session), 404 (unknown ID, or another user’s parent — byte-identical responses), 500 (internal server error).
Live progress streams on the authenticated twap_orders channel via sdk.ws.twapOrders.

Order Queries

Order reads and order WebSocket events expose version?: number, an opaque revision for the same order only. Merge a REST or subscription snapshot when snapshot.version >= local.version; the snapshot wins ties because several live events can share one sequencer step. Gaps are normal, versions from different orders are not comparable, and an absent version means unknown rather than zero. See the market-maker reconciliation recipe. Conditional-order reads and subscription snapshots also expose version?: number, but live conditional events never carry it. Compare versioned snapshots for the same conditional order with >= and apply live updates without version ranking.
(params?: GetPaginatedOrdersParams) => Promise<GetPaginatedOrdersResponse>
Query orders with filters, cursor-paginated by default. Legacy page-number (offset) pagination is deprecated but still available by passing page.Every kind of order comes back in one stream sorted by timestamp — book orders, TWAP parents and conditional orders. There is no separate open-orders call: filter status to ["SUBMITTED", "PARTIALLY_FILLED"] for the working set across all three. orderType names the kind and the kind-specific detail hangs off the matching field:TWAP and CONDITIONAL are response-only: both kinds are created through their own endpoints, and createOrder still takes LIMIT or MARKET.A CONDITIONAL row whose conditional has triggered reports the order it fired into rather than its own state: quantity is the size the leg resolved to; filledQuantity, averageFillPrice, quoteVolume, filledAt, cancelledAt and expiredAt are the close’s own; and status is the close’s current status, copied verbatim — SETTLED for a settled market leg and FILLED in the window before settlement, SUBMITTED or PARTIALLY_FILLED for a LIMIT leg still resting, CANCELLED whenever the remainder was cut (a MARKET or IOC leg that filled part of its quantity lands here too, with a nonzero filledQuantity), EXPIRED for a lapsed LIMIT leg. The status filter applies the same rule, so status: "SETTLED" returns exactly the triggered rows whose close has filled and settled. A triggered row whose close cannot be read keeps the older rendering (a synthesized FILLED with filledQuantity: "0").Aggregating a page needs two different rules. The fee fields stay undefined on the CONDITIONAL row — the close’s own row carries them, and conditional.triggeredOrder.totalTakerFees repeats the total — so summing fees across a whole page counts each exit once. Quantities are the opposite: the close is listed again as its own MARKET or LIMIT row, so sum quantity or quoteVolume over those rows only, or the triggered pair double-counts. That close carries conditionalOrderId back to the conditional, so the two rows can be paired in either direction.Parameters: all optional
  • status?: OrderStatusFilter — a single OrderStatus or an array (e.g. ["SUBMITTED", "PARTIALLY_FILLED"]), sent as one request
  • tradingPairId?: string
  • tradingMode?: "SPOT" | "MARGIN"
  • marginAccountId?: string
  • pageSize?: number — items per page; max 1000 in cursor mode (the default), max 100 in legacy page-number mode
  • pageToken?: string — pagination cursor:
    • omitted — the SDK starts a cursor walk (pageToken=""), unless the deprecated page was passed
    • "" (empty string) — start a cursor walk over full history (hot and archived rows merged), newest first (or oldest with orderBy: "ASC")
    • a previous nextPageToken — resume the walk from that cursor
  • page?: number — deprecated: legacy page-number pagination over the recent hot window only; ignored whenever pageToken is present
Returns: GetPaginatedOrdersResponse:
  • orders: Order[] — historical orders
  • nextPageToken: string — the cursor for the next page; non-empty whenever a page returns rows, empty when the walk is exhausted (a zero-row page) or in legacy page-number mode
  • pageSize: number — items per page
  • total, totalPages: number — the item count and page count matching the filter, populated in both modes and exact up to the server ceiling (10,000), saturating there. A lower bound when totalCapped is true.
  • totalCapped: boolean — true when more than the ceiling matched, so the count stopped there and total/totalPages are a lower bound (“10,000+”); false when total is exact (including exactly the ceiling).
  • page: number — deprecated: current page in legacy page-number mode only; 0 in cursor mode. Build “load more” UIs on nextPageToken instead of “page N of M”.
Example (every working order, of every kind):
Example (walk full order history):
(params?) => AsyncGenerator<Order>
Walk full order history with cursor pagination, yielding one order at a time. Accepts the getPaginatedOrders filters plus pageSize; the cursor is managed internally.
(orderId: string) => Promise<GetOrderResponse>
Get specific order details.An order the engine placed for a take-profit or stop-loss trigger — including one the book then rejected — carries conditionalOrderId, the conditional that fired it, so a close in order history can be attributed without scanning the conditional list. It is absent on every order you placed yourself, on TWAP slice children (those carry parentOrderId), and on triggered closes written before the field existed: there is no backfill, so absence on an older close means unknown, not placed by hand. getPaginatedOrders carries it on the same terms; no order WebSocket event or snapshot row does, so a close first seen over the socket acquires the field on the next REST read.

Fee Simulation

Simulate fees before placing an order to understand exact costs.
(params: SimulateFeeParams) => Promise<SimulateFeeResponse>
Calculate exact fees for an order before placing it. Requires authentication.Parameters:
  • tradingPairId: string - Trading pair UUID
  • side: “BUY” | “SELL” - Order side
  • price: string - Price per unit
  • quantity: string - Quantity to trade
  • orderType?: "LIMIT" | "MARKET" - Order type (default: "LIMIT"). MARKET orders include a slippage buffer in the lock amount.
  • slippageToleranceBps?: number - Slippage tolerance in basis points (0–1000); only tightens the protective band, never widens it. Only valid when orderType is "MARKET" (rejected otherwise). Default: 1000 (10%), matching the market-order price band.
Returns:
  • notional: string - Total order value (price × quantity)
  • monacoTakerFee: string - Monaco protocol taker fee
  • monacoTakerFeeBpsExact: string | null - Tier-resolved Monaco taker rate as a decimal bps string (e.g. "6.5") — the exact rate the ledger charges this caller, equal to monacoTakerFee / notional. Prefer this over the integer field below
  • monacoMakerRebateBpsExact: string | null - Tier-resolved Monaco maker rebate as a decimal bps string (negative = rebate, e.g. "-1") — the exact rate the ledger credits this caller
  • monacoTakerFeeBps: number - Deprecated. Whole-bps taker rate; an integer cannot carry fractional tiered rates (e.g. 6.5), so this echoes the flat trading-pair column, not the tier-resolved rate. Use monacoTakerFeeBpsExact or fees.getMyFeeTier
  • monacoMakerRebate: string - Monaco maker rebate (negative = rebate)
  • monacoMakerRebateBps: number - Deprecated. Whole-bps maker rebate; same integer limitation as above. Use monacoMakerRebateBpsExact or fees.getMyFeeTier
  • applicationTakerFee: string - Application taker fee
  • applicationTakerFeeBps: number - Application fee in basis points
  • totalTakerFees: string - Total fees for taker (monaco + application)
  • takerTotalPayment: string - Total amount taker must pay
  • makerTotalReceipt: string - Total amount maker receives
  • buyOrderLockAmount: string | null - Amount locked for BUY orders
  • maxQuantity: string | null - Maximum quantity affordable at the given price, accounting for fees (null if not authenticated or balance unavailable)
  • maxQuantityRaw: string | null - maxQuantity in RAW (smallest-unit) format
  • slippageToleranceBps: number | null - Slippage tolerance used in the calculation, echoed back for MARKET orders (null for LIMIT orders)
Example (LIMIT):
Example (MARKET with slippage):

Fee Tier

Look up your current volume-based fee tier and a pair’s full schedule.
(params: GetMyFeeTierParams) => Promise<GetMyFeeTierResponse>
Return the authenticated caller’s current fee tier, rolling 14-day volumes, and the requested pair’s six-row fee schedule. Requires authentication.Fee tiers are volume-based and recalculated daily from a trailing 14-day weighted volume (14d perp + 2.5 × 14d spot). See Fees for the tier tables.Parameters:
  • tradingPairId: string - Trading pair UUID whose fee schedule to return
Returns:
  • currentTierLevel: number - Resolved tier, 1 (lowest volume) through 6 (highest)
  • weightedVolume14d: string - Weighted 14-day volume (perp + 2.5× spot) used to resolve the tier, in whole USD (e.g. "5000000" = $5 M)
  • spotVolume14d: string - Rolling 14-day spot volume, in whole USD
  • perpVolume14d: string - Rolling 14-day perp volume, in whole USD
  • volumeToNextTier: string | null - Additional weighted volume needed to reach the next tier; omitted at tier 6
  • nextTierLevel: number | null - Next tier level; omitted at tier 6
  • feeSchedule: FeeTierScheduleRow[] - The pair’s six rows, ascending by tier. Each row: tierLevel (number), minVolumeThreshold (string — weighted 14-day volume floor in quote/USD units), makerFeeBps (string — human bps, negative = rebate), takerFeeBps (string — human bps)
Example: