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

# Place an order

> Closed request schema — an unknown field is `400 unknown_field`. The
`201` reports the **actual sequenced outcome** (the gateway holds the
request through ack-by-observation), not a synthesized "accepted".
Execution outcomes (post-only cross, FOK/IOC, STP, max-cost) return
`201` with `status: "canceled"` and a `reason` — they are not errors
(api.md §5, §6.5). Reservation and fee accounting are absent here; they
arrive on the WS `user` channel or via the balance read.




## OpenAPI

````yaml /api-spec/venue-openapi.yaml post /v1/portfolio/orders
openapi: 3.1.0
info:
  title: Exchange API — REST lane
  version: 1.0.0
  summary: Client-facing REST surface for the binary prediction-market exchange.
  description: >
    The client-visible REST contract of the API lane — the normative source is

    `specs/api.md`; the request-ingress mechanics are in `specs/gateway.md`.


    ## Conventions (api.md §1)

    - **Versioning:** every path is under `/v1/`. Unknown *request* fields are
      rejected (`400 unknown_field`); clients MUST ignore unknown *response*
      fields (additive changes are non-breaking).
    - **Numbers:** prices are integer **ticks** (1–99, cents); quantities are
      integer shares; money is integer cents. u64-domain values (`order_id`,
      `client_order_id`, `seq`, cents amounts, timestamps) render as decimal
      **strings**; u32-and-below render as JSON numbers. Floats never appear.
    - **Timestamps:** `ts`/`*_ts` fields are nanoseconds since the Unix epoch as
      decimal strings — the sequencer's stamp, untranslated.
    - **`as_of_seq`:** every read response carries the stream sequence number
      its answer is current as of. Two reads with the same `as_of_seq` describe
      one consistent instant.
    - **Pagination:** list endpoints take `limit` (default 100, max 1000) and an
      opaque `cursor`; responses echo `cursor` for the next page (empty string
      when exhausted).

    ## Authentication (api.md §2, gateway.md §4–§5)

    Every request — there is no anonymous surface — carries three headers:

    `DX-ACCESS-KEY`, `DX-ACCESS-TIMESTAMP` (Unix ms), and `DX-ACCESS-SIGNATURE`

    (base64 HMAC-SHA256 over the canonical string

    `timestamp + "\n" + METHOD + "\n" + path?query + "\n" + body`, ±5000 ms

    replay window). Keys carry scopes `read` (GETs) and `trade`
    (order/withdrawal

    mutations); the required scope per operation is given in `x-required-scope`.

    Rate limits are per-key token buckets (read 100/s +200 burst; write 50/s

    +100 burst) answered with `429` + `Retry-After`.


    ## Execution outcomes are not errors (api.md §5)

    Post-only cross, FOK infeasible, IOC remainder, STP and max-cost-infeasible

    arrive as a **successful** placement response with `status: "canceled"` and

    a `reason` — they are the order's history, not a protocol failure. Only the

    reject taxonomy in §5 maps to non-2xx.
  x-other-lanes:
    websocket:
      endpoint: wss://{host}/v1/ws
      spec: specs/api.md §7, specs/ws.md
      note: >-
        AsyncAPI territory — subscribe/unsubscribe command envelope, public
        channels (orderbook_delta, trades, ticker) and the private `user`
        channel with snapshot+resume. Not modelled in this OpenAPI document.
    mcp:
      endpoint: POST /v1/mcp
      spec: specs/mcp.md
      note: >-
        JSON-RPC 2.0 agent lane exposing the same reads/writes as MCP tools.
        Described by its own tool schema, not OpenAPI.
servers:
  - url: https://api.raeth.exchange
    description: >-
      Production. Every request is authenticated — there is no anonymous access,
      including market data. See Authentication.
security:
  - DxAccessKey: []
    DxAccessTimestamp: []
    DxAccessSignature: []
tags:
  - name: Exchange
    description: Exchange-wide control state (api.md §3).
  - name: Markets
    description: Market metadata, orderbooks and public tape (api.md §4).
  - name: Portfolio (read)
    description: Key-scoped balance, positions, fills and orders (api.md §6.1–6.3, 6.6).
  - name: Orders (write)
    description: >-
      Order placement, cancel, decrease, batch and mass-cancel (api.md
      §6.5–6.10).
  - name: Funding
    description: Deposit address and withdrawals (api.md §6A).
  - name: Admin
    description: >
      Control-plane operator actions (specs/admin.md). Served on a SEPARATE
      listener from every path above — see the operation's own `servers`
      override; the top-level `servers` block does not reach it.
externalDocs:
  description: Normative API surface specification (REST + WebSocket).
  url: specs/api.md
paths:
  /v1/portfolio/orders:
    post:
      tags:
        - Orders (write)
      summary: Place an order
      description: |
        Closed request schema — an unknown field is `400 unknown_field`. The
        `201` reports the **actual sequenced outcome** (the gateway holds the
        request through ack-by-observation), not a synthesized "accepted".
        Execution outcomes (post-only cross, FOK/IOC, STP, max-cost) return
        `201` with `status: "canceled"` and a `reason` — they are not errors
        (api.md §5, §6.5). Reservation and fee accounting are absent here; they
        arrive on the WS `user` channel or via the balance read.
      operationId: placeOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlaceOrderRequest'
      responses:
        '201':
          description: The sequenced placement outcome (api.md §6.5).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlaceOrderResponse'
              example:
                order_id: '16777291'
                client_order_id: '42'
                status: partially_filled
                seq: '182391'
                filled_qty: 100
                resting_qty: 400
                fills:
                  - tick_yes: 47
                    qty: 100
                    path: direct
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/MissingScope'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/Shed'
        '504':
          $ref: '#/components/responses/SequencingTimeout'
components:
  schemas:
    PlaceOrderRequest:
      type: object
      description: Closed schema (api.md §6.5) — unknown field ⇒ 400.
      additionalProperties: false
      properties:
        client_order_id:
          allOf:
            - $ref: '#/components/schemas/U64String'
          description: idempotency key
        market_id:
          type: integer
        side:
          $ref: '#/components/schemas/Side'
        outcome:
          $ref: '#/components/schemas/Outcome'
        type:
          type: string
          enum:
            - limit
            - market
        tick:
          allOf:
            - $ref: '#/components/schemas/Tick'
          description: limit only
        worst_tick:
          allOf:
            - $ref: '#/components/schemas/Tick'
          description: >-
            market only, optional; marketable-limit bound (default 99 buy / 1
            sell)
        qty:
          type: integer
          minimum: 1
        tif:
          type: string
          enum:
            - gtc
            - gtt
            - ioc
            - fok
          description: limit only; market ⇒ forced ioc
        expiry_ts:
          allOf:
            - $ref: '#/components/schemas/U64String'
          description: ns; gtt only
        max_cost:
          allOf:
            - $ref: '#/components/schemas/U64String'
          description: cents; required for market buys
          else optional: null
        group_id:
          type: integer
          default: 0
        post_only:
          type: boolean
          default: false
        reduce_only:
          type: boolean
          default: false
        cancel_on_pause:
          type: boolean
          default: false
        stp_maker:
          type: boolean
          default: false
      required:
        - client_order_id
        - market_id
        - side
        - outcome
        - type
        - qty
    PlaceOrderResponse:
      type: object
      description: The sequenced placement outcome (api.md §6.5).
      properties:
        order_id:
          $ref: '#/components/schemas/U64String'
        client_order_id:
          $ref: '#/components/schemas/U64String'
        status:
          type: string
          enum:
            - resting
            - partially_filled
            - executed
            - canceled
        reason:
          type:
            - string
            - 'null'
          description: present when status is canceled (execution outcome
          api.md §5): null
        seq:
          allOf:
            - $ref: '#/components/schemas/U64String'
          description: the NEW_ORDER's stamp
        filled_qty:
          type: integer
        resting_qty:
          type: integer
        fills:
          type: array
          items:
            $ref: '#/components/schemas/FillBrief'
      required:
        - order_id
        - client_order_id
        - status
        - seq
        - filled_qty
        - resting_qty
        - fills
    U64String:
      type: string
      description: A u64-domain value rendered as a decimal string (api.md §1).
      pattern: ^[0-9]+$
      example: '182390'
    Side:
      type: string
      enum:
        - buy
        - sell
    Outcome:
      type: string
      enum:
        - 'yes'
        - 'no'
    Tick:
      type: integer
      description: Price tick in cents, in the outcome's own space.
      minimum: 1
      maximum: 99
    FillBrief:
      type: object
      description: One FILL event in stream order (api.md §6.5).
      properties:
        tick_yes:
          $ref: '#/components/schemas/Tick'
        qty:
          type: integer
        path:
          $ref: '#/components/schemas/FillPath'
      required:
        - tick_yes
        - qty
        - path
    ErrorEnvelope:
      type: object
      description: The uniform error body (api.md §5).
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: lowercase snake_case reject/gateway code.
            num:
              type:
                - integer
                - 'null'
              description: >-
                The u16 reject code; non-null iff origin is `core` or `port`
                drawing from the shared registry (funding-port rejects carry a
                null num).
            origin:
              type: string
              enum:
                - core
                - port
                - gateway
            message:
              type: string
            details:
              type:
                - object
                - 'null'
          required:
            - code
            - num
            - origin
            - message
            - details
      required:
        - error
    FillPath:
      type: string
      description: The FILL path flag.
      enum:
        - direct
        - mint
        - merge
  responses:
    BadRequest:
      description: >
        Edge validation fault (origin gateway: `unknown_field`,
        `malformed_json`, `schema_violation`, `bad_client_withdrawal_id`,
        `bad_amount`, `bad_destination`) or a core/port validity reject
        (`bad_price_tick`, `bad_qty`, `invalid_decrease`,
        `client_order_id_required`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: unknown_field
              num: null
              origin: gateway
              message: unknown_field
              details: null
    Unauthorized:
      description: Missing or invalid signature (`unauthorized`, origin gateway).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: unauthorized
              num: null
              origin: gateway
              message: unauthorized
              details: null
    MissingScope:
      description: >-
        Key lacks the required scope (`missing_scope`), or a risk reject
        (`per_market_limit`, `user_suspended`, `reduce_only_violation`, …).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: missing_scope
              num: null
              origin: gateway
              message: missing_scope
              details: null
    Conflict:
      description: >
        `duplicate_client_order_id`, `stale_client_withdrawal_id`, or a
        market-state reject (`market_closed`, `market_inactive`,
        `exchange_paused`, `trading_paused`, `market_frozen`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: duplicate_client_order_id
              num: 259
              origin: core
              message: duplicate_client_order_id
              details: null
    Unprocessable:
      description: >-
        Funding reject (`insufficient_balance`, `sell_exceeds_position`,
        `max_cost_exceeded`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: insufficient_balance
              num: 257
              origin: core
              message: insufficient_balance
              details: null
    RateLimited:
      description: Token bucket empty (`rate_limited`). Retry after the header interval.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: rate_limited
              num: null
              origin: gateway
              message: rate_limited
              details: null
    Shed:
      description: Backpressure — no session capacity (`shed`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: shed
              num: null
              origin: gateway
              message: shed
              details: null
    SequencingTimeout:
      description: >
        The sequenced outcome did not arrive within the response budget
        (`sequencing_timeout`, origin gateway). For a placement, retry the
        identical request then `GET /v1/portfolio/orders?client_order_id=` — at
        most one order results (api.md §8).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: sequencing_timeout
              num: null
              origin: gateway
              message: sequencing_timeout
              details: null
  securitySchemes:
    DxAccessKey:
      type: apiKey
      in: header
      name: DX-ACCESS-KEY
      description: The API key id (decimal string).
    DxAccessTimestamp:
      type: apiKey
      in: header
      name: DX-ACCESS-TIMESTAMP
      description: Request timestamp, Unix milliseconds (decimal). ±5000 ms replay window.
    DxAccessSignature:
      type: apiKey
      in: header
      name: DX-ACCESS-SIGNATURE
      description: >
        base64(HMAC-SHA256(secret, "timestamp\nMETHOD\npath?query\nbody")). For
        the WS handshake the body is empty and the path is `/v1/ws`.

````