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

# Get a single order by internal id

> Returns the full order row (including `raw`, the unredacted venue response, and `metadata`) for a single order the caller owns. Use this after `POST /orders` to poll a specific order's terminal state, or after `GET /orders` (which strips `raw`/`metadata`) to drill into one row.



## OpenAPI

````yaml /openapi/execution.yaml get /orders/{order_id}
openapi: 3.1.0
info:
  title: Kairos Order Execution API
  version: 1.0.0
  summary: >-
    Order entry, cancellation, fee quotes, and live position exposure across
    venues.
  description: >
    The Order Execution API at `execution.kairos.trade` places and manages

    orders across every venue Kairos integrates. Two lanes:


    - **Custodial** (`POST /orders`) — Kairos signs and routes on your behalf
      (custodial signing). Async ack: a 200 means validated + enqueued; track via
      `GET /orders/{order_id}` or the WebSocket order/fill stream.
    - **Self-custody / external signing** (`POST /v2/orders/intent` +
      `POST /v2/orders/submit`) — for allow-listed institutional accounts on
      Polymarket and Predict.fun: Kairos builds the EIP-712 payload, you sign
      with your own key, submission is synchronous with the venue's verbatim
      result. `POST /v2/onchain/intent` + `POST /v2/onchain/submit` are the
      same pattern for on-chain operations (approvals, redeem, split/merge,
      unwrap) on Polygon, where you also pay the gas.

    ## Authentication


    All endpoints require a Kairos API key (`X-Client-Id` + `X-Api-Key` +

    `X-Api-Secret`) or a first-party session JWT, plus the per-operation

    scope (`trade:execute`, `trade:read`, `position:read`) where the operation

    documents one. Synthetic Books accepts any otherwise-valid account

    credential without an extra scope or allowlist. There is

    no anonymous tier. Scope checks apply to API-key credentials only; a

    session JWT carries no scope list and is treated as holding every scope.


    The custodial mutation endpoints (`POST /orders`, the three cancel

    endpoints) and Synthetic Books create/refresh/release carry an additional

    `RequireServiceToken` gate satisfied by **any** of: the full API-key triple,

    an internal `X-Service-Token`, or a valid `X-Csrf-Token`. API-key consumers

    need no extra header — but a bare `Authorization: Bearer <jwt>` alone is NOT

    sufficient on those routes. The `/v2/orders/*` and `/v2/onchain/*`

    external-signing routes have no such gate: a session JWT alone works there.


    ## Rate limits


    Order submission is capped per user (default 5 orders per **second**,

    sliding window, `ORDER_RATE_LIMIT_PER_SEC`); some credentials carry an

    `orders` override, which is enforced on its own per-credential window of

    the same duration *in addition to* the per-user window — either one

    denying is a `429`. Idempotent replays (same `client_order_id`) return the

    existing order before the limiter runs and never consume a slot. The

    limiter is Redis-backed and **fails closed**: if Redis is unreachable the

    submission is denied with `429`.


    Separately, repeated *authentication failures* from one client IP are

    throttled at 10 failures per 60 s (also fail-closed). That limiter returns

    the minimal `{"error": "Too many authentication attempts"}` body.


    **No rate-limit headers.** This service does not emit `Retry-After`,

    `X-RateLimit-*`, or any other backoff hint on a `429` — back off on your

    own schedule.


    ## Error responses


    **Six different error body shapes are in use across this service and they

    are not interchangeable.** Check the shape documented on the specific

    operation before writing a parser; a client that assumes one shape will

    read `undefined` for the reason on the others.


    1. `OrderErrorResponse` — the structured envelope (`error`, `code`,
       `error_details{code,message,details?,metadata?,actions}`) returned by
       every handler that surfaces an `ExecutionError`/`ApiError`: order
       submission, cancel-all, the CTF endpoints, the Polymarket/Opinion
       onboarding endpoints, Hyperliquid withdraw/transfer, and most of the
       deposit-wallet family. Note the two `code` fields differ in case:
       top-level `code` is PascalCase (`"AuthInsufficientScope"`), while
       `error_details.code` is the SCREAMING_SNAKE_CASE wire code
       (`"AUTH_INSUFFICIENT_SCOPE"`). Match on `error_details.code`.
    2. `OrderSimpleErrorResponse` — the minimal `{"error": "..."}` (sometimes
       with `code`) used by the auth middleware (any endpoint's
       `401`/`403`/`429`), the whole `/v2/*` external-signing and on-chain
       lane, the Kalshi and Predict.fun endpoints.
    3. `OrderMarketLinkErrorResponse` — `{"message": "..."}`, with no `error`
       and no `code`. Used by `POST /orders/market-links` **only**.
    4. **Empty or plain-text, not JSON at all.** Several deposit-wallet
       endpoints — most importantly
       the RPC signed-batch submission and
       `POST /exchanges/polymarket/imported/relay-info` — return most 4xx/5xx
       responses with a **completely empty body** and `content-type:
       text/plain`. A handful of cases carry a bare plain-text sentence
       (`batch is not an allowed withdrawal or collateral conversion`,
       `relayer rejected batch: …`). Do not attempt to JSON-parse these.
    5. Handlers whose Rust signature returns a bare `StatusCode` likewise send
       **no body at all**; those responses are marked "empty body (status code
       only)".
    6. `SyntheticBookErrorResponse` — `{"error": "stable_snake_case_code",
       "message": "...", "details"?: {...}}` on `/v1/synthetics*`. Match the
       top-level `error`; upstream definition validation may be nested under
       `details`.

    A further wrinkle inside shape 1: some provider-access checks discard the

    specific reason and return a generic `"Request failed with status 403"` /

    `AUTH_CREDENTIALS_INVALID` body, while others preserve

    `AUTH_INSUFFICIENT_SCOPE` and the real message. Do not rely on the message

    text of an access denial being stable.


    The central `ExecutionError` → HTTP mapping (`ApiError::from`) is:


    | `ExecutionError` | Status | `error_details.code` |

    |---|---|---|

    | `InsufficientBalance` | 400 | `FUNDS_INSUFFICIENT_USDC` |

    | `CollateralLocation` | 400 | `FUNDS_COLLATERAL_LOCATION` |

    | `InvalidOrder` | 400 | `VALIDATION_INVALID_ORDER` |

    | `PositionShortfall` | 400 | `FUNDS_INSUFFICIENT_BALANCE` |

    | `MarketClosed` | 400 | `EXCHANGE_POLYMARKET_MARKET_CLOSED` |

    | `OrderAlreadyCancelled` | 400 | `VALIDATION_INVALID_ORDER` |

    | `UnsupportedExchange` | 400 | `EXCHANGE_UNSUPPORTED` |

    | `SlippageExceeded` | 400 | `MARKET_FOK_NOT_FILLED` |

    | `FokNotFilled` | 400 | `MARKET_FOK_NOT_FILLED` |

    | `AuthenticationError` | 401 | `AUTH_CREDENTIALS_INVALID` |

    | `CredentialError` | 401 | `AUTH_CREDENTIALS_NOT_FOUND` |

    | `MarketNotFound` | 404 | `VALIDATION_MARKET_NOT_FOUND` |

    | `OrderNotFound` | 404 | `VALIDATION_INVALID_ORDER` |

    | `MarketNotSettledOnChain` | 409 | `VALIDATION_MARKET_NOT_SETTLED_ON_CHAIN`
    |

    | `OrderbookUnavailable` | 422 | `ORDERBOOK_UNAVAILABLE` |

    | `ExchangeError` (code `429`/`RATE_LIMITED`) | 429 |
    `EXCHANGE_POLYMARKET_RATE_LIMITED` |

    | `ExchangeError` (code `401`/`UNAUTHORIZED`) | 401 |
    `AUTH_POLYMARKET_API_KEY_INVALID` |

    | `SigningError` | 500 | `SIGNATURE_ERROR` |

    | `DatabaseError` | 500 | `DATABASE_ERROR` |

    | `InternalError` / `LedgerReconciliationRequired` /
    `SponsoredRequestWedged` / `PreTradeError` | 500 | `INTERNAL_ERROR` |

    | `NetworkError`, `ExchangeError` (any other code) | 502 | `NETWORK_ERROR` /
    venue-classified |

    | `LockError` | 503 | `INTERNAL_ERROR` |

    | `Timeout` | 504 | `NETWORK_TIMEOUT` |


    A venue `ExchangeError` is further classified from the venue's own message

    text before it is mapped, so an "allowance is not enough" rejection becomes

    `ALLOWANCE_CTF_NOT_SET`, a "not enough balance" rejection becomes

    `FUNDS_INSUFFICIENT_BALANCE`, "post-only mode" becomes `MARKET_NOT_READY`,

    a "no liquidity" rejection becomes `MARKET_INSUFFICIENT_LIQUIDITY`, and so

    on. Match on `error_details.code`, never on `error`.


    ## Server-level guards


    Every request is subject to a 120 s timeout (`OE_REQUEST_TIMEOUT_SECS`), a

    2 MiB request-body cap (`OE_MAX_BODY_BYTES`, over-size bodies get `413`),

    and a 1024-request global concurrency ceiling

    (`OE_MAX_CONCURRENT_REQUESTS`). Every response carries
    `X-Content-Type-Options:

    nosniff`, `X-Frame-Options: DENY`, HSTS, and a `default-src 'none'` CSP.


    ## Conventions


    - Prices are decimal strings on the 0–1 scale; `*_bps` fields are the
      same value in basis points (× 10000).
    - Quantities/sizes are decimal strings.

    - Structured errors carry `error_details.code`
      (SCREAMING_SNAKE_CASE) plus actionable recovery `actions`.

    ## Changelog


    **2026-09-14 — collateral routing fields on `POST /orders`.** Four optional

    request fields and one optional response field. `collateral`

    (`skip` | `check` | `fund`) **defaults to** `skip`, which is exactly today's

    path: no affordability check, no hold, no funding, zero added latency — so

    no existing caller changes behaviour without opting in. `shard_funding`

    **defaults to** `true`, which is also exactly today's behaviour: the Kalshi

    shard move is same-venue, zero-fee and already runs for every account; send

    `false` to opt out. `collateral=fund` requires both `max_bridge_fee_usdc`

    and `max_funding_wait_ms` and is rejected `400` naming the missing cap;

    either cap without `fund` is likewise a `400`. The response gains

    `funding`, `null` whenever no funding work ran. FIX sessions carry the same

    fields on `NewOrderSingle(D)` as optional tags `5701`–`5704`; a session that

    sends none of them is unchanged.
  contact:
    name: Kairos
    url: https://app.kairos.trade/docs/api-reference
  termsOfService: https://kairos.trade/terms
servers:
  - url: https://execution.kairos.trade
    description: Production (central primary, us-east-1)
  - url: https://eu-west-1-polymarket.executor.kairos.trade
    description: >-
      Production regional execution node — Ireland, colocated with Polymarket.
      Same API surface; assigned at onboarding.
  - url: https://ap-northeast-1-predictfun.executor.kairos.trade
    description: >-
      Production regional execution node — Tokyo, colocated with Predict.fun.
      Same API surface; assigned at onboarding.
  - url: https://staging-execution.kairos.trade
    description: Staging
security:
  - apiKeyClientId: []
    apiKeyKey: []
    apiKeySecret: []
paths:
  /orders/{order_id}:
    get:
      tags:
        - Orders
      summary: Get a single order by internal id
      description: >-
        Returns the full order row (including `raw`, the unredacted venue
        response, and `metadata`) for a single order the caller owns. Use this
        after `POST /orders` to poll a specific order's terminal state, or after
        `GET /orders` (which strips `raw`/`metadata`) to drill into one row.
      operationId: getOrder
      parameters:
        - name: order_id
          in: path
          required: true
          description: >-
            Internal Kairos order id (the `order_id` returned by `POST /orders`
            or `POST /v2/orders/submit`).
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The order, including `raw` and `metadata`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: >-
            `order_id` is not a valid UUID (framework-level path rejection —
            plain-text body, not JSON).
        '401':
          $ref: '#/components/responses/ExecUnauthorized'
        '403':
          description: >-
            Order belongs to another user, missing `trade:read` scope, or
            API-key access to the order's provider is disabled. Empty body
            (status code only).
        '404':
          description: No order with that id. Empty body (status code only).
        '500':
          description: Database read failed. Empty body (status code only).
        '503':
          description: >-
            API-key access to the order's provider could not be checked
            (access-cache read failed — fails closed). Empty body (status code
            only).
components:
  schemas:
    Order:
      type: object
      description: Exchange-agnostic order record.
      required:
        - id
        - user_id
        - exchange_id
        - market_id
        - side
        - kind
        - quantity
        - time_in_force
        - filled_quantity
        - status
        - created_at
        - updated_at
        - gas_sponsored
        - collateral_mode
        - shard_funding
        - holding_wallet
      properties:
        id:
          type: string
          format: uuid
          description: Internal Kairos order id.
        user_id:
          type: string
          description: Owning user's id.
        exchange_id:
          type: string
          description: >-
            Venue identifier (e.g. `polymarket`, `kalshi`, `predictfun`,
            `hyperliquid`).
          example: polymarket
        market_id:
          type: string
          description: >-
            Market/contract identifier on the venue (condition id for
            Polymarket; numeric HIP-4 outcome id for Hyperliquid).
        token_id:
          type: string
          nullable: true
          description: >-
            Outcome-token id. Hyperliquid uses a side coin such as `#1010` or
            `#1011`.
        side:
          $ref: '#/components/schemas/OrderSide'
        kind:
          $ref: '#/components/schemas/OrderKind'
        quantity:
          type: string
          description: Order quantity (decimal string, full precision), shares/contracts.
          example: '100'
        price:
          type: string
          nullable: true
          description: >-
            Limit price as a decimal string in `[tick, 1]` (prediction-market
            venues).
          example: '0.52'
        price_bps:
          type: integer
          nullable: true
          description: >-
            `price` expressed in basis points (price × 10000), for DB/analytics
            compatibility.
          example: 5200
        time_in_force:
          $ref: '#/components/schemas/OrderTimeInForce'
        post_only:
          type: boolean
          description: >-
            Whether this order was submitted maker-only. A post-only order is
            one the venue was told to REJECT rather than let cross the spread
            and take liquidity. Always present; `false` for ordinary orders and
            for venues with no post-only concept.
          default: false
          example: false
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: Expiration timestamp for GTD orders.
        filled_quantity:
          type: string
          description: Cumulative filled quantity (decimal string).
          example: '0'
        avg_fill_price:
          type: string
          nullable: true
          description: >-
            Size-weighted average fill price (decimal string, 0..1), null until
            any fill lands.
        avg_fill_price_bps:
          type: integer
          nullable: true
          description: '`avg_fill_price` in basis points.'
        exchange_order_id:
          type: string
          nullable: true
          description: Venue-assigned order handle. Null until the order reaches the venue.
        status:
          $ref: '#/components/schemas/OrderStatus'
        terminal_fill_verification:
          allOf:
            - $ref: '#/components/schemas/TerminalFillVerification'
          nullable: true
          description: >-
            Durable venue-terminal fill barrier. While `pending`, callers must
            retain protection even if another status field appears terminal.
            `complete` carries the exact venue cumulative that was folded before
            terminal publication.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        locked_by:
          type: string
          nullable: true
          description: Worker id currently holding the execution lock, if any.
        lock_expires_at:
          type: string
          format: date-time
          nullable: true
        error_message:
          type: string
          nullable: true
          description: Failure detail when `status` is `failed`.
        failure:
          $ref: '#/components/schemas/OrderFailure'
        fee_amount:
          type: string
          nullable: true
          description: Fee charged for this order, decimal string.
        fee_currency:
          type: string
          nullable: true
        client_order_id:
          type: string
          nullable: true
          description: Caller-supplied idempotency key, if one was provided at submission.
        wallet_id:
          type: string
          nullable: true
          description: FK to the user's wallet used for this order.
        outcome:
          type: string
          nullable: true
          description: Human-readable outcome label (e.g. "Yes", "No", a team name).
        outcome_id:
          type: string
          nullable: true
          description: Outcome id — equals `token_id` on Polymarket.
        trigger_price:
          type: string
          nullable: true
          description: >-
            Trigger price for stop-loss/take-profit style orders, decimal
            string.
        trigger_price_bps:
          type: integer
          nullable: true
        gas_sponsored:
          type: boolean
          description: >-
            Whether Kairos sponsored gas for this order (always `false` on the
            self-custody external-signing lane).
        collateral_mode:
          type: string
          enum:
            - skip
            - check
            - fund
          description: >-
            The collateral mode resolved for this order at submit. Always
            present; `skip` for an order that asked for nothing.
          example: skip
        shard_funding:
          type: boolean
          description: >-
            Whether the Kalshi shard move was permitted for this order. Always
            present; `true` unless the caller opted out.
          example: true
        max_bridge_fee_usdc:
          type: string
          nullable: true
          description: >-
            The order's bridge-fee ceiling in USDC, decimal string. Only ever
            set under `collateral_mode=fund`.
        max_funding_wait_ms:
          type: integer
          nullable: true
          description: >-
            The order's funding-wait ceiling in milliseconds. Only ever set
            under `collateral_mode=fund`.
        gas_amount:
          type: string
          nullable: true
          description: Gas spent, decimal string, if applicable.
        maker_address:
          type: string
          nullable: true
          description: On-chain maker/signer address, for Polymarket reconciliation.
        tx_hash:
          type: string
          nullable: true
          description: On-chain transaction hash (Polygon), if the fill involved one.
        raw:
          nullable: true
          description: >-
            Full raw venue request/response payload for audit. Present on `GET
            /orders/{order_id}`; stripped to `null` on `GET /orders` (list
            responses) to keep list payloads small.
        bot_id:
          type: string
          nullable: true
          description: >-
            Trading-bot id that placed this order, if any (null for manual/API
            orders).
        source:
          type: string
          nullable: true
          description: >-
            Attribution for who initiated the order: `manual` (web UI), `bot`,
            `copytrade`, `api` (API-key auth), or `fastlane` (external-signing
            lane).
          example: api
        metadata:
          nullable: true
          description: >-
            Exchange-specific metadata (arbitrary JSON). Present on `GET
            /orders/{order_id}`; stripped to `null` on `GET /orders`.
        holding_wallet:
          type: string
          description: >-
            On-chain wallet that holds (or will hold) the resulting shares — the
            EOA for legacy Polymarket orders, or the Safe deposit-wallet proxy
            for upgraded/external-signing users. Empty string for non-Polymarket
            orders.
    OrderSide:
      type: string
      description: Order/intent side. Lower-case on the wire.
      enum:
        - buy
        - sell
      example: buy
    OrderKind:
      type: string
      description: >-
        Order type. `market` orders still require a `price` (the limit you'll
        cross to); `limit` orders rest at `price` until filled or cancelled.
      enum:
        - market
        - limit
      example: limit
    OrderTimeInForce:
      type: string
      description: >-
        Time-in-force, always UPPER-CASE on the wire. `GTC`/`GTD` are resting
        (limit-style); `FOK`/`FAK`/`IOC` are immediate taker executions.
      enum:
        - GTC
        - GTD
        - FOK
        - FAK
        - IOC
      example: GTC
    OrderStatus:
      type: string
      description: >-
        Lifecycle status. `partial` is the wire spelling of a partially-filled
        order (NOT

        `partially_filled`).


        The internal states `queued`, `locked` and `orphaned` are **persisted as
        `pending`**, so

        an order read back from `GET /orders` or `GET /orders/{order_id}`
        reports `pending` for

        all three — they are listed here because they are part of the type and
        can appear on

        in-process/streamed values. `executing` is the exception: once a worker
        claims the order

        for submission it is persisted as `executing`, and read-back endpoints
        report `executing`

        until the venue acknowledges (then `live`) or the attempt fails. The one
        place a caller

        sees `queued` directly is the `status` field of a fresh `POST /orders`
        response, which is

        the literal string `"queued"`.
      enum:
        - pending
        - queued
        - locked
        - executing
        - live
        - partial
        - filled
        - cancelled
        - expired
        - failed
        - orphaned
      example: live
    TerminalFillVerification:
      type: object
      required:
        - state
        - exchange_order_id
        - reason
        - target_status
        - started_at
      properties:
        state:
          type: string
          enum:
            - pending
            - complete
        exchange_order_id:
          type: string
          description: Exact venue-order generation covered by the barrier.
        reason:
          type: string
          enum:
            - explicit_cancel
            - venue_absent
        target_status:
          type: string
          enum:
            - cancelled
            - expired
        started_at:
          type: string
          format: date-time
        final_filled_quantity:
          type: string
          nullable: true
          description: >-
            Exact venue cumulative, including explicit `0`; required when state
            is complete.
        verified_at:
          type: string
          format: date-time
          nullable: true
          description: Receipt completion timestamp; required when state is complete.
    OrderFailure:
      type: object
      description: >-
        Structured failure detail attached to a `failed` order (`GET /orders`,

        `GET /orders/{order_id}`, and the `order_update` WebSocket event).
        OMITTED

        entirely (not `null`) when the order has no failure.


        `classification` is the **authoritative retry policy**:

        `expected_user_rejection` is a well-formed request the venue or the
        user's own

        inputs rejected — do not retry without changing the order; `retryable`
        is a

        transient condition that may succeed on retry; `non_retryable` cannot
        succeed

        by retrying the same order.


        `details.actions` is a **UI affordance only**. It is derived from `code`

        independently of `classification` and may include `retry` (even as
        `primary`)

        on a `non_retryable` failure, because the suggested buttons target an
        end user

        who may be able to change something first. Do NOT build an automatic
        retry

        loop from `actions`; branch on `classification`. A client that is not
        rendering

        buttons can ignore `actions` entirely.
      required:
        - code
        - classification
        - details
      properties:
        code:
          type: string
          description: |-
            Machine-readable failure code. This is NOT the same namespace as
            `details.code`: `code` is the execution error's wire code (e.g.
            `FOK_NOT_FILLED`), while `details.code` is the `OrderErrorCode`
            used for incident grouping (e.g. `MARKET_FOK_NOT_FILLED`). For a
            venue `ExchangeError` the two coincide.
          example: FOK_NOT_FILLED
        classification:
          type: string
          enum:
            - expected_user_rejection
            - retryable
            - non_retryable
          description: Authoritative retry policy for this failure.
        details:
          $ref: '#/components/schemas/OrderErrorDetails'
    OrderErrorDetails:
      type: object
      description: >-
        Structured, machine-readable error payload shared across order-execution
        error responses.
      required:
        - code
        - message
        - actions
      properties:
        code:
          $ref: '#/components/schemas/OrderErrorCode'
        message:
          type: string
          description: Human-readable error message.
        details:
          type: string
          nullable: true
          description: Optional extended explanation.
        metadata:
          nullable: true
          description: >-
            Error-type-specific structured metadata (shape varies by `code` —
            e.g. `{type: "insufficient_funds", required, available, currency,
            shortfall}` or `{type: "rate_limit", retry_after_seconds, limit,
            window}`). Untagged union; treat as opaque unless you match on the
            embedded `type` field.
          additionalProperties: true
        actions:
          type: array
          description: Zero or more actionable recovery steps a client can surface.
          items:
            $ref: '#/components/schemas/OrderErrorAction'
    OrderErrorCode:
      type: string
      description: Machine-readable error code, SCREAMING_SNAKE_CASE on the wire.
      enum:
        - AUTH_CREDENTIALS_NOT_FOUND
        - AUTH_CREDENTIALS_INVALID
        - AUTH_POLICY_OUTDATED
        - AUTH_INSUFFICIENT_SCOPE
        - AUTH_POLYMARKET_API_KEY_INVALID
        - AUTH_TURNKEY_WALLET_NOT_FOUND
        - AUTH_TURNKEY_AUTH_FAILED
        - AUTH_TURNKEY_SIGNING_FAILED
        - VALIDATION_INVALID_ORDER
        - VALIDATION_INVALID_PRICE
        - VALIDATION_INVALID_SIZE
        - VALIDATION_MARKET_NOT_FOUND
        - VALIDATION_TOKEN_NOT_FOUND
        - VALIDATION_ORDER_EXPIRED
        - VALIDATION_MARKET_NOT_SETTLED_ON_CHAIN
        - AUTH_IDENTITY_MISMATCH
        - FUNDS_INSUFFICIENT_USDC
        - FUNDS_INSUFFICIENT_GAS
        - FUNDS_INSUFFICIENT_TOTAL
        - FUNDS_INSUFFICIENT_BALANCE
        - FUNDS_COLLATERAL_LOCATION
        - ALLOWANCE_USDC_NOT_SET
        - ALLOWANCE_CTF_NOT_SET
        - ALLOWANCE_APPROVAL_FAILED
        - NETWORK_RPC_ERROR
        - NETWORK_TIMEOUT
        - NETWORK_HTTP_ERROR
        - NETWORK_ERROR
        - EXCHANGE_POLYMARKET_API_ERROR
        - EXCHANGE_POLYMARKET_UNAUTHORIZED
        - EXCHANGE_POLYMARKET_MARKET_CLOSED
        - EXCHANGE_POLYMARKET_RATE_LIMITED
        - EXCHANGE_KALSHI_API_ERROR
        - EXCHANGE_KALSHI_UNAUTHORIZED
        - EXCHANGE_KALSHI_MARKET_CLOSED
        - EXCHANGE_ERROR
        - EXCHANGE_UNSUPPORTED
        - SIGNATURE_EIP712_FAILED
        - SIGNATURE_ERROR
        - GAS_ESTIMATION_FAILED
        - TRANSACTION_FAILED
        - GAS_SPONSORSHIP_FAILED
        - TRANSACTION_TIMEOUT
        - MARKET_NOT_READY
        - MARKET_PAUSED
        - MARKET_INSUFFICIENT_LIQUIDITY
        - ORDERBOOK_UNAVAILABLE
        - MARKET_FOK_NOT_FILLED
        - MARKET_ORDER_SIZE_EXCEEDS_MAX
        - DATABASE_ERROR
        - DATABASE_CREDENTIAL_DECRYPTION_FAILED
        - INTERNAL_ERROR
      example: FUNDS_INSUFFICIENT_USDC
    OrderErrorAction:
      type: object
      description: An actionable recovery step a client can surface to the end user.
      required:
        - action
        - label
        - primary
      properties:
        action:
          $ref: '#/components/schemas/OrderErrorActionType'
        label:
          type: string
          description: Human-readable button/link label.
          example: Add Funds
        url:
          type: string
          nullable: true
        primary:
          type: boolean
          description: Whether this is the primary/recommended action.
    OrderErrorActionType:
      type: string
      description: Machine-readable recovery-action identifier, snake_case on the wire.
      enum:
        - enable_trading
        - reenable_trading
        - update_policies
        - regenerate_api_key
        - contact_support
        - retry
        - review_order
        - adjust_price
        - adjust_size
        - browse_markets
        - refresh_market
        - create_new_order
        - add_funds
        - reduce_size
        - swap_usdc
        - add_matic
        - approve_usdc
        - approve_ctf
        - retry_approval
        - wait_and_retry
        - check_status
        - use_limit_order
        - update_kalshi_credentials
        - enable_bridge_funding
  responses:
    ExecUnauthorized:
      description: >
        No valid credential presented — missing/invalid API-key headers or an
        invalid/expired session token.
      content:
        application/json:
          schema:
            type: object
            required:
              - error
            properties:
              error:
                type: string
                example: Unauthorized
  securitySchemes:
    apiKeyClientId:
      type: apiKey
      in: header
      name: X-Client-Id
      description: >-
        Credential client id (`kairos_ck_...`). Must be sent together with
        X-Api-Key and X-Api-Secret.
    apiKeyKey:
      type: apiKey
      in: header
      name: X-Api-Key
      description: 64-char hex API key.
    apiKeySecret:
      type: apiKey
      in: header
      name: X-Api-Secret
      description: 64-char hex API secret.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.