Skip to content

Order Endpoints

Place Limit Order

POST /orders

Authentication: EIP-712 Order signature

Request Body

{
  "owner_address": "0x...",
  "side": "bid",
  "amount": "1000",
  "price": "1.085",
  "order_type": "limit",
  "from_address": "0x...",
  "to_address": "0x...",
  "order_id": "00000000-0000-4000-8000-000000000001",
  "uuid_int": "6427948336465191935941739505432058208337171677044006212075520",
  "signature": "0x...",
  "expiration": 1713254400
}
Field Type Required Description
owner_address address Yes Wallet address of the order owner
side string Yes bid or ask
amount string Yes Quantity in natural units (base-token side)
price string Yes Price in natural units (quote per base)
order_type string Yes limit or market; no public IOC/FOK/post-only policy
from_address address Yes ERC-20 address of the market base token
to_address address Yes ERC-20 address of the market quote token (must differ from from_address)
order_id UUID string Yes Human-readable UUID4 order ID
uuid_int decimal string Yes Composite uint256 bound to order_id
signature hex string Yes EIP-712 Order signature
expiration integer Yes Unix timestamp deadline; must satisfy now < expiration <= now + 365 days - 300 seconds

fee_bps is optional (nonnegative uint48 integer, default 0) and is signed as feeBps. client_id is accepted by the request model but is not forwarded as an order identifier or idempotency key. Amount and price must be canonical decimal strings; use order preview before signing. The request also accepts order_type="market"; it does not expose IOC/FOK/post-only execution policies. Read current public capabilities from GET /config.

from_address and to_address identify the market, not the immediate spend direction. For a bid, you buy from_address using to_address; for an ask, you sell from_address for to_address. Resolve these addresses from GET /tokens.

Response

{
  "order_id": "00000000-0000-4000-8000-000000000001"
}

Preview an Order

POST /api/v1/orders/preview

Authentication: None. Preview validates public market precision and minimum input amounts; it does not reserve liquidity or check balances, self-trading or compliance.

Use the same fields as POST /orders, including order_id, uuid_int and expiration, but omit signature and client_id. fee_bps is optional and defaults to 0. A sample request:

{
  "owner_address": "0x...",
  "side": "bid",
  "amount": "1000.0",
  "price": "1.085",
  "order_type": "limit",
  "from_address": "0x...",
  "to_address": "0x...",
  "order_id": "00000000-0000-4000-8000-000000000001",
  "uuid_int": "6427948336465191935941739505432058208337171677044006212075520",
  "expiration": 1800000000
}

Response

Field Description
ok true on success
symbol, side Resolved market and side
normalized_amount, normalized_price Canonical positive decimal strings; "1000.0" becomes "1000"
amount_step, price_step Allowed quantity/price increments
rounding_mode reject_extra_precision
canonicalization_required Whether the submitted string representation must change
from_token, to_token, from_amount, to_amount, notional Signed token direction, raw amounts and display notional
eip712_order, eip712_types Exact Order message and types to sign using GET /config's domain

Submit the normalized values and the resulting signature to POST /orders. Previewing "1000.0" is allowed; submitting that unnormalized string as an order is not. Nonzero digits beyond the market precision return 422 / INVALID_PRECISION; other noncanonical submission strings return INVALID_DECIMAL_FORMAT. No silent rounding is performed. A preview error uses a top-level {ok:false, detail, error_code, ...}; order submission wraps the same business details under detail.

For raw integer amounts and prices, see Integer API (v2).

Cancel Order

POST /orders/cancel

Authentication: EIP-712 CancelOrder signature

Request Body

{
  "owner_address": "0x...",
  "order_id": "00000000-0000-4000-8000-000000000001",
  "uuid_int": "6427948336465191935941739505432058208337171677044006212075520",
  "signature": "0x..."
}

uuid_int is required because the signed CancelOrder.orderId field is the composite uint256, not the UUID string.

Response

{
  "status": "ok"
}

Notes

  • Orders are subject to a cancel cooldown (default 5 minutes).
  • Hitting the cooldown returns 429.
  • If you lost uuid_int, fetch the order first; it is returned in order status responses.

Cancel All Orders

POST /orders/cancel-all?owner_address=0x...

Authentication: API Key and EIP-712 CancelAll signature.

The lowercase owner_address query parameter is still required and must match the API-key owner and the request body's owner.

Request Body

{
  "owner_address": "0x...",
  "nonce": "123456789",
  "deadline": 1800000000,
  "signature": "0x..."
}
nonce is a positive uint256 string, unique for this owner; deadline is integer Unix seconds in the future, within the signed expiration window. Sign CancelAll(owner address, nonce uint256, deadline uint256) using the Sera domain; see Authentication. The server consumes the nonce once; replay returns 409. Persist it and check order state after an ambiguous response before signing another cancellation.

Response

{
  "cancelled": [
    "order-id-1"
  ],
  "failed": [],
  "skipped_cooldown": [
    "order-id-2"
  ],
  "total": 1
}
total counts accepted successful cancellations, including already-terminal orders. A dispatched cancellation still needs a subsequent order-state query to confirm the final state and released balance. Inspect failed and skipped_cooldown; the response does not guarantee every open order has been cancelled.

Get Order

GET /orders/{order_id}

Authentication: API Key required

Response

{
  "trade_id": "00000000-0000-4000-8000-000000000001",
  "owner_address": "0x...",
  "status": "pending",
  "order_type": "limit",
  "symbol": "EURC/USDC",
  "side": "bid",
  "base_symbol": "EURC",
  "quote_symbol": "USDC",
  "base_token": "0x...",
  "quote_token": "0x...",
  "price": "1.085",
  "amount": "1000.0",
  "remaining_amount": "600.0",
  "filled_base_amount": "400.0",
  "filled_quote_amount": "434.0",
  "notional": "1085.0",
  "remaining_notional": "651.0",
  "from_token": "0x...",
  "to_token": "0x...",
  "from_amount": "1085000000",
  "filled_amount": "434000000",
  "to_amount": "1000000000",
  "created_at": "2026-04-15T08:00:00+00:00",
  "updated_at": "2026-04-15T08:01:00+00:00",
  "expiration": "1713254400",
  "error": null,
  "error_code": null,
  "uuid_int": "6427948336465191935941739505432058208337171677044006212075520",
  "vl_batch_id": null,
  "settlement_summary": {
    "status": "settled",
    "total_fill_count": 1,
    "pending_fill_count": 0,
    "settled_fill_count": 1,
    "failed_fill_count": 0,
    "reverted_fill_count": 0,
    "latest_settlement_id": 42,
    "latest_tx_hash": "0x...",
    "latest_parent_status": "confirmed",
    "latest_fill_settlement_status": "settled",
    "latest_failed_fill_failure_reason": null
  },
  "settlement_economics": {
    "perspective_order_id": "00000000-0000-4000-8000-000000000001",
    "gross_debits": [
      { "token": "USDC", "token_address": "0x...", "amount": "434.0", "amount_raw": "434000000" }
    ],
    "gross_credits": [
      { "token": "EURC", "token_address": "0x...", "amount": "400.0", "amount_raw": "400000000" }
    ],
    "balance_debits": [
      { "token": "USDC", "token_address": "0x...", "amount": "434.0", "amount_raw": "434000000" }
    ],
    "balance_credits": [
      { "token": "EURC", "token_address": "0x...", "amount": "400.0", "amount_raw": "400000000" }
    ],
    "fees_paid": []
  }
}

Response Notes

  • order_type is limit for limit orders and vl/cancel flows, and swap for orders created through POST /swap.
  • expiration echoes the signed order deadline as a string when present.
  • error_code is a typed terminal failure code. See the error envelope table below and the additional codes at the end of this page. Any unrecognised internal failure collapses to TRANSIENT_SETTLEMENT_FAILURE.
  • vl_batch_id is set when the order belongs to a Virtual Liquidity batch.
  • settlement_summary aggregates per-fill settlement progress for the order. latest_failed_fill_failure_reason is a curated, display-oriented revert name for the most recent failed fill (anything outside the public allowlist is returned as null).
  • settlement_economics is the public owner-perspective view. balance_debits / balance_credits describe the owner-visible balance movements. When upstream balance rows are present, the public API maps gross_debits / gross_credits to the same movements for compatibility; those names do not guarantee pre-fee trade totals. fees_paid lists explicit user-visible fees. Do not sum gross and balance arrays or subtract a listed fee again from an already adjusted movement.
  • Positive-spread fills can make filled_amount / filled_quote_amount differ from the user's total source-token debit.

External order statuses are:

  • pending — submitted, resting on the book, or partially filled; the order can still receive more fills or be cancelled
  • matched — fully matched, with settlement still unresolved. Follow settlement evidence for success or failure. Eligible failed limit takers can later return to pending during recovery; this is not a monotonic terminal-state sequence.
  • settled — chain-confirmed terminal success
  • failed — chain-confirmed revert, or pre-broadcast failure / rejection
  • cancelled — currently removed from the book. Explicit user cancellation prevents recovery; a system removal after failed settlement can be recoverable for eligible limit takers. Check the current order and per-fill settlement state.

Error Envelope

POST /orders returns a typed envelope for categorized business rejections, including self-match 409. Other 4xx failures can contain a string detail. A categorized response has this shape:

{
  "detail": {
    "detail": "Order placement failed",
    "error_code": "INSUFFICIENT_EQUITY"
  }
}

Branch on error_code; the human detail is for display only.

error_code When it surfaces Client action
ALLOWANCE_INSUFFICIENT ERC-20 allowance to the spender insufficient at transfer time, including invalid/expired permit signatures Re-permit or re-approve and retry
INTENT_DEADLINE_EXPIRED Signed order's deadline passed before the tx landed Replace the order with a fresh deadline
SLIPPAGE_EXCEEDED The matching engine killed an IOC/FOK because no crossing liquidity exists at the signed price Review the signed price and reconcile the original order before replacing it
NO_LIQUIDITY Route has no executable depth at the quoted price Reduce size or try a different pair
QUOTE_STALE Quote/plan snapshot or signed deadline expired before submission Submit a fresh order
AMOUNT_BELOW_MIN Amount is below the pair's configured minimum Increase amount
STP_BLOCKED Self-trade prevention: order would have matched the caller's own resting order on the opposite side Cancel the resting order or revise the side
INSUFFICIENT_EQUITY Caller's available equity for the spent token is below the order's frozen-amount requirement Deposit more or cancel orders that have it tied up
PAIR_INACTIVE Trading pair is not currently active Use GET /markets to find a tradeable pair
TRANSIENT_SETTLEMENT_FAILURE Catch-all for non-actionable infrastructure failures and counterparty-state changes; also the safe default for any unknown internal code Retry; if it persists, escalate operationally

GET /orders/{id}.error_code is drawn from the same set; error carries the display-oriented revert reason of the most recent reverted fill (free-form text — use error_code for logic).

List Orders

trade_ids accepts at most 50 IDs. offset is bounded to 0–10000 (also for fill lists). Queries exceeding the supported scan window return 400; narrow by symbol, status or time. total is the full filtered count only for a successful query.

GET /orders

Authentication: API Key required

Query Parameters

Parameter Type Default Description
owner_address address Required Must match the authenticated owner
limit integer 50 Max 500
offset integer 0 Pagination offset
status string All Filter accepts pending, settled, cancelled, failed; matched is currently rejected with 422.
type string All swap or limit
symbol string All Exact normalized pair label(s), e.g. EURC/USDC; not free-text search.
side string All bid or ask
from_token string All Filter by resolved from-token address
to_token string All Filter by resolved to-token address
base_token string All Filter by base-token address
quote_token string All Filter by quote-token address
base_currency string All Legacy query-param name that filters on base_symbol, for example EURC
quote_currency string All Legacy query-param name that filters on quote_symbol, for example USDC
trade_ids string All Comma-separated trade ID list
search string All Free-text search across trade fields
has_error boolean All true returns only errored trades
min_price / max_price string All Price range filters
min_amount / max_amount string All Amount range filters
min_remaining_amount / max_remaining_amount string All Remaining amount range filters
min_filled_amount / max_filled_amount string All Filled amount range filters
min_notional / max_notional string All Notional range filters
created_after / created_before string All ISO8601 or timestamp-compatible created-at bounds
updated_after / updated_before string All ISO8601 or timestamp-compatible updated-at bounds
sort_by string created_at See allowed values below.
order string desc Sort direction (asc or desc)

sort_by accepts amount, created_at, filled_base_amount, filled_quote_amount, notional, price, remaining_amount, remaining_notional, status, symbol, trade_id, type, updated_at; order_type is an alias of type. Invalid values return 422.

status, type, symbol, side, from_token, to_token, base_token, quote_token, base_currency, quote_currency and trade_ids accept comma-separated alternatives. Alternatives within a field are ORed; different filters are combined. symbol is normalized to uppercase and matched exactly; use search for free text.

matched remains a valid response state for matched but unsettled orders. Only this list filter rejects it; GET /fills?order_status=matched remains supported. To inspect matched orders, fetch a broader order list and inspect its returned states instead of sending status=matched.

Filters are applied across the full matching trade set before pagination, so total reflects all filtered matches and you can paginate against it directly.

Response

Each entry in trades has the same schema as the Get Order response, including base_token / quote_token, full numeric breakdown (remaining_amount, filled_base_amount, filled_quote_amount, notional, remaining_notional), vl_batch_id, settlement_summary, and public-safe settlement_economics. total reflects the count after filtering, not the current page size.

{
  "trades": [
    {
      "trade_id": "00000000-0000-4000-8000-000000000001",
      "owner_address": "0x...",
      "status": "pending",
      "order_type": "limit",
      "symbol": "EURC/USDC",
      "side": "bid",
      "base_symbol": "EURC",
      "quote_symbol": "USDC",
      "base_token": "0x...",
      "quote_token": "0x...",
      "price": "1.085",
      "amount": "1000.0",
      "remaining_amount": "1000.0",
      "filled_base_amount": "0",
      "filled_quote_amount": "0",
      "notional": "1085.0",
      "remaining_notional": "1085.0",
      "from_token": "0x...",
      "to_token": "0x...",
      "from_amount": "1085000000",
      "filled_amount": "0",
      "to_amount": "1000000000",
      "created_at": "2026-04-15T08:00:00+00:00",
      "updated_at": "2026-04-15T08:00:00+00:00",
      "expiration": "1713254400",
      "error": null,
      "error_code": null,
      "uuid_int": "6427948336465191935941739505432058208337171677044006212075520",
      "vl_batch_id": null,
      "settlement_summary": { "status": "pending", "total_fill_count": 0, "pending_fill_count": 0, "settled_fill_count": 0, "failed_fill_count": 0, "reverted_fill_count": 0, "latest_settlement_id": null, "latest_tx_hash": null, "latest_parent_status": null, "latest_fill_settlement_status": null, "latest_failed_fill_failure_reason": null },
      "settlement_economics": {
        "perspective_order_id": "00000000-0000-4000-8000-000000000001",
        "gross_debits": [],
        "gross_credits": [],
        "balance_debits": [],
        "balance_credits": [],
        "fees_paid": []
      }
    }
  ],
  "total": 1
}

Place VL Batch

POST /orders/vl/batch

Authentication: EIP-712 Order signature for every sibling order

Request Body

{
  "orders": [
    {
      "owner_address": "0x...",
      "side": "bid",
      "amount": "100",
      "price": "0.75",
      "order_type": "limit",
      "from_address": "0x...",
      "to_address": "0x...",
      "order_id": "00000000-0000-4000-8000-000000000010",
      "uuid_int": "6427948336465191935942058520151046588146668590738473494773760",
      "signature": "0x...",
      "expiration": 1713254400
    },
    {
      "owner_address": "0x...",
      "side": "bid",
      "amount": "100",
      "price": "0.80",
      "order_type": "limit",
      "from_address": "0x...",
      "to_address": "0x...",
      "order_id": "00000000-0000-4000-8000-000000000011",
      "uuid_int": "6427948336465191935942079787798979146800635051651437980286977",
      "signature": "0x...",
      "expiration": 1713254400
    }
  ]
}

VL Validation Rules

Rule Description
Batch size 2 to 50 orders (active cap returned at runtime by GET /config under limits.vl_batch)
Same owner All siblings must share one owner_address
Same spent token All siblings must resolve to the same fromToken
Unique markets Exact duplicates and inverse pairs are rejected
Shared group All uuid_int values must share the same VL group_id
Sequential legs leg_id values must be 0, 1, 2, ... in array order

Each sibling uses the same request semantics as POST /orders: from_address is the market base token, to_address is the quote token, and expiration is required.

Response

{
  "order_ids": [
    "00000000-0000-4000-8000-000000000010",
    "00000000-0000-4000-8000-000000000011"
  ],
  "amendments": [],
  "cancelled": [],
  "fills": [],
  "vl_group": {
    "primary_id": "00000000-0000-4000-8000-000000000010",
    "max_budget": "80",
    "budget_consumed": null,
    "spent_token": "USDC",
    "status": "pending"
  }
}

order_ids identifies all submitted legs in input order; it does not prove acceptance onto the book or settlement. Reconcile each order and its settlement state before replacing it.

Placement Outcome Details

The batch response also returns amendments, cancelled, fills, and nullable vl_group. Empty arrays mean this response carries no corresponding outcome; they do not prove all legs are resting, particularly while confirmation is pending.

Field Description
amendments[] order_id, original_amount, actual_amount, reason, optional quantity_semantics
quantity_semantics placement_total_quantity describes the placement total; remaining_quantity describes the remainder. Interpret actual_amount according to this value
cancelled[] order_id and reason for legs dropped during placement
fills[] order_id, immediate trades[] (quantity, price, optional counterparty_order_id, ts), and remaining
vl_group primary_id, max_budget, spent_token, status, budget_consumed
vl_group.status confirmed means budget consumption is known; pending means it is not yet confirmed and budget_consumed is null

Do not treat a pending budget as zero or assume every signed leg is resting at its original size. Older responses can omit quantity_semantics or status; do not infer confirmation from an absent field.

Cancel VL Batch

POST /orders/vl/cancel

Authentication: EIP-712 CancelVLBatch signature

Request Body

{
  "owner_address": "0x...",
  "vl_batch_id": "00000000-0000-4000-8000-000000000010",
  "signature": "0x..."
}

Response

{
  "status": "ok"
}

status is the cancellation result and is typically ok.

Get Fills For One Order

GET /fills/{order_id}

Authentication: API Key required

Query Parameters

Parameter Type Default
limit integer 100
offset integer 0

Response

{
  "items": [
    {
      "maker_order_id": "maker-order-id",
      "taker_order_id": "taker-order-id",
      "quantity": "100.0",
      "price": "0.75",
      "settlement_status": "pending",
      "tx_hash": null,
      "timestamp": "2026-04-15T08:00:00+00:00",
      "failure_reason": null,
      "settlement_economics": {
        "perspective_order_id": "taker-order-id",
        "gross_debits": [
          { "token": "USDC", "token_address": "0x...", "amount": "75.0", "amount_raw": "75000000" }
        ],
        "gross_credits": [
          { "token": "EURC", "token_address": "0x...", "amount": "100", "amount_raw": "100000000" }
        ],
        "balance_debits": [
          { "token": "USDC", "token_address": "0x...", "amount": "75.0", "amount_raw": "75000000" }
        ],
        "balance_credits": [
          { "token": "EURC", "token_address": "0x...", "amount": "100", "amount_raw": "100000000" }
        ],
        "fees_paid": []
      }
    }
  ]
}

Per-fill settlement_status values:

  • pending — settlement transaction has not been broadcast yet (tx_hash is null)
  • confirming — settlement transaction broadcast and awaiting block confirmations (tx_hash is populated; safe to watch on chain)
  • settled — chain-confirmed terminal success
  • failed — settlement-level failure
  • reverted — per-leg revert inside the on-chain batcher; the parent settlement transaction may still have succeeded

failure_reason, when present, is one of a fixed allowlist of decoded contract revert names. Anything outside that allowlist is returned as null so the field shape stays a closed set.

Fill-level settlement_economics uses the same public-safe owner perspective as orders. Fills may include both maker_order_id and taker_order_id as references, but the response does not expand the counterparty's signed order payload, protocol spread capture, or counterparty transfer split. tx_hash is safe to expose because it is the on-chain settlement transaction reference.

List Fills Across Orders

GET /fills

Authentication: API Key required

Query Parameters

Parameter Type Default Description
owner_address address Required Must match the authenticated owner
order_status string All pending, matched, settled, cancelled, failed
settlement_status string All pending, confirming, settled, failed, reverted
limit integer 100 Max 500
offset integer 0 Pagination offset

Response

{
  "items": [
    {
      "maker_order_id": "maker-order-id",
      "taker_order_id": "taker-order-id",
      "quantity": "100.0",
      "price": "0.75",
      "settlement_status": "pending",
      "tx_hash": null,
      "timestamp": "2026-04-15T08:00:00+00:00",
      "failure_reason": null,
      "settlement_economics": {
        "perspective_order_id": "taker-order-id",
        "gross_debits": [],
        "gross_credits": [],
        "balance_debits": [],
        "balance_credits": [],
        "fees_paid": []
      }
    }
  ]
}

Settlement Economics and Error Codes

Order and fill settlement_economics includes perspective_order_id, gross_debits, gross_credits, balance_debits, balance_credits and fees_paid. Token amount entries contain token, token_address, display amount and raw amount_raw; fee entries also contain type. balance_debits / balance_credits describe the owner-visible balance movements. When upstream balance rows are present, the public API maps gross_debits / gross_credits to the same movements for compatibility; those names do not guarantee pre-fee trade totals. fees_paid lists explicit user-visible fees. Do not sum gross and balance arrays or subtract a listed fee again from an already adjusted movement.

In addition to the original allowance/deadline/slippage/transient codes, public order errors can include STP_BLOCKED, INSUFFICIENT_EQUITY, PAIR_INACTIVE, AMOUNT_BELOW_MIN, QUOTE_STALE, COMPLIANCE_BLOCKED, DUPLICATE_ORDER_ID, INVALID_PRECISION and INVALID_DECIMAL_FORMAT. Submission business errors use detail.error_code; stored error_code describes an order result. Validation/authentication errors may instead contain a string detail. These shapes are not interchangeable with Exact Output or screening.

VL placement accepts only order_type="limit" for every leg. Standalone order support for market does not apply to /orders/vl/batch.