For the complete documentation index, see llms.txt. This page is also available as Markdown.

WebSocket Order Entry API Reference

Download the current mainnet contract: Order Entry AsyncAPI spec. This download describes the API currently available at that endpoint, which may differ from the version described in this guide. For the API 3.6.2 contract documented here, use the immutable canonical spec source.

Overview

The Reya DEX WebSocket Order Entry API v2 is a request/response surface for placing, modifying, and cancelling orders — and managing an account-scoped cancel-on-disconnect switch — over a persistent WebSocket connection. It carries the same operations and payload bodies as the REST /v2 endpoints (POST /v2/createOrder, POST /v2/modifyOrder, POST /v2/cancelOrder, POST /v2/cancelAll, POST /v2/cancelAllAfter), with lower per-operation overhead and id-correlated responses on the same channel.

Payload bodies are reused verbatim from REST. Request and response envelopes are id-correlated; the server replies on the same connection with a frame carrying the same id the client sent.

This surface is order-entry only. For real-time market data, position updates, and fill streaming, see the WebSocket Info API Reference. The recommended integration runs both connections in parallel: this surface for order entry, the streaming surface for market and account updates.

Server Endpoints

Production Environment

  • URL: wss://ws-exec.reya.xyz

  • Protocol: WSS

  • Description: Production WebSocket order-entry server for live trading

For integration testing against the same contract, use devnet1. See Environments for each environment's endpoints and signing values.

Connection & Auth Model

The connection itself is anonymous — no handshake, no login, no API key. There is no concept of a session-bound wallet identity.

Authentication is per-frame: every order-bearing request carries an EIP-712 signature in its payload (signature, nonce, and deadline — the required signature-validity timestamp; GTT orders additionally carry an expiresAfter lifetime). createOrder, modifyOrder, and cancelAllAfter also carry signerWallet; cancelOrder recovers the signer from the signature. The server validates the signature against the order contents on every request — identical to the REST /v2/createOrder etc. body shape. See Signatures and Nonces for the signing model; both transports use the same scheme and the same Python SDK helpers.

A consequence of per-frame authentication is that a single WebSocket connection can carry orders signed by multiple different signerWallet values — useful for integrators operating multiple subaccounts on one connection.

Choosing WebSocket instead of REST does not change order semantics. Account-operation allowances are shared across both transports, with a separate allowance for cancelAllAfter. See Rate Limits for account, message and IP limits. Production Order Entry access is restricted to approved market-maker source IPs; provide your egress IPs to the Reya team during onboarding.

Message Structure

All WebSocket messages follow a standardized envelope structure with a type discriminator and a client-chosen id for correlation.

Request Envelope (Client → Server)

Components

  • type (string, required): One of createOrder, modifyOrder, cancelOrder, cancelAll, cancelAllAfter, ping. (pong is server-only — see Heartbeats.)

  • id (string, required): Client-chosen correlation identifier. Must be unique across in-flight requests on the connection — see In-Flight id Uniqueness below.

  • payload (object, required for createOrder / modifyOrder / cancelOrder / cancelAll / cancelAllAfter): Operation-specific request body, byte-identical to the corresponding REST endpoint's request body.

Response Envelope (Server → Client)

or, on failure:

Components

  • type (string, required): Echoes the request type.

  • id (string, required): Echoes the request id.

  • ok (boolean, required): true for success, false for failure.

  • payload (object, required when ok = true, forbidden when ok = false): Operation-specific success body, byte-identical to the REST 200 response body.

  • error (object, required when ok = false, forbidden when ok = true): See Error Catalog for the shape and possible codes.

Top-Level Error Envelope (Server → Client)

The server emits a top-level error envelope when it cannot parse a request at all (malformed JSON, unknown type, in-flight id collision, internal failure). Connection stays open. Operation-specific errors instead come back as { ok: false, error } on the corresponding response envelope correlated by id.

  • id is present when the offending request carried one (e.g. for DUPLICATE_REQUEST_ID); absent for frame-level errors (e.g. unparseable JSON) where the server has no id to echo.

Heartbeats

The heartbeat / connection-liveness mechanism is documented in detail on its own page — see Heartbeats. Short version: protocol-level pings handle liveness automatically, no application-level code is required on the client.

Operations Reference

createOrder

Purpose: Place spot or perp LIMIT orders (IOC, GTC, or GTT), or arm perp STOP_LOSS / TAKE_PROFIT trigger orders. Identical body and semantics to REST POST /v2/createOrder.

Request Envelope (spot LIMIT GTC):

Request Envelope (perp IOC):

Request Envelope (perp GTT — good-til-time, post-only):

Success Response (rested without an immediate fill):

Success Response (IOC filled on entry):

Error Response:

Data Type — CreateOrderRequest payload
  • exchangeId (integer, required): Reya exchange identifier. Currently always 1.

  • symbol (string): Trading symbol (e.g. WETHRUSD, ETHRUSDPERP).

  • accountId (integer, required): Reya account ID placing the order.

  • isBuy (boolean, required): true for a buy, false for a sell.

  • limitPx (string, required): Limit price as a decimal string.

  • qty (string): Order quantity as a decimal string. Required for LIMIT orders. Omit for STOP_LOSS / TAKE_PROFIT orders — a trigger has no quantity; it protects the whole live position at fire time (the signature carries the full-position sentinel — see Trigger Orders (SL/TP)).

  • orderType (string, required): LIMIT, STOP_LOSS (stop-loss), or TAKE_PROFIT (take-profit). Triggers arm durably and fire against the mark price into the chosen TIF. See Trigger Orders (SL/TP).

  • timeInForce (string, required): IOC, GTC, or GTT, on every create including triggers. For a trigger this chooses the fired child's behaviour. GTT additionally requires expiresAfter.

  • triggerPx (string): Trigger price. Required for STOP_LOSS / TAKE_PROFIT orders.

  • reduceOnly (boolean): Whether the order is reduce-only. Perp IOC only — required for perp IOC orders, and not supported for perp GTC / GTT, spot, or STOP_LOSS / TAKE_PROFIT orders. For unsupported request types, omit the REST/WS JSON field; the signer encodes the on-chain value as false.

  • postOnly (boolean, optional): Maker-only intent — the order may only add liquidity, never take it. Valid on GTC / GTT (spot and perp) and rejected on IOC. A STOP_LOSS / TAKE_PROFIT create must omit it, including false.

  • signature (string, required): EIP-712 signature over the order. See Signatures and Nonces.

  • nonce (string, required): Order nonce.

  • signerWallet (string, required): Address that produced the signature.

  • deadline (integer, required): Signature-validity timestamp (seconds since epoch). The order is rejected at entry if deadline has already passed (ORDER_DEADLINE_PASSED_ERROR). For IOC orders it must also be within 600 seconds of now (ORDER_DEADLINE_TOO_HIGH_ERROR); GTC / GTT are not capped. Distinct from expiresAfter: deadline bounds how long the signature is valid; expiresAfter is a GTT order's own lifetime.

  • expiresAfter (integer): The order's lifetime — expiration timestamp in seconds since epoch. Required only for GTT orders, where it must be strictly greater than deadline. For GTC/IOC, including triggers, omit it. A GTT trigger and its child share the same expiry and stop early to allow time for settlement; see Trigger Orders (SL/TP).

  • clientOrderId (string, optional): Echoed back in the response; useful for client-side correlation independent of the server-issued orderId.

Data Type — CreateOrderResponse payload
  • status (string, required): One of OPEN, FILLED, CANCELLED.

  • execQty (string, optional): Executed quantity in this order update.

  • cumQty (string, optional): Total executed quantity across all fills where the order is active.

  • avgFillPx (string, optional): Quantity-weighted average price across all fills of the order, excluding fees; corresponds to cumQty. Omitted before the first fill. See Average fill price for rounding and lifecycle rules.

  • orderId (string, required): Server-issued order ID. Issued for all order types — including perp IOC: the matching engine assigns a non-zero orderId even though an IOC leaves no resting state.

  • clientOrderId (string, optional): Echoes the request's clientOrderId.

  • cancelReason (CancelReason, optional): Present when status is CANCELLED and the engine supplied a machine-readable reason.

  • cancelReasonMessage (string, optional): Human-readable explanation for cancelReason.

  • firstFillId (string, optional): Identifier of the first fill this order produced on entry. Together with fillCount, identifies a contiguous fill range. Absent if the order did not fill on entry.

  • fillCount (integer, optional): Number of fills this order produced on entry. Present only with firstFillId.

modifyOrder

Purpose: Amend one live order in place: a resting LIMIT (GTC or GTT; spot or perp) or an armed perp STOP_LOSS / TAKE_PROFIT. The order keeps its orderId and clientOrderId. Identical body and semantics to REST POST /v2/modifyOrder.

Full restate. The payload carries the complete post-modify OrderDetails state plus a target id — restate every value, even unchanged ones. It reuses the same signed EIP-712 field universe as createOrder, but not always the same JSON field set: trigger create and modify both require timeInForce and must omit reduceOnly and postOnly, including false; both Boolean fields are reconstructed as fixed false for signing. The modifiable set is class-split: limitPx, qty, postOnly, and expiresAfter for a LIMIT order; only limitPx and triggerPx for a STOP_LOSS / TAKE_PROFIT trigger. All other fields are immutable and must be restated at the live order's values. Signing reuses the OrderDetails envelope with a fresh nonce, exactly as createOrder. For the complete modify lifecycle — modifiable-vs-immutable fields, targeting, crossing behavior, queue-priority effects, and the full error set — see Modifying a resting order. The field-level rules for this WebSocket payload are in the schema block below.

Request Envelope (re-price + resize, targeting by orderId):

Success Response (rested after modify, preserving earlier fills of 0.6 at 40000):

Success Response (alternatively, the modify crossed and filled the remaining 0.4 at 41000):

Error Response:

Data Type — ModifyOrderRequest payload
  • orderId (string): Reya-issued order ID of the order to modify. If present, this is the canonical lookup key; clientOrderId, when also present, restates the resting order's immutable client id.

  • clientOrderId (string): Restated client-provided ID from the original createOrder. Used as the lookup key only when orderId is absent, and then it must be non-zero. If orderId is present, this field restates the resting order's immutable client id for signing; omit it when the resting order has no client id. The modification cannot assign a new clientOrderId.

  • symbol (string, required): Market symbol for the order.

  • accountId (integer, required): Account ID that owns the order. Immutable; must match the resting order.

  • exchangeId (integer, required): On-chain OrderDetails.exchangeId. Restated immutable — must match the resting order (mismatch → INPUT_VALIDATION_ERROR).

  • isBuy (boolean, required): Order side. Restated immutable — must match the live order. For LIMIT, it sets the sign of the E18 qty; for a trigger it sets the sign of the raw full-position sentinel.

  • orderType (string, required): On-chain OrderDetails.orderType. Restated immutable: LIMIT, STOP_LOSS, or TAKE_PROFIT; a modify cannot change the order class.

  • timeInForce (string, required): Restated immutable. Send GTC or GTT for a LIMIT; a modify cannot flip GTC ↔ GTT. For an armed trigger, restate the originally chosen IOC/GTC/GTT. A fired child is cancel-only.

  • triggerPx (string, optional): On-chain OrderDetails.triggerPrice. Modifiable — re-prices an armed STOP_LOSS / TAKE_PROFIT trigger in place. Required on a trigger modify; omit for a LIMIT order.

  • reduceOnly (boolean, required for LIMIT): On-chain OrderDetails.reduceOnly. Restated immutable for LIMIT. Omit for a trigger, including false; its signed value is fixed false.

  • limitPx (string, required): Post-modify worst acceptable execution price. Send the complete intended value even when unchanged. On a LIMIT order, changing it loses queue priority and a non-post-only crossing modify executes immediately. On an armed trigger, the new limit is band-checked for its future child.

  • qty (string, conditionally required): Required for a LIMIT: the post-modify total order quantity (not remaining), which must be strictly greater than cumQty (else MODIFY_QTY_BELOW_FILLED_ERROR). A decrease at an unchanged limitPx preserves queue priority; an increase loses it. Omit for a trigger; the signer restates the raw full-position sentinel.

  • postOnly (boolean, required for LIMIT): The post-modify maker-only flag. For a LIMIT, if true and the order would cross, the modify is rejected with POST_ONLY_WOULD_CROSS_ERROR and the resting order is unchanged. Omit for a trigger, including false; its signed value is fixed false.

  • expiresAfter (integer, optional): Post-modify order lifetime in seconds since epoch. For a LIMIT, omit for GTC and send a future timestamp greater than deadline for GTT. For a GTT trigger, restate its original expiry; omit for GTC/IOC and sign 0. A trigger's expiry cannot be amended.

  • signature (string, required): Fresh EIP-712 signature over the full restated order state — all fields (modifiable + restated immutables) exactly as sent on the wire, using the same OrderDetails envelope as createOrder. See Signatures and Nonces.

  • nonce (string, required): Monotonically increasing per-signer nonce. A fresh nonce is required for every modify; replays are rejected with INVALID_NONCE_ERROR.

  • signerWallet (string, required): Address that produced the signature. Not modifiable; must match the resting order's signer.

  • deadline (integer, required): Signature-validity timestamp (seconds since epoch). Distinct from expiresAfter (the order's lifetime).

Data Type — ModifyOrderResponse payload

Modify response fields are the same order-outcome fields as CreateOrderResponse; orderId is the ID the order had before the modification.

  • status (string, required): One of OPEN, FILLED, CANCELLED. OPEN for a partial fill leaving a remainder resting; FILLED for a complete fill when the modify crossed.

  • execQty (string, optional): Quantity executed by this modification. Present only when the modify crossed and filled immediately; absent when the modified order rested. Use cumQty for lifetime filled quantity.

  • cumQty (string, optional): Total executed quantity across the order's lifetime, including fills from before the modification.

  • avgFillPx (string, optional): Quantity-weighted average price across all maker and taker fills of the order, excluding fees, including fills before this modification. Preserved when the modify produces no new fill; omitted if the order has never filled. See Average fill price for rounding and lifecycle rules.

  • orderId (string, required): Modified order ID — unchanged by the modification.

  • clientOrderId (string, optional): Client-provided order ID preserved from order creation.

  • cancelReason (CancelReason, optional): Present when status is CANCELLED and the engine supplied a machine-readable reason.

  • cancelReasonMessage (string, optional): Human-readable explanation for cancelReason.

  • firstFillId (string, optional): Identifier of the first fill this modify produced. Together with fillCount, identifies a contiguous fill range. Absent if the modify did not fill immediately.

  • fillCount (integer, optional): Number of fills this modify produced. Present only with firstFillId.

cancelOrder

Purpose: Cancel a previously placed order by orderId, or by non-zero clientOrderId when orderId is absent. Identical body and semantics to REST POST /v2/cancelOrder.

Request Envelope:

Success Response:

Data Type — CancelOrderRequest payload
  • orderId (string): Reya-issued order ID to cancel. Provide orderId, or provide a non-zero clientOrderId when orderId is absent.

  • clientOrderId (string): Client-provided order ID to cancel. Used only when orderId is absent, and then it must be non-zero. Omit it when cancelling by orderId or when the order has no client id.

  • accountId (integer, required): Account ID that owns the order.

  • symbol (string, required): Market symbol for the order.

  • signature (string, required): EIP-712 signature over the cancellation.

  • nonce (string, required): Cancel nonce.

  • deadline (integer, required): Signature-validity timestamp (seconds since epoch). Must be within 600 seconds of now (ORDER_DEADLINE_TOO_HIGH_ERROR).

Data Type — CancelOrderResponse payload
  • status (string, required): Always CANCELLED on success.

  • orderId (string, required): The cancelled order ID.

  • clientOrderId (string, optional): Echoes the request's clientOrderId.

cancelAll

Purpose: Mass-cancel all open orders for an account on a given market (spot or perp), or across all markets if symbol is omitted. Identical body and semantics to REST POST /v2/cancelAll. Per-market mass-cancel is supported for both spot and perp markets.

Request Envelope:

Success Response:

Data Type — MassCancelRequest payload
  • accountId (integer, required): Account ID to cancel orders for.

  • symbol (string, optional): Symbol to cancel orders for. If omitted, cancels all orders for the account across all markets.

  • signature (string, required): EIP-712 signature.

  • nonce (string, required): Mass-cancel nonce.

  • deadline (integer, required): Signature-validity timestamp (seconds since epoch). Must be within 600 seconds of now (ORDER_DEADLINE_TOO_HIGH_ERROR).

Data Type — MassCancelResponse payload
  • cancelledCount (integer, required): Number of orders that were cancelled.

cancelAllAfter

Purpose: Arm, refresh, or disarm an account-scoped dead-man's switch (cancel-on-disconnect). Identical body and semantics to REST POST /v2/cancelAllAfter. Send a signed cancelAllAfter with a timeoutMs in [5000, 60000] to arm/refresh a countdown, or 0 to disarm; if the countdown elapses without a refresh, the matching engine cancels every open order on the account except protective stops. The switch is transport-agnostic (REST and ws-exec share one account-level timer) and is not tied to the connection — closing the WebSocket neither fires nor disarms it, and only another cancelAllAfter refreshes it. For the full behavior — bounds, protective-stops exemption, trigger semantics, and recommended heartbeat use — see Cancel-on-Disconnect. The field-level rules are in the schema block below.

The EIP-712 envelope signs accountId, timeoutMs, nonce, and deadline. Note that deadline is the signature-validity window (unix seconds), not the trigger time — the trigger time is timeoutMs relative to server receipt.

Request Envelope (arm a 30-second countdown):

Success Response (armed — echoes timeoutMs and the triggerAt fire time):

Success Response (disarm — timeoutMs: 0, no triggerAt):

Data Type — CancelAllAfterRequest payload
  • accountId (integer, required): Account ID whose open orders are covered by the countdown.

  • timeoutMs (integer, required): Countdown duration in milliseconds. 0 disarms; any non-zero value must be within [5000, 60000] and (re-)arms a fresh countdown of that duration, replacing any previously armed one (re-arming with the same value is the refresh/heartbeat). Out-of-range values are rejected with INPUT_VALIDATION_ERROR.

  • signature (string, required): EIP-712 signature over the CancelAllAfter envelope (signs accountId, timeoutMs, nonce, deadline). See Signatures and Nonces.

  • nonce (string, required): Monotonically increasing per-signer nonce. A fresh nonce is required on every arm/refresh/disarm call; replays are rejected with INVALID_NONCE_ERROR.

  • signerWallet (string, required): Address that produced the signature.

  • deadline (integer, required): Signature-validity timestamp (seconds since epoch) — not the trigger time. The countdown is timeoutMs relative to server receipt.

Data Type — CancelAllAfterResponse payload
  • accountId (integer, required): Account ID the countdown applies to, echoed from the request.

  • timeoutMs (integer, required): Effective countdown duration in milliseconds; 0 means the switch is now disarmed.

  • triggerAt (integer, optional): Milliseconds POSIX timestamp at which the cancel-all fires if the countdown is not refreshed before then (server receipt time + timeoutMs). Omitted when timeoutMs is 0 (disarmed).

ping / pong

Purpose: Optional client-initiated application-level liveness/RTT probe. The client sends {type:"ping", id?}; the server replies with {type:"pong", id?} echoing the optional id. See Heartbeats for the full description — when to use it, when not to, and how it relates to the protocol-level liveness mechanism that keeps the connection alive automatically.

Error Catalog

Account-operation and resting-order rejections use the codes below. An optional positive retryAfterMs gives the minimum wait after an account-operation rate rejection. Message-rate limits instead close the connection with 4029; they do not produce a per-operation error response. See Rate-limit errors and recovery.

Every error envelope (both per-operation {ok: false, error} and top-level error) carries a RequestError-shaped object:

The error field is one of the codes below. Per-operation responses ({ok: false, error} on createOrder / modifyOrder / cancelOrder / cancelAll / cancelAllAfter) use codes from the Order Management group, shared 1:1 with REST. Top-level error envelopes use codes from the Framing Layer group exclusively; these only make sense for a streamed envelope protocol and never appear in REST responses.

Order Management Codes (shared with REST)

Code
When emitted
Client action

SYMBOL_NOT_FOUND_ERROR

The symbol in the payload doesn't resolve to a known market.

Refresh market definitions via REST GET /v2/perpMarketDefinitions.

NO_ACCOUNTS_FOUND_ERROR

The accountId doesn't exist or isn't owned by the signer.

Verify account configuration.

INPUT_VALIDATION_ERROR

Generic body-validation failure (missing field, wrong type, illegal value). Also a modifyOrder that restated an immutable field with a value that doesn't match the resting order, or whose expiresAfter is inconsistent with the order's timeInForce.

Fix the request body; consult the human-readable message.

RATE_LIMITED_ERROR

The account exhausted the allowance for this operation group.

Respect retryAfterMs when present and back off; see Rate Limits.

INSUFFICIENT_BALANCE_ERROR

Available collateral is insufficient for the order.

Reduce size or add collateral.

OPEN_ORDER_COUNT_EXCEEDED_ERROR

The account-wide or per-market resting-order count cap is reached.

Cancel resting orders or wait for fills before placing another GTC/GTT order.

OPEN_ORDER_NOTIONAL_EXCEEDED_ERROR

A create or modify would exceed the account's gross resting-order notional cap.

Reduce the proposed notional or release capacity through cancellations or fills.

CAPACITY_LIMITED_ERROR

Venue load temporarily restricts creates and modifies.

Back off with jitter; cancellations and countdown requests retain their own allowances.

PRICE_QTY_BOUNDS_ERROR

Price or quantity is outside the market's accepted bounds.

Refresh market definitions and adjust price/quantity.

SERVICE_DISABLED_ERROR

Order entry is disabled for this market or instrument.

Stop submitting until the market is re-enabled.

UNAUTHORIZED_ACCOUNT_ERROR

The signer is valid but is not authorized for the target account/order.

Check account ownership and trading-key permissions.

TRADING_HALTED_ERROR

A createOrder reached the matching engine while it was shutting down for a restart. Not returned when settlement falls behind: that pauses matching and returns CROSSING_ORDERS_TEMPORARILY_UNAVAILABLE_ERROR instead.

The order was not accepted. Back off, then re-sign with a fresh nonce and resubmit if it is still wanted.

DUPLICATE_CLIENT_ORDER_ID_ERROR

A live order already uses the supplied clientOrderId.

Use a fresh client order id or reconcile the existing order.

ACCOUNT_BELOW_LIQUIDATION_MARGIN_ERROR

The account is already below liquidation margin, or its realised balance is below the chain floor.

Restore the margin / real-balance floor; ordinary reducing orders do not bypass it. Read message for the binding condition.

ACCOUNT_BELOW_INITIAL_MARGIN_ERROR

The proposed trade would leave the account below initial margin, including the settlement buffer.

Reduce size, add collateral, or submit a genuinely risk-improving order. Do not retry unchanged.

OPEN_INTEREST_CAP_ERROR

The market's open-interest cap is reached.

Wait for market open interest to fall or reduce exposure; do not loop retries.

OPEN_INTEREST_BUDGET_ERROR

The tighter budget covering matched-but-unsettled fills is exhausted.

Let pending settlement clear, then retry deliberately; do not blindly loop.

REDUCE_ONLY_CONDITION_NOT_MET_ERROR

A reduce-only order would not strictly reduce the current position.

Reconcile the position, side, and size, then re-sign a correcting order.

CROSSING_ORDERS_TEMPORARILY_UNAVAILABLE_ERROR

A createOrder or modifyOrder would cross immediately while crossing orders are temporarily unavailable: the exchange cannot run pre-trade risk checks for it, or matching is paused. Nothing is placed; a rejected modify leaves the order unchanged.

Back off, then retry the crossing request. Cancels remain available. During a matching pause, non-crossing creates and modifies and trigger placement keep working; while risk checks are unavailable, other admission still requires its own risk data to be ready.

TRIGGER_IOC_MUST_NOT_EXPIRE_ERROR

An IOC trigger carries an expiry. This invalid combination can also return INPUT_VALIDATION_ERROR.

Omit expiresAfter for IOC and re-sign.

TRIGGER_LIMIT_OUTSIDE_BAND_ERROR

limitPx is outside the permitted trigger-price band, or stops are unavailable on the market.

Read message: move the limit closer and re-sign for a price-band rejection; contact Reya if stops are unavailable.

TRIGGER_ALREADY_EXISTS_ERROR

An armed trigger of the same type already exists for this account and market.

Modify or cancel the existing trigger before creating another of that type.

ORDER_EXPIRES_TOO_SOON_ERROR

A GTT expiresAfter is still in the future but leaves too little time for settlement.

Re-sign with a later expiresAfter; do not retry the same payload.

CREATE_ORDER_OTHER_ERROR

Generic matching-engine create failure not covered by a more specific code.

Read message for the underlying reason; do not infer a settlement result from this catch-all.

CANCEL_ORDER_OTHER_ERROR

Generic cancelOrder failure not covered by a more specific code.

Read message.

ORDER_DEADLINE_PASSED_ERROR

deadline (the signature-validity timestamp) is in the past.

Re-sign with a fresh deadline.

ORDER_DEADLINE_TOO_HIGH_ERROR

deadline is more than 600 seconds in the future. Enforced on IOC creates and on all cancels (cancelOrder / cancelAll); GTC / GTT creates are not capped.

Use a deadline within 600 seconds of now.

INVALID_NONCE_ERROR

Nonce is not strictly monotonic for this signer, or was already used.

Re-sign with a fresh monotonic nonce.

CANCEL_ALL_AFTER_OTHER_ERROR

A matching-engine-side cancelAllAfter failure with no more specific code. (A non-zero timeoutMs outside [5000, 60000] is rejected with INPUT_VALIDATION_ERROR, not this code.)

Read message; for an out-of-band timeoutMs, send 0 or a value in range.

SERVICE_UNAVAILABLE_ERROR

The service was temporarily unavailable. The request was not accepted.

Back off and re-sign with a fresh nonce, retaining the same clientOrderId when supplied.

ORDER_OUTCOME_UNKNOWN_ERROR

API 3.6.2: the operation may have been applied.

Reconcile state and executions before resubmitting; never replace an unresolved attempt with a fresh nonce. See Handling ambiguous outcomes.

UNAUTHORIZED_SIGNATURE_ERROR

The recovered signer is not authorized to act on the accountId.

Verify the signer wallet is in the account's permissioned-addresses list on-chain.

NUMERIC_OVERFLOW_ERROR

A numeric field exceeds the allowed uint64 / int256 range.

Fix the request body.

POST_ONLY_WOULD_CROSS_ERROR

A post-only order (on createOrder) or post-only modify (on modifyOrder) would cross or touch the best opposite price at entry. Nothing is placed; on a modify the resting order is left untouched.

Re-price the order so it rests as a maker, or drop postOnly to allow it to take.

ORDER_NOT_FOUND_ERROR

The orderId / clientOrderId targeted by a modifyOrder or cancelOrder does not resolve to a live resting order.

Verify the order is still resting (check GET /v2/wallet/{address}/openOrders).

EMPTY_MODIFY_ERROR

A modifyOrder whose post-modify state is identical to the order's current state — no field actually changed.

Send a modify that changes at least one of limitPx / qty / postOnly / expiresAfter / triggerPx.

MODIFY_QTY_BELOW_FILLED_ERROR

A modifyOrder qty (the total post-modify quantity) is not strictly greater than the order's already-filled cumQty.

Set qty above the filled amount, or cancel instead.

MODIFY_ORDER_OTHER_ERROR

A modifyOrder the matching engine can't apply — e.g. the signer isn't authorized for the account, or (for a trigger modify) a matching-engine-level trigger rule is violated.

Read message — the engine's reason is passed through. A fired protective child must be cancelled, not modified.

Framing Layer Codes (top-level error envelope only)

These codes appear only in the top-level error envelope, never inside a per-operation {ok: false} response.

Code
When emitted
Client action

MALFORMED_JSON

The frame body could not be parsed as JSON, or required envelope fields (type, id) are missing. Connection stays open.

Fix the client serializer.

UNKNOWN_TYPE

The frame's type field is not one of the accepted values. Connection stays open.

Verify the request type.

DUPLICATE_REQUEST_ID

The frame's id is already in-flight on this connection — i.e., the client sent a new request with an id whose response hasn't yet been emitted. Connection stays open; the new request is rejected, the original is unaffected.

Use a fresh id for each request (UUIDs work).

INTERNAL

The server hit an internal failure handling the frame. Connection stays open.

Retry; if the problem persists, contact support with the id.

SERVER_SHUTTING_DOWN

The service is restarting and is not accepting new requests.

Reconnect and reconcile unanswered requests before resubmitting; see Heartbeats.

TOO_MANY_INFLIGHT

The connection has too many un-acknowledged in-flight requests.

Throttle — wait for outstanding responses before sending more.

Data Types & Schemas

Enumeration Types

OrderType
  • LIMIT — Limit order (with timeInForce = IOC, GTC, or GTT).

  • STOP_LOSS — Stop-loss conditional order (perp).

  • TAKE_PROFIT — Take-profit conditional order (perp).

TimeInForce
  • IOC — Immediate or Cancel: fills immediately against the book, never rests.

  • GTC — Good Till Cancelled: rests on the book until filled or cancelled.

  • GTT — Good Till Time: rests until filled, cancelled, or its signed expiresAfter timestamp passes (which must be strictly later than deadline).

OrderStatus
  • OPEN — Order is resting in the book.

  • FILLED — Order is fully filled by the matching engine. This is the matching-engine status — a fill is only final once it settles on-chain; see Trade Settlement and Trade Busts.

  • CANCELLED — Order is cancelled.

Request-level rejects such as post-only-would-cross are returned as error responses (RequestErrorCode), not as an order status.

CancelReason
  • NO_LIQUIDITY — IOC executed zero quantity because no fillable liquidity was available at its limit.

  • IOC_REMAINDER — IOC partially filled and cancelled the unfilled remainder.

  • SELF_TRADE_PREVENTION — Order would have crossed the same account.

  • GTT_EXPIRED — GTT order expired.

  • USER_CANCEL — Explicit user cancel.

  • MASS_CANCEL — Explicit cancel-all.

  • CANCEL_ALL_AFTER — Cancel-on-disconnect timer fired.

Protective-stop lifecycle reasons (OCO_SIBLING_FIRED, PROTECTIVE_SELF_TRADE_SWEEP, POSITION_CLOSED, RISK_REJECTED) arrive on the Info stream; see Trigger Orders (SL/TP).

RISK_CANCELLED is delivered only on the WebSocket Info orderChanges stream when pre-trade risk cancels an already-resting order; it is never a create/modify response. FEED_RESET is an Info resynchronization signal; resynchronization currently uses close code 1012 instead. WebSocket Order Entry responses carry neither value. See the WebSocket Info API Reference.

For the complete enumeration of RequestErrorCode (per-operation errors) and WsExecErrorCode (top-level errors), see the Error Catalog above.

Connection Management

Reconnection Pattern

Reconnect with the usual exponential-backoff-with-jitter pattern any robust WebSocket client should use. The Reya-specific bits are:

  1. No subscription state to replay. There is no session-bound identity to restore — the next request authenticates itself via its EIP-712 signature just like the first one did.

  2. Verify in-flight requests via REST before resubmitting. Closing the WebSocket has zero persistent side effects on the order book itself, but an unanswered request may already have reached the matching engine and created, matched, modified, or cancelled an order. Check GET /v2/wallet/{address}/openOrders, orderHistory, and the relevant executions endpoint before retrying — otherwise you risk a duplicate action. See Idempotency (clientOrderId) for safe correlation; do not infer settlement merely from request acceptance.

For the meaning of WS close codes you'll see on onclose (1000, 1001, 1006, etc.), see What Happens When the Server Closes the Connection.

Service Restarts

Order Entry service restarts close connections with code 1001; reconcile any unanswered request. The Info WebSocket uses a 1012 resync close. Both are documented in Service restarts.

In-Flight id Uniqueness

Each id must be unique across in-flight requests on the connection. Once the server has emitted the corresponding response envelope, the id is free to reuse. Sending a fresh request with the same id as an in-flight one triggers a top-level DUPLICATE_REQUEST_ID error envelope; the original in-flight request is unaffected.

In practice, clients should generate a fresh id for every request (e.g. UUIDv4 or a monotonic counter prefixed with a session token).

Idempotency (clientOrderId)

For createOrder, the optional clientOrderId field is echoed back unchanged in the successful response and in any subsequent order-update events on the Info WebSocket. Use it for client-side correlation independent of the server-issued orderId — particularly useful when the response envelope is lost mid-flight and the client must reconcile state from Info-WebSocket updates after reconnect.

When supplied with a non-zero value, clientOrderId must be unique among live orders for the same signer wallet on the same market. A duplicate live clientOrderId is rejected with DUPLICATE_CLIENT_ORDER_ID_ERROR. Omit the field when you do not want a client tag; the signer encodes the omitted value as 0. This is live-order deduplication for correlation and safe retries, not exactly-once idempotency across all historical terminal orders.

Signatures and Nonces

All createOrder, modifyOrder, cancelOrder, cancelAll, and cancelAllAfter payloads carry an EIP-712 signature over the order contents. The shape of the signed message is identical to the REST /v2 endpoints — see Signatures and Nonces for the canonical reference. The Python SDK provides the helpers sign_order, sign_cancel_order, sign_mass_cancel, and sign_cancel_all_after to produce these signatures correctly. A modifyOrder reuses the same OrderDetails envelope as createOrder (sign_order), signed over the full post-modify order state with a fresh nonce.

The WebSocket transport does not add or change any signing requirement. Frames are signed by your wallet (or a permissioned trading key) at the payload level; the WebSocket connection itself is unauthenticated.

Differences vs REST

The WebSocket Order Entry surface is functionally equivalent to the corresponding REST endpoints, with transport-level differences:

Concern
REST
WebSocket Order Entry

Request body

CreateOrderRequest / ModifyOrderRequest / CancelOrderRequest / MassCancelRequest / CancelAllAfterRequest

Same — embedded as payload

Response body

CreateOrderResponse / ModifyOrderResponse / CancelOrderResponse / MassCancelResponse / CancelAllAfterResponse

Same — embedded as payload on ok: true

Success / failure

HTTP 200 vs 400 / 500

ok: true vs ok: false inside the frame

Error body

RequestError

Same — embedded as error on ok: false

Correlation

HTTP request/response pairing

Client-supplied id field

Heartbeat

n/a (stateless)

Protocol-level, automatic — see Heartbeats

Auth

EIP-712 signature in body

Same EIP-712 signature in same body

Idempotency

clientOrderId echoed

Same

Connection

Per-request

Persistent, multiplexed

When to use which:

  • REST — One-off requests, low frequency, simpler client integration, no need to maintain a long-lived connection.

  • WebSocket Order Entry — High-frequency order submission, lower per-request overhead (no TLS handshake per request), latency-sensitive integrations. Recommended for latency-sensitive integrations running together with the WebSocket Info API.

Python SDK Example

A worked example is included in the Python SDK 3.6.1.0 at examples/websocket/exec/ws_exec.py — a minimal quickstart that places a resting spot LIMIT GTC order and cancels it through the high-level ReyaWsExecClient (which handles the wire envelope, EIP-712 signing, and in-flight request dispatch for you).

After installing the pinned SDK, run from its checkout:

See the example's README for prerequisites (.env setup, funded test accounts).

Transport failures and retrying

See Handling ambiguous outcomes for the API 3.6.2 error codes and when to retry or reconcile. An unanswered request may have been applied.

Last updated