> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xo.market/llms.txt
> Use this file to discover all available pages before exploring further.

# Post a new order

> Place a single signed CTF order. Optional `postOnly` on the
envelope (not inside the signed order) rejects the request if
the order would take liquidity. See `PlaceOrderRequest.postOnly`.




## OpenAPI

````yaml /api-reference/openapi.yaml post /order
openapi: 3.0.3
info:
  title: XO Orderbook API
  description: |
    Public REST surface of the XO CLOB API.

    XO mainnet chain id is `3223`. The EIP-712 order domain is
    `XO Market CLOB` with `verifyingContract` set to the
    [CTF Exchange](/) address. See
    [Smart accounts](../guides/smart-accounts) for the smart-account
    identity model and ERC-1271 order signing.

    Wire conventions:
      * Prices are trimmed decimal strings (e.g. `"0.5"`, `"0.555"`).
      * Sizes are decimal-string integers in human shares.
      * Timestamps in trade and book responses are stringified Unix
        seconds / milliseconds (the SDK uses `TimestampSeconds<String>`
        / `TimestampMilliSeconds<String>`).
      * Token IDs are decimal U256 strings; condition IDs are
        `0x`-prefixed 32-byte hex.
  version: 1.0.0
  contact:
    name: XO Market
    url: https://beta.xo.market
servers:
  - url: https://orderbooks.xo.market
    description: Mainnet (XO chain id 3223)
security: []
tags:
  - name: Authentication
    description: >-
      Create and manage API keys. The L1 ClobAuth EIP-712 flow mints HMAC
      credentials that authenticate every other private request.
  - name: Market Data
    description: >-
      Public reads for books, prices, midpoints, spreads, last trades, and price
      history. Also includes server time and per-token configuration.
  - name: Markets
    description: >-
      Discovery for tradable markets, including pagination and SDK-compatible
      simplified shapes.
  - name: Trade
    description: Place, cancel, and inspect orders and trades for the authenticated maker.
  - name: Account
    description: Maker balance, allowance, positions, and claimable settled positions.
paths:
  /order:
    post:
      tags:
        - Trade
      summary: Post a new order
      description: |
        Place a single signed CTF order. Optional `postOnly` on the
        envelope (not inside the signed order) rejects the request if
        the order would take liquidity. See `PlaceOrderRequest.postOnly`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlaceOrderRequest'
            examples:
              gtc_buy_smart_account:
                summary: GTC BUY at 0.55 from a Privy/ZeroDev smart account
                value:
                  orderType: GTC
                  order:
                    salt: '12345678901234567890'
                    maker: '0xCAFE000000000000000000000000000000000A11'
                    signer: '0xCAFE000000000000000000000000000000000A11'
                    beneficiary: '0x0000000000000000000000000000000000000000'
                    tokenId: >-
                      26516164265702901957933644848127860370782874751279270726689263951695181556943
                    makerAmount: '55000000'
                    takerAmount: '100000000'
                    expiration: '0'
                    nonce: '0'
                    identifier: '0x00000000000000000000000000000000'
                    metadata: >-
                      0x0000000000000000000000000000000000000000000000000000000000000000
                    side: 0
                    signatureType: 3
                    signature: >-
                      0xa1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f901b
              gtc_post_only:
                summary: GTC maker that must rest (reject if it would take)
                value:
                  orderType: GTC
                  postOnly: true
                  order:
                    salt: '12345678901234567890'
                    maker: '0xCAFE000000000000000000000000000000000A11'
                    signer: '0xCAFE000000000000000000000000000000000A11'
                    beneficiary: '0x0000000000000000000000000000000000000000'
                    tokenId: >-
                      26516164265702901957933644848127860370782874751279270726689263951695181556943
                    makerAmount: '55000000'
                    takerAmount: '100000000'
                    expiration: '0'
                    nonce: '0'
                    identifier: '0x00000000000000000000000000000000'
                    metadata: >-
                      0x0000000000000000000000000000000000000000000000000000000000000000
                    side: 0
                    signatureType: 3
                    signature: >-
                      0xa1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f901b
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlaceOrderResponse'
              examples:
                live_resting:
                  summary: order rested on the book (no immediate fills)
                  value:
                    success: true
                    errorMsg: null
                    makingAmount: '0'
                    takingAmount: '0'
                    orderID: >-
                      0x0011223344556677889900aabbccddeeff00112233445566778899aabbccddee
                    status: live
                    transactionsHashes: []
                    tradeIds: []
                fully_matched:
                  summary: order matched immediately and settled
                  value:
                    success: true
                    errorMsg: null
                    makingAmount: '55000000'
                    takingAmount: '100000000'
                    orderID: >-
                      0x0011223344556677889900aabbccddeeff00112233445566778899aabbccddee
                    status: matched
                    transactionsHashes:
                      - >-
                        0xdeadbeef000000000000000000000000000000000000000000000000000000c0
                    tradeIds:
                      - >-
                        0xc0ffee0000000000000000000000000000000000000000000000000000000a11
                fok_failed:
                  summary: >-
                    FOK could not fill at signed price (returns success=false
                    but 200 status)
                  value:
                    success: false
                    errorMsg: FOK could not fill at signed price
                    makingAmount: '0'
                    takingAmount: '0'
                    orderID: >-
                      0x0011223344556677889900aabbccddeeff00112233445566778899aabbccddee
                    status: delayed
                    transactionsHashes: []
                    tradeIds: []
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '503':
          $ref: '#/components/responses/Error503TradingPaused'
      x-codeSamples:
        - lang: Rust
          label: xo-orderbook-client-rs
          source: >
            use alloy::signers::local::LocalSigner;

            use rust_decimal_macros::dec;

            use xo_orderbook_client::orderbook::{Client, Config};

            use xo_orderbook_client::orderbook::types::{OrderType, Side};

            use xo_orderbook_client::types::{Decimal, U256};


            // 1. Authenticate (mints/derives the L2 HMAC creds).

            let signer =
            LocalSigner::from_bytes(&std::env::var("XO_PRIVATE_KEY")?.parse()?)?;

            let client = Client::new("https://orderbooks.xo.market",
            Config::default())?
                .authentication_builder(signer.clone())
                .authenticate()
                .await?;

            let token_id = U256::from_str_radix(
                "26516164265702901957933644848127860370782874751279270726689263951695181556943",
                10,
            )?;


            // 2. Build a GTC limit BUY at 0.55 for 100 shares.

            let order = client
                .limit_order()
                .token_id(token_id)
                .order_type(OrderType::GTC)
                .price(dec!(0.55))
                .size(Decimal::ONE_HUNDRED)
                .side(Side::Buy)
                .build()
                .await?;

            // 3. Sign + submit.

            let signed = client.sign(&signer, order).await?;

            let resp = client.post_order(signed).await?;

            println!("order id: {}, status: {}", resp.order_id, resp.status);
components:
  schemas:
    PlaceOrderRequest:
      type: object
      required:
        - order
        - orderType
      properties:
        order:
          $ref: '#/components/schemas/CTFOrder'
        orderType:
          type: string
          enum:
            - GTC
            - FAK
            - FOK
            - GTD
          description: >
            * `GTC` - Good-Till-Cancel; rests on the book until filled or
            cancelled.

            * `GTD` - Good-Till-Date; requires non-zero `expiration` in the
            signed order.

            * `FOK` - Fill-Or-Kill; fills the entire signed `takerAmount` (BUY)
            /
              `makerAmount` (SELL) at the signed price or rejects with no fills.
            * `FAK` - Fill-And-Kill (a.k.a. IOC); fills as much as the book
            supports
              at the signed price; cancels any unfilled remainder.

            **Market-style execution.** There is no dedicated `MARKET` value.

            Submit a signed CTFOrder at an aggressive cap price (e.g. `0.99`

            for BUY, `0.001` for SELL), then choose `FAK` for immediate

            partial fill or `FOK` for all-or-nothing execution. The matching

            logic can also use economically compatible YES/NO liquidity.
        postOnly:
          type: boolean
          default: false
          description: |
            Envelope flag — not part of the signed EIP-712 order. When
            `true`, the order must rest without taking any liquidity.
            The engine rejects it (HTTP 400) if it would match at
            placement via COMPLEMENTARY, MINT, or MERGE.

            Requires `orderType` of `GTC` or `GTD`. `FAK` / `FOK` with
            `postOnly: true` returns
            `{"error": "postOnly orders must use orderType GTC or GTD"}`.
            A crossing GTC/GTD returns
            `{"error": "post-only order would cross resting liquidity"}`.

            Omitted or `false` is a normal order.
    PlaceOrderResponse:
      type: object
      description: |
        Wire shape uses **camelCase** (`orderID`, `errorMsg`,
        `makingAmount`, `takingAmount`, `transactionsHashes`, `tradeIds`)
        to satisfy `polymarket-client-sdk` deserialisation. The struct's
        Rust source is `#[serde(rename_all = "camelCase")]` with explicit
        `rename = "orderID"` and `rename = "transactionsHashes"`.
      required:
        - success
        - errorMsg
        - makingAmount
        - takingAmount
        - orderID
        - status
        - transactionsHashes
        - tradeIds
      properties:
        success:
          type: boolean
        errorMsg:
          type: string
          nullable: true
          description: |
            `null` when `success: true`. Populated with a stable failure
            message when `success: false` (e.g. `"FOK could not fill at
            signed price"`).
        makingAmount:
          type: string
          description: |
            Total maker-side amount across all fills, decimal string.
            USDC micro-units for a BUY, human-share tokens for a SELL.
            `"0"` when the order rested with no fills.
        takingAmount:
          type: string
          description: |
            Total taker-side amount across all fills, decimal string.
            Opposite-side unit of `makingAmount`. `"0"` when no fills.
        orderID:
          type: string
          description: 0x-prefixed EIP-712 order hash digest. Same hash the SDK signed.
        status:
          type: string
          enum:
            - live
            - matched
            - delayed
          description: |
            * `live` — resting on the book (GTC/GTD with remainder).
            * `matched` — fully filled.
            * `delayed` — queued, FOK could not fill at signed price,
              or otherwise not yet matched. Matches the canonical
              `py-clob-client` status strings (NOT `"cancelled"`).
        transactionsHashes:
          type: array
          items:
            type: string
          description: 0x-prefixed on-chain settlement tx hashes (one per matched batch).
        tradeIds:
          type: array
          items:
            type: string
          description: 0x-prefixed 32-byte trade ids for fills produced by this order.
    CTFOrder:
      type: object
      description: |
        EIP-712 signed order. Wire fields are camelCase. Sign over domain
        `name="XO Market CLOB", version="1", chainId=<XO chain id>,
        verifyingContract=<CTF Exchange address>`. XO Privy/ZeroDev smart
        accounts use `signatureType = 3`; direct EOA integrations use
        `signatureType = 0`.

        Orders do **not** carry a fee rate. Fetch the market category rate
        with `GET /fee-rate` and see the Fees guide for the conviction curve.
        Legacy wire keys `taker` and `feeRateBps` are ignored on parse and
        must not be used for signing (the typehash changed).
      required:
        - salt
        - maker
        - signer
        - beneficiary
        - tokenId
        - makerAmount
        - takerAmount
        - expiration
        - nonce
        - identifier
        - metadata
        - side
        - signatureType
        - signature
      properties:
        salt:
          type: string
          description: Unique entropy for the order (decimal uint256 string).
        maker:
          type: string
          description: |
            Address that funds the order (principal + any fee) and receives
            refunded unspent principal.
        signer:
          type: string
          description: |
            Address that signs the order. For `signatureType = 3`, must equal
            `maker` (the XO smart account).
        beneficiary:
          type: string
          description: |
            Address that receives fill proceeds (collateral or outcome tokens).
            `0x0000…0000` pays the maker (default). A beneficiary never funds
            fees and never receives principal refunds — those stay with `maker`.
          default: '0x0000000000000000000000000000000000000000'
        tokenId:
          type: string
          description: |
            Decimal U256 CTF outcome token id. On BUY this is the asset bought;
            on SELL this is the asset sold.
        makerAmount:
          type: string
          description: |
            Maximum amount the maker sells, in micro units (6 decimals).
            For BUY this is collateral; for SELL this is outcome tokens.
        takerAmount:
          type: string
          description: |
            Minimum amount the maker receives, in micro units (6 decimals).
            For BUY this is outcome tokens; for SELL this is collateral.
        expiration:
          type: string
          default: '0'
          description: Unix seconds; 0 = no expiration
        nonce:
          type: string
          description: |
            On-chain cancel nonce (`uint128`). Accepts a JSON number, a decimal
            string, or a `0x`-prefixed hex string.
        identifier:
          type: string
          description: >
            Opaque 16-byte tag (`bytes16`) the signer attaches for off-chain

            fill grouping (partner, campaign, strategy). Zero-filled when
            unused.

            Covered by the EIP-712 hash and echoed in `OrderFilled`.
          default: '0x00000000000000000000000000000000'
        metadata:
          type: string
          description: |
            Opaque 32-byte tag (`bytes32`) with the same guarantees as
            `identifier`. Zero-filled when unused.
          default: '0x0000000000000000000000000000000000000000000000000000000000000000'
        side:
          type: integer
          enum:
            - 0
            - 1
          description: 0 = BUY, 1 = SELL
        signatureType:
          type: integer
          enum:
            - 0
            - 1
            - 2
            - 3
          description: 0 = EOA, 1 = POLY_PROXY, 2 = POLY_GNOSIS_SAFE, 3 = XO_ZERODEV
        signature:
          type: string
          description: 0x-prefixed 65-byte hex (not part of the EIP-712 typehash)
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
  responses:
    Error400:
      description: |
        Validation failure. The body is always `{"error": "<message>"}`. The
        message is the verbatim string the gateway emits (callers may
        substring-match on stable prefixes like `"invalid token_id"`,
        `"duplicate order"`, `"post-only order"`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalid_token_id:
              summary: malformed token_id query
              value:
                error: 'invalid token_id: invalid digit found in string'
            invalid_json_body:
              summary: request body is not JSON
              value:
                error: 'invalid JSON body: expected value at line 1 column 1'
            duplicate_order:
              summary: replayed signed order
              value:
                error: >-
                  duplicate order: an order with the same signed-payload hash is
                  already resting in this book
            post_only_would_cross:
              summary: post-only would take liquidity
              value:
                error: post-only order would cross resting liquidity
            post_only_invalid_tif:
              summary: postOnly with FAK or FOK
              value:
                error: postOnly orders must use orderType GTC or GTD
    Error401:
      description: |
        Authentication failure. L1 ClobAuth (wallet) or L2 HMAC (API key)
        headers were missing, malformed, expired, or did not match the
        requested resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            l1_required:
              summary: L1 ClobAuth headers missing
              value:
                error: L1 ClobAuth headers required
            l2_required:
              summary: HMAC credentials missing
              value:
                error: HMAC L2 credentials required
            address_mismatch:
              summary: L1-recovered address does not match request
              value:
                error: L1 auth address does not match request address
    Error422:
      description: |
        Business-rule failure. The request was well-formed and authorised but
        the engine refused it for a stateful reason (balance, position,
        market lifecycle, size/notional floors). Stable message prefixes:
        `insufficient balance`, `insufficient position`, `size below minimum`,
        `notional below minimum`, `market is not active`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficient_balance:
              summary: BUY exceeds USDC balance
              value:
                error: 'insufficient balance: required 100000000, available 12345678'
            insufficient_position:
              summary: SELL exceeds token position
              value:
                error: 'insufficient position: required 5000000, available 1000000'
            size_below_minimum:
              summary: order size below MIN_ORDER_SIZE_SHARES floor
              value:
                error: 'size below minimum: min 5000000, got 1000'
            notional_below_minimum:
              summary: price * size below the notional floor
              value:
                error: 'notional below minimum: min 10000, got 500'
            market_not_active:
              summary: market is not in Active status
              value:
                error: 'market is not active (status: Pending)'
    Error429:
      description: |
        Per-user mutation rate limit exceeded. The body includes
        `retry_after_ms` (milliseconds until the current 1-second fixed
        window resets) so clients can back off precisely. Returned by
        write endpoints under burst load.
      content:
        application/json:
          schema:
            type: object
            required:
              - error
              - retry_after_ms
            properties:
              error:
                type: string
              retry_after_ms:
                type: integer
                format: int64
          examples:
            rate_limited:
              summary: rate-limit window not yet reset
              value:
                error: rate limit exceeded
                retry_after_ms: 387
    Error503TradingPaused:
      description: |
        Global trading is paused (admin kill-switch active). Returned by
        order-placement endpoints when the shared `trading_paused` flag is
        set. Wire body has a stable `error: "trading_paused"` code so
        clients can branch on it. The response always carries a
        `Retry-After: 60` header (advisory back-off floor).
      headers:
        Retry-After:
          schema:
            type: string
            example: '60'
      content:
        application/json:
          schema:
            type: object
            required:
              - error
              - message
            properties:
              error:
                type: string
                enum:
                  - trading_paused
              message:
                type: string
          examples:
            trading_paused:
              summary: kill-switch active
              value:
                error: trading_paused
                message: Global trading is paused. New orders are not being accepted.

````