openapi: 3.0.3
info:
  title: True Markets Gateway API
  description: |
    Gateway API for the True Markets trading platform — unified order orchestration, quotes, transfers, and balance management across CeFi and DeFi venues. Recommended for most integrations.

    ## Base URLs

    | Environment | Base URL |
    |---|---|
    | Production | `https://api.truemarkets.co/v1/gateway` |
    | UAT (sandbox) | `https://api.uat.truemarkets.co/v1/gateway` |

    > The legacy `/v1/conductor` base path continues to work for existing integrations but is deprecated — new integrations should use `/v1/gateway`.

    > UAT is the testing environment. It may require VPN/allowlist access for some integrations — contact [support@truemarkets.co](mailto:support@truemarkets.co) if requests time out from a public network.

    ## Authentication

    All endpoints require a JWT access token in the `Authorization: Bearer <token>` header.

    ### Getting credentials

    1. **Create an account** at [https://www.truemarkets.co](https://www.truemarkets.co) (passkey, email, magic link, or Sign in with Apple).
    2. **Register an API key** in your account's *API Keys* settings page. Generate an EC P-256 key pair locally and submit only the public key — the private key never leaves your machine. You'll receive a `key_id` (UUID).
    3. **Mint JWTs** by calling `POST /v1/auth/api-key/token` with `key_id`, a current `timestamp` (Unix seconds, within ±30s of server UTC time), and `signature` — an ES256 (ECDSA P-256 + SHA-256) signature of the message `{key_id}.{timestamp}`, base64url-encoded. The response returns `access_token` and `refresh_token`.
    4. **Call the Gateway** with `Authorization: Bearer <access_token>`.
    5. **Refresh** expired access tokens via `POST /v1/auth/token/refresh` with the `refresh_token` — no re-signing required.

    ### Acting for a user

    An organization trades for the users it created. Mint a token from an organization API key,
    then add `TM-On-Behalf-Of: <user_id>` to any user route: the request reads and writes that
    user's account. The header is declared on every route that accepts it, and organization-scoped
    routes reject it.

    ### Quick start

    ```bash
    # Mint a JWT
    curl -X POST https://api.truemarkets.co/v1/auth/api-key/token \
      -H "Content-Type: application/json" \
      -d '{"key_id":"<UUID>","timestamp":<UNIX_SECONDS>,"signature":"<BASE64URL_ES256_SIG>"}'

    # Compute a quote
    curl -X POST https://api.truemarkets.co/v1/gateway/quotes \
      -H "Authorization: Bearer <ACCESS_TOKEN>" \
      -H "Content-Type: application/json" \
      -d '{"base_asset":"BTC","quote_asset":"USD","qty":"1000","qty_unit":"quote","side":"buy"}'
    ```

    > Need to trade on a CeFi venue directly? CeFi direct FIX/REST/WS is institutional only — see the [CeFi Direct REST API](/apis/cefi-direct/openapi) reference. Retail traders reach CeFi via this Gateway, which proxies and signs the upstream HMAC for you.

    ## Order lifecycle

    Orders move through a small set of statuses. The path depends on whether the venue and order type require client-side signing.

    1. **Create** — `POST /orders` with your trade params. The response returns an `order_id` and a `status`. The exception is a DeFi order the account cannot fund (no on-chain balance and no CeFi balance to bridge): the response carries the `quote` with an `Insufficient balance` entry in `quote.issues`, an empty `order_id`, and no `payloads`. The quote is informational so the client can still show the expected output, but no order is created and it cannot be executed.
    2. **Sign and execute** — for DeFi orders and CeFi buy orders that need a funding bridge, the create response returns `status: initialized` along with an array of unsigned `payloads`. Sign each payload locally with your private key and post the signatures to `POST /orders/{id}/execute`. A CeFi buy then moves to `pending`; a DeFi order settles synchronously to `complete` (immediate fill) or `active` (a limit order resting on-chain).
    3. **Submitted directly** — for CeFi sell orders and sufficiently funded CeFi buy orders, the create response already returns `status: pending` with no `payloads`. The execute step is skipped. In a paper-trading environment DeFi orders also take this path: they settle against the virtual ledger during create and return a terminal `status` (`complete`) with no `payloads`, so clients must treat an empty `payloads` array as "already submitted" rather than waiting to sign.
    4. **Settle** — the order transitions out of `pending` to one of:
        - `complete` — fully filled.
        - `active` — limit order resting in the order book (can later move to `complete` or `canceled`).
        - `canceled` — canceled by the user or rejected by exchange/market conditions. A CeFi cancel first passes through `cancel_pending` until the exchange confirms.
        - `failed` — rejected by the exchange or DeFi execution reverted.

    Poll `GET /orders/{id}/status` (or list orders) to track progression. The `payloads` field in the create response is the signal: if it's non-empty, you need to sign and call execute. If it's empty or absent, the order is already submitted, unless `order_id` is empty and `quote.issues` reports an insufficient-balance problem, which means no order was created.

    ## Support
    - 📧 [support@truemarkets.co](mailto:support@truemarkets.co)
  version: "1.33.0"
  contact:
    name: True Markets support
    email: support@truemarkets.co
servers:
  - url: https://api.truemarkets.co/v1/gateway
    description: Production
  - url: https://api.uat.truemarkets.co/v1/gateway
    description: UAT (sandbox)
tags:
  - name: Quotes
    description: Request real-time market quotes for trading pairs without creating an order.
  - name: Orders
    description: Create, execute, cancel, and monitor orders across CeFi and DeFi.
  - name: Transfers
    description: Create, execute, and monitor transfers across CeFi and DeFi.
  - name: Ramps
    description: Sell stablecoin balances for fiat through Coinbase or PayPal, funded from CeFi when needed.
  - name: Custody
    description: Commit DeFi wallet holdings to CeFi trading without moving them on chain.
  - name: Transactions
    description: One unified feed of the caller's orders, transfers, and ramps.
  - name: Assets
    description: Browse the unified catalog of tradeable assets across DeFi and CeFi venues.
  - name: Balances
    description: Query account balances for the authenticated user.
  - name: Positions
    description: Query a user's open Hyperliquid perpetual positions.
  - name: Change Log
    description: |
      
      | Version | Date       | Notes                                                                                                                                    |
      |---------|------------|--------------------------------------------------------------------------------------------------------------------------------------------|
      | v1.33.0 | 2026-10-01 | Added `POST /withdrawals`, `GET /withdrawals` and `GET /withdrawals/{id}`. A withdrawal takes committed balance back out of CeFi trading: conductor asks the exchange to withdraw the amount and answers `202`; the exchange holds it, releases the matching DeFi allocation and then debits it, and conductor settles the withdrawal in the background. `DepositTransfer` is now `CustodyTransfer`, shared by both. |
      | v1.32.1 | 2026-10-01 | A `stranded` deposit now holds its listing, so `POST /deposits` answers `409` for that `asset_id` until an operator resolves it. |
      | v1.32.0 | 2026-09-29 | `POST /quotes` returns `notional`, the quote asset amount the order is expected to execute, and `fee`, the expected taker fee in quote asset units. `qty` is documented as the base asset quantity for every side and `qty_unit`, which is what it has always returned. |
      | v1.31.1 | 2026-09-28 | Declared `TM-On-Behalf-Of` as a header parameter on every user route, documented acting for a user under Authentication, and listed the `400`, `401`, `403` and `500` responses every user route can return. |
      | v1.31.0 | 2026-09-24 | Added `POST /deposits`, `GET /deposits` and `GET /deposits/{id}`. A deposit commits part of a DeFi wallet balance to CeFi trading without moving tokens: conductor raises an allocation against the caller's wallet, asks the exchange to credit the same amount and answers `202` at once; the exchange credits only after reading the allocation back, and conductor settles the deposit in the background, releasing the allocation again if the exchange refuses. |
      | v1.31.0 | 2026-09-29 | Chain accepts `robinhood` (Robinhood Chain, an Arbitrum-based Ethereum L2) for DeFi orders, alongside `solana`, `base`, `hypercore-spot`, and `hypercore-perp`. |
      | v1.30.0 | 2026-08-27 | Added `GET /assets/{chain}/{address}`, which returns one catalog listing in the same shape `GET /assets` returns, replacing the retired DeFi-service asset lookup. Chain and address match case-insensitively. |
      | v1.29.0 | 2026-08-20 | Transaction feed rows carry `asset_flow` (`in`/`out`), the direction the row's asset moved relative to the caller's holdings, so a mixed list renders without reading the typed sub-object. |
      | v1.28.0 | 2026-08-19 | Added `GET /transactions`, one paginated feed of the caller's orders, transfers, and ramps, so clients no longer merge the per-type endpoints themselves. Order responses carry `qty_unit`. |
      | v1.27.0 | 2026-08-18 | `GET /assets/availability` accepts an optional bearer token and resolves availability for the authenticated caller when one is supplied. |
      | v1.26.0 | 2026-08-17 | `POST /ramps` accepts `direction=onramp`, which buys crypto with fiat and returns the provider page in `redirect_url`. Adds the onramp-only payment methods `APPLE_PAY` and `GOOGLE_PAY`, which require the new `channel` field (`web`/`ios`/`android`). Provider preconditions the caller can clear now answer `422`, and an expired phone verification answers `409`. The signing relays remain offramp-only. |
      | v1.25.0 | 2026-08-17 | Trading is restricted by the country the request comes from: `POST /orders` returns `403` when the asset is not available there. Added `GET /assets/availability`, which reports the product types and asset classes the caller's country may trade. |
      | v1.24.0 | 2026-08-14 | Added the ramp endpoints: `POST /ramps` creates an offramp and tops any shortfall up from the user's CeFi balance, then `POST /ramps/{id}/bridge/execute`, `POST /ramps/{id}/prepare`, `POST /ramps/{id}/execute`, and `GET /ramps/{id}` carry it to settlement. `GET /ramps` lists the caller's ramps. The venue is chosen with `payment_method`; the provider is resolved downstream. |
      | v1.23.0 | 2026-08-14 | `GET /assets` accepts `product_type` (renamed from `type`, which stays as a deprecated alias) and a new `asset_class` (`crypto`, `stock`) defaulting to `crypto`. Assets carry `asset_class`, orthogonal to `type`: a tokenized stock is an ordinary spot listing. |
      | v1.22.0 | 2026-07-24 | Asset listings carry a `status` (`active`, `preview`, `sell_only`, `transfer_only`, `disabled`), enforced on order create. Transfer endpoints document their `400`, `403`, `404`, and `500` responses. |
      | v1.21.0 | 2026-07-23 | Order responses carry `asset_type` (`spot` or `perp`), separating perp orders from spot orders on the same symbol.                      |
      | v1.20.0 | 2026-07-16 | Added take-profit / stop-loss triggers for Hyperliquid perps, and `max_leverage` on perp assets in `GET /assets`.                        |
      | v1.19.0 | 2026-07-15 | Perp assets carry hourly market data — funding, open interest, and volume.                                                               |
      | v1.18.0 | 2026-07-08 | `GET /assets` accepts a `type` parameter gating perp assets. Failed CeFi orders carry `failure_reason`.                                  |
      | v1.17.0 | 2026-07-07 | `POST /orders` can return `422` when an asset cannot be resolved.                                                                        |
      | v1.16.0 | 2026-07-01 | Added `GET /positions` for read-only Hyperliquid perp positions, and `POST /orders/all/cancel` for CeFi mass cancels.                    |
      | v1.15.1 | 2026-06-30 | Documented the insufficient-balance case: a DeFi order the account cannot fund returns the quote with an `Insufficient balance` entry in `quote.issues`, an empty `order_id`, and no `payloads`. |
      | v1.15.0 | 2026-06-26 | Added `POST /orders/{id}/cancel` and `/cancel/execute` for Hyperliquid limit orders. `DELETE /orders/{id}` is **deprecated**.            |
      | v1.14.0 | 2026-06-25 | Perp orders accept `leverage` (1–50, isolated margin) and `reduce_only`.                                                                 |
      | v1.13.0 | 2026-06-24 | Base path moved to `/v1/gateway`; `/v1/conductor` continues to work but is **deprecated**. Added `PATCH /orders/{id}` to modify a CeFi order. |
      | v1.12.0 | 2026-06-18 | **Breaking:** `GET /balances` unified with `GET /balances/unified` and now returns the unified shape. Hyperliquid limit orders can rest on-chain by supplying a DeFi `chain`. |
      | v1.11.1 | 2026-06-17 | `GET /orders` defaults to all venues (`cefi,defi`) instead of `cefi`.                                                                    |
      | v1.11.0 | 2026-06-15 | `quote_asset` is no longer required; DeFi resolves the quote asset per chain.                                                            |
      | v1.10.0 | 2026-06-12 | Chain accepts `hypercore-spot` and `hypercore-perp` alongside `solana` and `base`.                                                       |
      | v1.9.0  | 2026-06-10 | `GET /orders` accepts a `venue` filter.                                                                                                  |
      | v1.8.0  | 2026-05-18 | Added `GET /orders/{id}` and order fee reporting.                                                                                        |
      | v1.7.3  | 2026-05-01 | Expanded the order lifecycle documentation.                                                                                              |
      | v1.7.2  | 2026-04-27 | Aligned the authentication documentation with the API-key JWT flow.                                                                      |
      | v1.7.1  | 2026-04-24 | Published the UAT base URL and documented credentials and quick start.                                                                   |
      | v1.7.0  | 2026-04-23 | Assets carry network details for CeFi venues.                                                                                            |
      | v1.6.0  | 2026-04-21 | Added transfers: `POST /transfers`, `POST /transfers/{id}/execute`, `GET /transfers`, and `GET /transfers/{id}`.                         |
      | v1.5.1  | 2026-04-13 | Operations grouped under `Quotes`, `Orders`, `Assets`, and `Balances`.                                                                   |
      | v1.5.0  | 2026-04-01 | Added `GET /assets`, the unified asset catalog across venues.                                                                            |
      | v1.4.0  | 2026-03-27 | Added `GET /balances/unified`.                                                                                                           |
      | v1.3.0  | 2026-03-19 | Added `DELETE /orders/{id}` to cancel an order, and a `status` filter on `GET /orders` returning both in-flight and settled orders.      |
      | v1.2.0  | 2026-03-17 | Added limit orders — order type accepts `limit` and requires `price` with `qty_unit: base`.                                              |
      | v1.1.0  | 2026-02-26 | Added settled order history with cursor pagination.                                                                                      |
      | v1.0.1  | 2026-02-05 | Paths are now relative to the service base URL rather than repeating the prefix.                                                         |
      | v1.0.0  | 2026-02-02 | Initial release. Quotes, order create/execute/list/status, and balances.                                                                 |
paths:
  # ==================== QUOTE ENDPOINTS ====================
  /quotes:
    post:
      operationId: computeQuote
      summary: Compute market quote (CeFi only)
      description: >
        Non-binding price preview for a CeFi market order. For DeFi, the quote is returned by `POST /orders` (see `CreateOrderResponse.quote`).
      tags:
        - Quotes
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QuoteRequest"
      responses:
        "200":
          description: Quote computed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QuoteResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  # ==================== ORDER ENDPOINTS ====================
  /orders:
    post:
      operationId: createOrder
      summary: Create new order
      description: Creates a new order. For DeFi orders, returns unsigned payloads for client signing.
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateOrderRequest"
      responses:
        "201":
          description: Order created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateOrderResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    get:
      operationId: listOrders
      summary: List user orders
      description: >
        Returns a paginated list of the authenticated user's orders with execution data. All statuses are returned by default; narrow the results with the `status` query parameter.
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: limit
          in: query
          description: Maximum number of orders to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: status
          in: query
          description: Comma-separated list of order statuses to filter by
          required: false
          schema:
            type: string
            example: "pending,canceled"
        - name: venue
          in: query
          description: >
            Comma-separated list of trading venues to filter by (`defi`, `cefi`). Defaults to all venues (`cefi,defi`) when omitted.
          required: false
          schema:
            type: string
            default: "cefi,defi"
            example: "cefi,defi"
      responses:
        "200":
          description: Orders retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetOrdersResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /orders/{id}/execute:
    post:
      operationId: executeOrder
      summary: Execute pending order
      description: Executes a pending order using client-provided signatures for the unsigned payloads
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExecuteOrderRequest"
      responses:
        "200":
          description: Order execution initiated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExecuteOrderResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /orders/all/cancel:
    post:
      operationId: cancelAllOrders
      summary: Cancel all open orders on a venue
      description: |
        Cancels all of your open orders on the given venue and returns how many
        were canceled. Cancellation is asynchronous — confirm final per-order
        state via `GET /orders`. Only `cefi` is supported today; `defi` returns
        `501 Not Implemented`.
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CancelAllOrdersRequest"
      responses:
        "202":
          description: Cancellation accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelAllOrdersResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /orders/{id}/cancel:
    post:
      operationId: prepareCancelOrder
      summary: Cancel a limit order (CeFi or DeFi)
      description: |
        Venue-polymorphic cancel. The `payloads` field is the signal:
        - **CeFi** orders are canceled immediately and return `202 Accepted` with no
          `payloads`. Poll `GET /orders/{id}/status` for the terminal state.
        - **DeFi** (Hyperliquid) resting orders return `200 OK` with unsigned
          `payloads`. Sign each locally and post the signatures to
          `POST /orders/{id}/cancel/execute`.

        Only cancellable orders (CeFi `pending`/`active`, DeFi `active`) can be
        canceled; others return 400.
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Resting DeFi order; unsigned cancel payloads to sign and execute
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CancelOrderResponse"
        "202":
          description: CeFi cancel accepted; poll order status for the terminal state
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /orders/{id}/cancel/execute:
    post:
      operationId: executeCancelOrder
      summary: Execute a resting DeFi limit order cancellation
      description: |
        Submits the client's signatures over the payloads returned by
        `POST /orders/{id}/cancel` to cancel a resting DeFi limit order.
        The order moves to `canceled` once the venue confirms.
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExecuteOrderRequest"
      responses:
        "200":
          description: Cancellation submitted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExecuteOrderResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /orders/{id}:
    get:
      operationId: getOrder
      tags:
        - Orders
      summary: Get a single order
      description: Returns full execution details for an order owned by the authenticated user.
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Order retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrderDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
    delete:
      operationId: cancelOrder
      deprecated: true
      tags:
        - Orders
      summary: Cancel a pending limit order (CeFi)
      description: |
        Deprecated: use `POST /orders/{id}/cancel`, the venue-polymorphic entry.

        Accepts a CeFi limit-order cancel and returns `202 Accepted`. Poll
        `GET /orders/{id}/status` for the terminal state (`canceled`, or `complete`
        if it filled before the cancel landed).
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      responses:
        "202":
          description: Cancellation request accepted
          content:
            application/json:
              schema:
                type: object
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
    patch:
      operationId: modifyOrder
      tags:
        - Orders
      summary: Modify an active limit order
      description: |
        Changes the price and/or quantity of an active CeFi limit order. The change
        is asynchronous: the order's stored price and quantity update once the
        exchange confirms the modification. Only active limit orders are modifiable.
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ModifyOrderRequest"
      responses:
        "202":
          description: Modification request accepted
          content:
            application/json:
              schema:
                type: object
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /orders/{id}/status:
    get:
      operationId: getOrderStatus
      summary: Get order status
      description: Returns the current status of an order
      tags:
        - Orders
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Order ID
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Order status retrieved
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetOrderStatusResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  /transfers:
    post:
      operationId: createTransfer
      summary: Create new transfer
      description: >-
        Creates a new on-chain transfer. Returns unsigned payloads for the client to sign before executing.


        For CeFi transfers, `network` is required — retrieve the supported values from `GET /assets` (see the `network` field below). Omit it for DeFi transfers, which derive the network from the asset's chain.
      tags:
        - Transfers
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTransferRequest"
      responses:
        "201":
          description: Transfer created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransferDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    get:
      operationId: listTransfers
      summary: List user transfers
      description: Returns a paginated list of transfers for the authenticated user
      tags:
        - Transfers
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: status
          in: query
          description: Filter by transfer status
          required: false
          schema:
            $ref: "#/components/schemas/TransferStatus"
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of transfers to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Transfers retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListTransfersResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /transfers/{id}/execute:
    post:
      operationId: executeTransfer
      summary: Execute pending transfer
      description: Executes a transfer in `awaiting_signature` status using client-provided signatures
      tags:
        - Transfers
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Transfer ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExecuteTransferRequest"
      responses:
        "200":
          description: Transfer execution initiated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransferDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /transfers/{id}:
    get:
      operationId: getTransfer
      summary: Get transfer by ID
      description: Returns the current state of a transfer
      tags:
        - Transfers
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Transfer ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Transfer retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransferDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  # ==================== RAMP ENDPOINTS ====================
  /ramps:
    post:
      operationId: createRamp
      summary: Create a ramp
      description: >-
        Creates an onramp that buys crypto with fiat, or an offramp that converts the user's stablecoin balance to fiat, through the given provider. The response's `redirect_url` is the provider page the user completes the ramp on.


        An offramp tops any shortfall up from the user's CeFi balance first, which requires completed KYC and enough CeFi PYUSD, and returns a `bridge_plan` when the user's own cross-chain funds must move first: sign its payloads, submit them to `POST /ramps/{id}/bridge/execute`, then call `POST /ramps/{id}/prepare`.


        An onramp has nothing to sign, and is subject to provider preconditions: phone verification, accepted provider terms, an active wallet, and amount limits.
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRampRequest"
      responses:
        "201":
          description: Ramp created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateRampResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
    get:
      operationId: listRamps
      summary: List user ramps
      description: Returns a paginated list of ramps for the authenticated user, newest first
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: status
          in: query
          description: Filter by ramp status
          required: false
          schema:
            $ref: "#/components/schemas/RampStatus"
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of ramps to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Ramps retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListRampsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /ramps/{id}:
    get:
      operationId: getRamp
      summary: Get ramp by ID
      description: Returns the current state of a ramp
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Ramp ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Ramp retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RampDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  /ramps/{id}/bridge/execute:
    post:
      operationId: executeRampBridge
      summary: Execute a ramp's bridge plan
      description: >-
        Executes the `bridge_plan` returned by ramp creation, moving the user's own funds from other chains or stablecoins onto the settlement chain. Sign every payload in the plan and submit the signatures in the same order. Offramps only.
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Ramp ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RampBridgeExecuteRequest"
      responses:
        "200":
          description: Bridge executed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RampBridgeExecuteResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /ramps/{id}/prepare:
    post:
      operationId: prepareRampTransfer
      summary: Prepare a ramp's on-chain transfer
      description: >-
        Returns the unsigned payloads that send the user's stablecoin to the provider's deposit address. Call this once the provider page has been completed, and after the bridge plan if the create response returned one. Offramps only.
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Ramp ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Transfer prepared successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RampTransferPrepareResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /ramps/{id}/execute:
    post:
      operationId: executeRampTransfer
      summary: Execute a ramp's on-chain transfer
      description: >-
        Submits the signed transfer, sending the stablecoin to the provider. Once it lands, the provider settles the fiat leg and the ramp's status follows. Offramps only.
      tags:
        - Ramps
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Ramp ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RampTransferExecuteRequest"
      responses:
        "200":
          description: Transfer executed successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RampTransferExecuteResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  # ==================== CUSTODY ENDPOINTS ====================
  /deposits:
    get:
      operationId: listDeposits
      summary: List the caller's deposits
      description: Returns a paginated list of the caller's deposits, newest first.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: status
          in: query
          description: Filter by deposit status
          required: false
          schema:
            $ref: "#/components/schemas/DepositStatus"
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of deposits to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Deposits retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListDepositsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
    post:
      operationId: createDeposit
      summary: Commit wallet balance to CeFi trading
      description: >-
        Commits `amount` more of the caller's DeFi wallet balance to CeFi trading.


        The tokens are not moved: they stay in the caller's own wallet and the deposit raises an allocation against them, which is refused when the wallet does not cover the caller's whole commitment. Conductor then asks the exchange to credit the same amount and answers `202` with the deposit in `crediting`. The exchange credits only after it has read the allocation back; the deposit then settles in the background, to `completed` when the exchange credits it or to `rejected` once a refused deposit's allocation has been released again. Poll `GET /deposits/{id}` for the outcome.


        One deposit per listing may be unsettled at a time: a second request for the same `asset_id` while the first is `allocating`, `crediting`, `releasing` or `stranded` answers `409`, so a retry after a lost response cannot commit twice. A stranded deposit holds the listing until an operator resolves it.


        `asset_id` names a DeFi listing from `GET /assets` whose symbol is also traded on CeFi. A CeFi listing answers `404`.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateDepositRequest"
      responses:
        "202":
          description: Allocation raised and the CeFi credit requested
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DepositDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /deposits/{id}:
    get:
      operationId: getDeposit
      summary: Get deposit by ID
      description: Returns the current state of a deposit.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Deposit ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Deposit retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DepositDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  /withdrawals:
    get:
      operationId: listWithdrawals
      summary: List the caller's withdrawals
      description: Returns a paginated list of the caller's withdrawals, newest first.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: status
          in: query
          description: Filter by withdrawal status
          required: false
          schema:
            $ref: "#/components/schemas/WithdrawalStatus"
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of withdrawals to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Withdrawals retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListWithdrawalsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
    post:
      operationId: createWithdrawal
      summary: Take committed balance back out of CeFi trading
      description: >-
        Takes `amount` of the caller's committed balance back out of CeFi trading.


        No tokens move: they never left the caller's own DeFi wallet. Conductor asks the exchange to withdraw the amount and answers `202` with the withdrawal in `debiting`. The exchange holds the amount, releases the matching DeFi allocation and then debits it; the withdrawal settles in the background, to `completed` once the exchange debits it or to `rejected` if it refuses. Poll `GET /withdrawals/{id}` for the outcome.


        One withdrawal per listing may be unsettled at a time: a second request for the same `asset_id` while the first is `debiting` or `stranded` answers `409`, so a retry after a lost response cannot withdraw twice. A stranded withdrawal holds the listing until an operator resolves it.


        `asset_id` names a DeFi listing from `GET /assets` whose symbol is also traded on CeFi. A CeFi listing answers `404`.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWithdrawalRequest"
      responses:
        "202":
          description: CeFi withdrawal requested
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithdrawalDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /withdrawals/{id}:
    get:
      operationId: getWithdrawal
      summary: Get withdrawal by ID
      description: Returns the current state of a withdrawal.
      tags:
        - Custody
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: id
          in: path
          description: Withdrawal ID (UUID)
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Withdrawal retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithdrawalDetail"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  # ==================== ASSET ENDPOINTS ====================
  /assets/availability:
    get:
      operationId: getAssetAvailability
      tags:
        - Assets
      summary: Get asset availability for the caller's country
      description: >-
        Returns the product types and asset classes the caller may trade, based on the country the request originates from. Both lists are allowlists, so a product type that is absent is not available. The response varies per caller, so it is not edge-cached, and the bearer token is optional but should be sent when the caller has one.


        These lists describe the venues we run. DeFi spot crypto is held on the caller's own keys and stays tradeable regardless of country, so empty lists do not mean nothing can be traded — a country that is fully restricted, or one that cannot be resolved at all, returns empty lists while DeFi spot crypto orders are still accepted.
      security:
        - {}
        - bearerAuth: []
      responses:
        "200":
          description: Availability retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetAvailability"
        "500":
          $ref: "#/components/responses/InternalError"
  /assets:
    get:
      operationId: listAssets
      tags:
        - Assets
      summary: List tradeable assets
      description: >-
        Returns a unified catalog of active tradeable assets across DeFi and CeFi venues. Spot assets only by default, so perps and tokenized stocks are opt-in via `type`. Each asset's `networks` lists the rails accepted as the `network` field when creating a CeFi transfer.
      security: []
      parameters:
        - name: venue
          in: query
          description: Filter by trading venue
          required: false
          schema:
            $ref: "#/components/schemas/Venue"
        - name: product_type
          in: query
          description: >-
            Comma-separated list of product types to include (`spot`, `perp`), case-insensitive. Defaults to `spot` when omitted, so perp assets are returned only when requested explicitly.
          required: false
          schema:
            type: string
            default: spot
            example: spot,perp
        - name: type
          in: query
          deprecated: true
          description: >-
            Deprecated alias for `product_type`, kept for shipped app builds. Ignored when `product_type` is also supplied.
          required: false
          schema:
            type: string
            example: spot,perp
        - name: asset_class
          in: query
          description: >-
            Comma-separated list of asset classes to include (`crypto`, `stock`), case-insensitive. Defaults to `crypto` when omitted, so tokenized stocks are returned only when requested explicitly. Orthogonal to `product_type`: a tokenized stock is a spot or perp listing whose asset class is `stock`.
          required: false
          schema:
            type: string
            default: crypto
            example: crypto,stock
      responses:
        "200":
          description: Assets retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListAssetsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "500":
          $ref: "#/components/responses/InternalError"
  /assets/{chain}/{address}:
    get:
      operationId: getAsset
      tags:
        - Assets
      summary: Get one asset by chain and address
      description: >-
        Returns the single catalog listing held at `address` on `chain`, in the same shape a `GET /assets` row takes. Both parameters match case-insensitively, so a checksummed and a lowercased EVM address resolve to the same listing.


        Unlike `GET /assets`, this lookup applies no status, venue, or asset class filter, so a listing the browse list hides for its `status` (for example `sell_only`) is still returned here and a client holding the asset can read its real state. Deactivated listings are not returned.
      security: []
      parameters:
        - name: chain
          in: path
          required: true
          description: Blockchain network the listing sits on, or `hypercore-perp` for a perp.
          schema:
            type: string
            example: base
        - name: address
          in: path
          required: true
          description: Token contract/mint address, or the symbol for a perp listing.
          schema:
            type: string
            example: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
      responses:
        "200":
          description: Asset retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetItem"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  # ==================== BALANCE ENDPOINTS ====================
  /balances/unified:
    get:
      operationId: listBalances
      tags:
        - Balances
      summary: List balances
      description: Returns unified balances across CeFi and DeFi for the authenticated user
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      responses:
        "200":
          description: Balances retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListBalancesResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /balances:
    get:
      operationId: getBalances
      summary: Get user balances
      description: Returns unified balances across CeFi and DeFi for the authenticated user
      tags:
        - Balances
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      responses:
        "200":
          description: Balances retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListBalancesResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
  /positions:
    get:
      operationId: listPositions
      tags:
        - Positions
      summary: List open positions
      description: >
        Returns a read-only list of the authenticated user's open positions. Data is fetched on demand from the venue; nothing is persisted.
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
      responses:
        "200":
          description: Positions retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListPositionsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"

  /portfolio:
    get:
      operationId: getPortfolio
      tags:
        - Balances
      summary: Get the authenticated user's portfolio
      description: >
        Unified portfolio across CeFi and DeFi venues: valued balances, open positions, and PnL in a single call.


        `total_usd` is total account equity: `balances_usd` plus the margin committed to open positions. Unrealized PnL is deliberately not added, because the perp balance row is already marked to market. `balances_usd` on its own is the value of spot balances, which excludes collateral committed to perps.


        A balance with no live price returns `price`, `value` and `change_24h_pct` as null and is excluded from every total.


        `cost_basis` is present only for non-quote assets acquired on platform. Quote and stable assets omit it, and so does any quantity received by deposit or bridge. Unlike `/balances`, an upstream failure fails the request: equity depends on both venues, so a partial total would be wrong rather than merely incomplete.
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: venue
          in: query
          required: false
          description: >
            Restrict the portfolio to one venue (`defi`, `cefi`). Defaults to all venues when omitted.
          schema:
            $ref: "#/components/schemas/Venue"
      responses:
        "200":
          description: The user's portfolio
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortfolioResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  # ==================== TRANSACTION ENDPOINTS ====================
  /transactions:
    get:
      operationId: listTransactions
      summary: List user transactions
      description: >
        Returns the caller's orders, transfers, and ramps as one paginated feed, newest first. Each row pairs a type-agnostic envelope with the full typed object named by `type`, so the per-type endpoints do not need merging client-side.


        Covers platform-originated activity only; inbound transfers and external deposits are not included. Open Hyperliquid orders are served live by `GET /orders` and appear here once terminal.


        Paginate with the previous page's `next_cursor`.
      tags:
        - Transactions
      security:
        - bearerAuth: []
      parameters:
        - $ref: "#/components/parameters/OnBehalfOf"
        - name: type
          in: query
          description: Comma-separated types to include. Defaults to all.
          required: false
          schema:
            type: string
            example: "order,transfer"
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of transactions to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Transactions retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListTransactionsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
  /organizations/{organization_id}/transactions:
    get:
      operationId: listOrganizationTransactions
      summary: List organization transactions
      description: >
        Orders and transfers of every user the organization serves, newest first, each row naming its user. Ramps are not included.


        Requires an organization token for this organization, or an admin member of it. `TM-On-Behalf-Of` is rejected.
      tags:
        - Transactions
      security:
        - bearerAuth: []
      parameters:
        - name: organization_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: user_id
          in: query
          description: Comma-separated user ids, at most 100. Defaults to every user served.
          required: false
          schema:
            type: string
        - name: type
          in: query
          description: "Comma-separated: `order`, `transfer`. Defaults to both."
          required: false
          schema:
            type: string
            example: "order,transfer"
        - name: status
          in: query
          description: Comma-separated statuses. Defaults to all.
          required: false
          schema:
            type: string
            example: "completed,failed"
        - name: from
          in: query
          description: Created at or after this instant.
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: Created before this instant. Must be after `from`.
          required: false
          schema:
            type: string
            format: date-time
        - name: cursor
          in: query
          description: Opaque pagination cursor from the previous page's `next_cursor`
          required: false
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of transactions to return
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Transactions retrieved successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListOrganizationTransactionsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalError"
        "503":
          $ref: "#/components/responses/ServiceUnavailable"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  parameters:
    OnBehalfOf:
      name: TM-On-Behalf-Of
      in: header
      required: false
      description: >
        Act as one of your organization's users. The value is the `user_id` returned when the user was created; the request then reads and writes that user's account. Requires an organization token and a user your organization created: `400` for a personal token, a repeated header or a non-UUID, `403` for a user outside your organization. Not accepted on organization-scoped routes.
      schema:
        type: string
        format: uuid
      example: 3f6d2c0e-8a41-4c2b-9f1e-2b7d5c0a9e11
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: >-
        Forbidden. On order creation this also covers an asset that is not available to trade from the country the request came from.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    UnprocessableEntity:
      description: Request is well-formed but cannot be processed (e.g. leverage missing or out of range for a perp order)
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    ServiceUnavailable:
      description: Service unavailable
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    OrderSide:
      type: string
      enum: [buy, sell]
      example: "buy"
      description: >
        The side of the order.

        * **buy** — Purchase the base asset using the quote asset.

        * **sell** — Sell the base asset in exchange for the quote asset.
    OrderType:
      type: string
      enum: [market, limit]
      example: "market"
      description: >
        The type of order to place — how the order executes.

        * **market** — Execute immediately at the best available price. Buy orders require `qty_unit: quote`. Price must not be specified.

        * **limit** — Place an order at a specific price. Requires `price` and `qty_unit: base`. `chain` is optional: omit it for a CeFi limit order, or supply a DeFi chain (e.g. `hypercore-spot`) to rest the order on-chain.

        With a `trigger`, the type is how the fired order executes and must be `market`.
    Trigger:
      type: object
      description: >
        Makes the order a TP/SL trigger: a reduce-only market close that rests off-book and fires when the mark price crosses `price`. Perp-only (`hypercore-perp`). A `take_profit` must rest on the profitable side of the position and a `stop_loss` on the losing side, or the order is rejected. The order `type` must be `market`, and `price`/`leverage` must not be specified; `reduce_only` is implied.
      required:
        - type
        - price
      properties:
        type:
          type: string
          enum: [take_profit, stop_loss]
          description: Trigger direction relative to the position.
        price:
          type: string
          description: Trigger price per unit of base asset as a decimal string.
          example: "70000.00"
    OrderStatus:
      type: string
      enum: [initialized, pending, cancel_pending, complete, canceled, active, failed]
      example: "complete"
      description: >
        The current status of the order.

        * **initialized** — Order has been created but not yet submitted. For DeFi orders, the client must sign the returned payloads and call the execute endpoint. For CeFi buy orders with insufficient balance, a funding bridge is prepared first.

        * **pending** — Order has been submitted but is not yet confirmed by the CeFi exchange or on-chain.

        * **active** — Order was accepted by the CeFi exchange and is open for trading. Applies to limit orders that are working in the order book.

        * **cancel_pending** — A cancellation request has been sent to the CeFi exchange and is awaiting confirmation.

        * **complete** — Order has been fully executed. For CeFi orders this means the CeFi exchange reported a fill; for DeFi orders the on-chain swap was confirmed.

        * **canceled** — Order was successfully canceled via a cancel request or by exchange/market conditions.

        * **failed** — Order was rejected by the CeFi exchange or DeFi execution failed (e.g. on-chain transaction reverted, balance check failed).
    SigningMethod:
      type: string
      enum: [web_authn, api_key]
      example: "api_key"
      description: >
        The authentication method used to sign transaction payloads.

        * **web_authn** — Signed using a passkey (WebAuthn/FIDO2 credential) via the browser.

        * **api_key** — Signed using an API key. Suitable for programmatic/headless access.
    Chain:
      type: string
      enum: [solana, base, robinhood, hypercore-spot, hypercore-perp]
      example: "solana"
      description: >
        The blockchain network for DeFi orders. Omit for CeFi orders.

        * **solana** — Execute the swap on the Solana blockchain.

        * **base** — Execute the swap on the Base (Ethereum L2) blockchain.

        * **robinhood** — Execute the swap on Robinhood Chain (Arbitrum-based Ethereum L2).

        * **hypercore-spot** — Execute the order on the Hyperliquid spot order book.

        * **hypercore-perp** — Execute the order on the Hyperliquid perpetuals order book.
    Venue:
      type: string
      enum: [defi, cefi]
      example: "defi"
      description: >
        The trading venue to filter by.

        * **defi** — Decentralized exchange (on-chain swaps).

        * **cefi** — Centralized exchange (off-chain order book).
    ProductType:
      type: string
      enum: [spot, perp]
      example: "spot"
      description: Whether the asset is spot or a perpetual (perp).
    AssetClass:
      type: string
      enum: [crypto, stock]
      example: "crypto"
      description: >
        The underlying instrument, orthogonal to product type. A `stock` is a tokenized equity, which is an ordinary spot or perp listing and quotes and executes as one. Absent on servers predating the field, which list crypto only.
    QuoteRequest:
      type: object
      description: Request to compute a market quote
      required:
        - base_asset
        - quote_asset
        - qty
        - qty_unit
        - side
      properties:
        base_asset:
          type: string
          description: Base asset identifier (e.g. `BTC`, `ETH`, `SOL`)
          example: "BTC"
        quote_asset:
          type: string
          description: Quote asset identifier (e.g. `USD`, `USDC`)
          example: "USD"
        qty:
          type: string
          description: Quantity as a positive decimal string
          example: "0.5"
        qty_unit:
          type: string
          enum: [base, quote]
          description: >
            Unit of the quantity.

            * **base** — Quantity is denominated in the base asset (e.g. 0.5 BTC).

            * **quote** — Quantity is denominated in the quote asset (e.g. 1000 USD).
          example: "quote"
        side:
          $ref: "#/components/schemas/OrderSide"
    QuoteResponse:
      type: object
      description: Quote computation result with the expected quantity, execution price, notional and fee
      properties:
        qty:
          type: string
          description: Expected base asset quantity as a decimal string, for buys and sells and for both `qty_unit` values. With `qty_unit=quote` it is rounded down to the base increment.
          example: "0.00156"
        price:
          type: string
          description: Effective execution price per unit of base asset as a decimal string
          example: "64000"
        notional:
          type: string
          description: Expected quote asset amount the order executes, before fees, as a decimal string. With `qty_unit=quote` it can be slightly less than the requested amount after base increment rounding.
          example: "99.84"
        fee:
          type: string
          description: Expected taker fee in `quote_asset` units as a decimal string. Added to the cost on a buy and deducted from the proceeds on a sell.
          example: "0.039936"
    CreateOrderRequest:
      type: object
      description: |
        Request to create a new order.

        **Identifying the asset** — provide exactly one of `asset_id` or `base_asset`
        (supplying both or neither is a `400`). `asset_id` is the id from
        `GET /assets` and is preferred; `base_asset` is the legacy identifier.

        **Limit orders** (`type: limit`):
        - `price` is required and must be a positive decimal string
        - `qty_unit` must be `base`
        - `chain` is optional (omit for CeFi; include a DeFi chain such as `hypercore-spot` to rest the order on-chain)

        **Market orders** (`type: market`):
        - `price` is not accepted
        - Buy orders require `qty_unit: quote`
        - Sell orders accept `qty_unit: base` or `qty_unit: quote`
        - `chain` is optional (omit for CeFi, include for DeFi)

        **Perp orders** (a perp `asset_id`, or `chain: hypercore-perp` with `base_asset`):
        - `leverage` is required to open a position (buy = long, sell = short) and must be between 1 and 50; it must be omitted for non-perp assets
        - `reduce_only: true` marks the order as a close of the opposite position; `leverage` is then ignored
        - `qty` is the isolated margin to commit; position notional = `qty` × `leverage`
        - `qty_unit` may be `quote` (margin) or `base` (position size) on either side

        **Trigger orders** (a `trigger` object, perp-only):
        - the order rests off-book and fires as a reduce-only market close when the mark price crosses `trigger.price`
        - a take-profit must rest on the profitable side of the position and a stop-loss on the losing side, or the quote is rejected
        - `type` must be `market`; `price` and `leverage` must not be sent; `reduce_only` is implied
      required:
        - qty
        - qty_unit
        - type
        - side
      properties:
        asset_id:
          type: string
          format: uuid
          description: >
            Asset id from `GET /assets`. Preferred way to identify the asset; chain and venue are derived from it. Provide exactly one of `asset_id` or `base_asset`.
          example: "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
        base_asset:
          type: string
          description: >
            Legacy asset identifier: asset symbol for CeFi (e.g. `BTC`); token contract address on `chain` for DeFi. Provide exactly one of `asset_id` or `base_asset`.
          example: "BTC"
        qty:
          type: string
          description: Quantity as a positive decimal string
          example: "100"
        price:
          type: string
          description: >
            Limit price per unit of base asset as a decimal string. Required for limit orders; must not be sent for market orders.
          example: "67500.00"
        trigger:
          $ref: "#/components/schemas/Trigger"
        qty_unit:
          type: string
          enum: [base, quote]
          description: >
            Unit of the quantity.

            * **base** — Quantity is denominated in the base asset. Required for limit orders. Supported for market sell orders.

            * **quote** — Quantity is denominated in the quote asset. Required for market buy orders. For DeFi sell orders, `base` must be used instead.
          example: "quote"
        type:
          $ref: "#/components/schemas/OrderType"
        side:
          $ref: "#/components/schemas/OrderSide"
        chain:
          allOf:
            - $ref: "#/components/schemas/Chain"
          description: >
            Blockchain network for DeFi orders. Omit for CeFi orders.
        leverage:
          type: integer
          format: uint16
          minimum: 1
          maximum: 50
          description: >
            Isolated-margin leverage for a perp order. Required when the resolved asset is a perp (a perp `asset_id`, or `chain: hypercore-perp`) and the order opens a position (not reduce-only); must not be sent for non-perp assets.
          example: 10
        reduce_only:
          type: boolean
          description: >
            Marks a perp order as a reduce-only close — it only reduces an existing position and never opens one. Only valid for perp assets.
          example: false
    UnsignedPayload:
      type: object
      description: >
        An unsigned transaction payload that the client must sign before executing the order. Sign each payload using your API key or WebAuthn credential, then submit the resulting stamps to the execute endpoint in the same order.
      required:
        - digest
        - payload
      properties:
        digest:
          type: string
          description: SHA-256 hash of the payload, used as the signing input
        payload:
          type: string
          description: Base64-encoded transaction payload to be signed
    QuoteDetails:
      type: object
      description: Detailed quote information returned with DeFi order creation, showing expected swap output and fees
      properties:
        base_asset:
          type: string
          description: Base asset identifier (e.g. `SOL`, `ETH`)
        quote_asset:
          type: string
          description: Quote asset identifier (e.g. `USDC`)
        qty:
          type: string
          description: Input quantity as a decimal string — the amount being swapped from
        qty_out:
          type: string
          description: Expected output quantity as a decimal string — the amount the user will receive after fees
        fee:
          type: string
          description: Platform fee amount as a decimal string
        fee_asset:
          type: string
          description: Asset in which the fee is denominated (e.g. `USDC`)
        issues:
          type: array
          items:
            type: string
          description: >
            Warnings about the quote (e.g. high price impact, low liquidity, `Insufficient balance`). Empty when there are no issues. An `Insufficient balance` entry means the account cannot fund the trade, in which case the response is quote-only (empty `order_id`, no `payloads`).
    CreateOrderResponse:
      type: object
      description: >
        Response from creating an order. For DeFi orders (and CeFi buy orders requiring a funding bridge), the response includes unsigned payloads that must be signed by the client and submitted via the execute endpoint. For CeFi sell orders and sufficiently funded CeFi buy orders, the order is submitted immediately and no payloads are returned. When a DeFi order cannot be funded, the response is quote-only: it carries the `quote` (with an `Insufficient balance` entry in `quote.issues`), an empty `order_id`, and no `payloads`, and no order is created.
      properties:
        order_id:
          type: string
          description: Unique order identifier. Empty when no order was created, e.g. a DeFi quote the account cannot fund.
        status:
          $ref: "#/components/schemas/OrderStatus"
        payloads:
          type: array
          items:
            $ref: "#/components/schemas/UnsignedPayload"
          description: >
            Unsigned transaction payloads that the client must sign and return via the execute endpoint. Present for DeFi orders and CeFi buy orders that require a funding bridge. Empty or absent when the order is submitted immediately (e.g. CeFi sell orders).
        quote:
          allOf:
            - $ref: "#/components/schemas/QuoteDetails"
          description: >
            DeFi orders only. For CeFi price previews, use `POST /quotes`. When `issues` reports an insufficient-balance problem, the response is quote-only: `order_id` is empty and there are no `payloads`.
        web_authn_payload:
          type: string
          description: WebAuthn payload (deprecated, use payloads instead)
          deprecated: true
    ExecuteOrderRequest:
      type: object
      description: >
        Request to execute an order that is in `initialized` status. The client must sign each payload returned by the create endpoint and submit the signatures in the same order.
      required:
        - signatures
        - auth_type
      properties:
        signatures:
          type: array
          items:
            type: string
          minItems: 1
          description: >
            Signed stamps for the unsigned payloads, in the same order as the payloads returned by the create endpoint. Each signature corresponds to one payload.
        auth_type:
          $ref: "#/components/schemas/SigningMethod"
    ExecuteOrderResponse:
      type: object
      description: >
        Response from executing an order. For DeFi orders, a successful execution transitions the order to `complete` (an immediate fill) or `active` (a limit order resting on-chain). For CeFi orders, the order moves to `pending` while it is processed by the CeFi exchange.
      properties:
        status:
          $ref: "#/components/schemas/OrderStatus"
    CancelOrderResponse:
      type: object
      description: >
        Response from the cancel endpoint. A resting DeFi order returns unsigned payloads the client must sign and submit to the cancel-execute endpoint. A CeFi order is canceled immediately and returns 202 with no payloads.
      properties:
        payloads:
          type: array
          items:
            $ref: "#/components/schemas/UnsignedPayload"
          description: >
            Unsigned cancel payloads the client signs and returns via the cancel-execute endpoint. Present for resting DeFi orders, absent for CeFi orders.
    CancelAllOrdersRequest:
      type: object
      description: Request to cancel all open orders on a venue.
      required:
        - venue
      properties:
        venue:
          $ref: "#/components/schemas/Venue"
    CancelAllOrdersResponse:
      type: object
      description: Result of a cancel-all request.
      properties:
        canceled_count:
          type: integer
          description: Number of open orders canceled by this request.
          example: 3
    ModifyOrderRequest:
      type: object
      description: >
        Request to modify an active limit order. At least one of `price` or `qty` must be supplied; any field that is omitted is left unchanged.
      properties:
        price:
          type: string
          description: New limit price per unit of base asset as a positive decimal string.
          example: "67500.00"
        qty:
          type: string
          description: New quantity as a positive decimal string.
          example: "0.5"
    GetOrderStatusResponse:
      type: object
      description: Order status response
      properties:
        status:
          $ref: "#/components/schemas/OrderStatus"
    OrderDetail:
      type: object
      description: >
        Order with execution data, returned by the list-orders and get-order endpoints for orders of any status. Includes fill information from the CeFi exchange for CeFi orders.
      properties:
        order_id:
          type: string
          description: Unique order identifier
        asset_id:
          type: string
          format: uuid
          nullable: true
          description: Asset id the order was placed against. May be null for orders sourced directly from the venue.
        asset_symbol:
          type: string
          nullable: true
          description: Asset symbol the order was placed against. May be null for orders sourced directly from the venue.
        base_asset:
          type: string
          description: Base asset symbol (e.g. `BTC`, `ETH`, `SOL`)
        quote_asset:
          type: string
          description: Quote asset symbol (`PYUSD` for CeFi, `USDC` for DeFi)
        type:
          $ref: "#/components/schemas/OrderType"
        side:
          $ref: "#/components/schemas/OrderSide"
        price:
          type: string
          nullable: true
          description: >
            For limit orders, the limit price submitted. For market orders, the reference price at order creation. Null when no price was recorded.
        qty:
          type: string
          description: Original order quantity in the denomination specified by `qty_unit` at creation
        qty_unit:
          type: string
          enum: [base, quote]
          description: Denomination of `qty` at creation
        executed_qty:
          type: string
          description: Quantity of the base asset that has been filled so far
        leaves_qty:
          type: string
          description: Remaining base asset quantity yet to be filled. Zero when the order is complete.
        executed_vwap:
          type: string
          description: Volume-weighted average price across all fills for this order
        fee:
          type: string
          description: >
            Total fee charged for this order in the quote asset. For CeFi orders this is the cumulative `trade_fee` across all fills; for DeFi orders it is the service fee captured at quote time, written once on confirmation.
        tx_hash:
          type: string
          description: On-chain transaction hash for DeFi orders. Omitted for CeFi orders.
        explorer_url:
          type: string
          description: >
            Public block-explorer page for the order. Hyperliquid orders link to the wallet's address page on the Hyperliquid explorer, since only the venue order id is recorded. Set on `GET /orders` and the transaction feed, like `asset_type`; omitted for CeFi orders and until the venue has acknowledged the order.
        failure_reason:
          type: string
          description: >
            Human-readable reason a failed order failed, sourced from the venue (e.g. insufficient balance, below minimum size). Present only on failed CeFi orders; omitted otherwise.
        venue:
          $ref: "#/components/schemas/Venue"
        status:
          $ref: "#/components/schemas/OrderStatus"
        created_at:
          type: string
          format: date-time
          description: Timestamp when the order was created (RFC 3339)
        asset_type:
          type: string
          enum: [spot, perp]
          description: >
            Product type of the traded asset. `perp` for Hyperliquid perpetuals, `spot` otherwise. Lets clients tell perp orders apart from spot ones sharing the same symbol.
    Pagination:
      type: object
      description: >
        Cursor-based pagination metadata. The cursor is opaque and must be passed back verbatim; never parse or construct one.
      properties:
        next_cursor:
          type: string
          nullable: true
          description: Opaque cursor for the next page, null when the feed is exhausted
        limit:
          type: integer
          description: Number of items per page
    GetOrdersResponse:
      type: object
      description: Paginated list of orders with execution data
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/OrderDetail"
          description: List of orders
        pagination:
          $ref: "#/components/schemas/Pagination"
    ListBalancesResponse:
      type: object
      description: Unified balances across CeFi and DeFi venues
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BalanceItem"
          description: List of asset balances
    BalanceItem:
      type: object
      description: A single asset balance on a specific venue
      properties:
        asset_id:
          type: string
          format: uuid
          description: >-
            Unique asset identifier; pass as `asset_id` when creating an order. Empty when the asset is not in the catalog.
        economic_asset_id:
          type: string
          format: uuid
          description: Economic asset this listing belongs to, shared across chains; omitted for CeFi rows
        venue:
          $ref: "#/components/schemas/Venue"
        symbol:
          type: string
          description: Asset ticker symbol (e.g. BTC, USDC)
        name:
          type: string
          description: Human-readable asset name
        chain:
          type: string
          nullable: true
          description: Blockchain network ("solana", "base"), or null for exchange-held assets
        address:
          type: string
          nullable: true
          description: Token contract/mint address, or null for exchange-held assets
        decimals:
          type: integer
          description: Display precision (e.g. 8 for BTC, 6 for USDC)
        total:
          type: string
          description: Gross balance including held amounts (decimal string)
        available:
          type: string
          description: Usable balance after holds (decimal string)
        held:
          type: string
          description: Amount locked in orders or transfers (decimal string)
        stable:
          type: boolean
          description: Whether this is a stablecoin
        tradeable:
          type: boolean
          description: Whether this asset is active for trading
    ListPositionsResponse:
      type: object
      description: A user's open positions
      required:
        - positions
      properties:
        positions:
          type: array
          items:
            $ref: "#/components/schemas/Position"
          description: Open positions
    Position:
      type: object
      description: A single open position
      properties:
        asset_id:
          type: string
          format: uuid
          description: >-
            Unique asset identifier for the perp; pass as `asset_id` when creating an order. Empty when the coin is not listed.
        venue:
          $ref: "#/components/schemas/Venue"
        symbol:
          type: string
          description: Asset ticker symbol (e.g. BTC)
        side:
          type: string
          enum: [long, short]
          description: Position direction
        size:
          type: string
          description: Absolute position size in the base asset (decimal string)
        entry_price:
          type: string
          description: Average entry price (decimal string)
        mark_price:
          type: string
          description: Current mark price used to value the position (decimal string)
        liquidation_price:
          type: string
          nullable: true
          description: Estimated liquidation price, or null when none is reported
        margin_used:
          type: string
          description: Margin committed to this position (decimal string)
        unrealized_pnl:
          type: string
          description: >-
            Signed unrealized PnL at mark (decimal string). Reported but never added into a portfolio total; the perp balance row is already marked to market.
        return_on_equity:
          type: string
          description: Unrealized PnL as a fraction of margin used (decimal string)
        leverage:
          type: integer
          description: Configured leverage for the position
    PortfolioResponse:
      type: object
      description: >-
        The user's portfolio across the venues in scope: valued balances, open positions, and PnL.
      required:
        - total_usd
        - balances_usd
        - cash_usd
        - change_24h_usd
        - change_24h_pct
        - unrealized_pnl_usd
        - realized_pnl_usd
        - balances
        - positions
      properties:
        total_usd:
          type: string
          description: >-
            Total account equity (decimal string): balances_usd plus margin committed to open positions. Unrealized PnL is not added; the perp balance row is already marked to market.
        balances_usd:
          type: string
          description: >-
            Value of spot balances (decimal string). Excludes collateral committed to open perps and excludes unpriced assets.
        cash_usd:
          type: string
          description: >-
            Value of stablecoin and quote-asset balances at the venues in scope (decimal string).
        change_24h_usd:
          type: string
          description: Rolling 24h change in balance value (decimal string)
        change_24h_pct:
          type: string
          description: Rolling 24h change as a percent (decimal string)
        unrealized_pnl_usd:
          type: string
          description: >-
            Spot unrealized PnL plus position unrealized PnL (decimal string). Spot covers on-platform acquisitions only.
        realized_pnl_usd:
          type: string
          description: Realized PnL from on-platform spot sells (decimal string)
        balances:
          type: array
          items:
            $ref: "#/components/schemas/PortfolioBalance"
        positions:
          type: array
          items:
            $ref: "#/components/schemas/Position"
    PortfolioBalance:
      type: object
      description: >-
        A single asset balance with USD valuation. price, value and change_24h_pct are null when the asset has no live price.
      required:
        - symbol
        - venue
        - decimals
        - total
        - available
        - held
        - stable
        - tradeable
      properties:
        asset_id:
          type: string
          format: uuid
          description: >-
            Unique asset identifier; pass as `asset_id` when creating an order. Absent when the asset is not in the catalog.
        symbol:
          type: string
          description: Asset ticker symbol (e.g. BTC, USDC)
        name:
          type: string
          description: Human-readable asset name
        venue:
          $ref: "#/components/schemas/Venue"
        chain:
          type: string
          nullable: true
          description: Blockchain network, or null for exchange-held assets
        address:
          type: string
          nullable: true
          description: Token contract/mint address, or null for exchange-held assets
        decimals:
          type: integer
          description: Display precision
        icon:
          type: string
          nullable: true
          description: Icon image URL
        status:
          type: string
          enum: [active, preview, sell_only, transfer_only, disabled]
          description: Per-listing trading status
        stable:
          type: boolean
          description: Whether this is a stablecoin
        tradeable:
          type: boolean
          description: Whether this asset is active for trading
        total:
          type: string
          description: Gross balance including held amounts (decimal string)
        available:
          type: string
          description: Usable balance after holds (decimal string)
        held:
          type: string
          description: Amount locked in orders or transfers (decimal string)
        price:
          type: string
          nullable: true
          description: Current USD price per unit; null when unpriced
        value:
          type: string
          nullable: true
          description: USD value of total; null when unpriced and excluded from totals
        change_24h_pct:
          type: string
          nullable: true
          description: Rolling 24h price change as a percent (decimal string)
        cost_basis:
          $ref: "#/components/schemas/PortfolioCostBasis"
    PortfolioCostBasis:
      type: object
      description: >-
        On-platform cost basis for one asset symbol, FIFO over buys. Absent for quote and stable assets and when the holding was acquired entirely off platform.
      required:
        - avg_entry_price
        - cost_usd
        - qty
        - realized_pnl
        - unrealized_pnl
      properties:
        avg_entry_price:
          type: string
          description: FIFO average entry price of the still-held on-platform quantity
        cost_usd:
          type: string
          description: USD cost of the still-held on-platform quantity
        qty:
          type: string
          description: >-
            Still-held quantity acquired on platform, clamped so it never exceeds the row's total.
        realized_pnl:
          type: string
          description: Realized PnL from sells; sell fees reduce proceeds
        unrealized_pnl:
          type: string
          description: Mark-to-market PnL on the still-held on-platform quantity
    AssetImage:
      type: object
      description: Asset image URLs at various resolutions
      properties:
        thumb:
          type: string
        small:
          type: string
        large:
          type: string
    AssetMarketData:
      type: object
      description: Supply-side market data
      properties:
        circulating_supply:
          type: integer
          format: int64
        total_supply:
          type: integer
          format: int64
        max_supply:
          type: integer
          format: int64
    AssetPerpData:
      type: object
      description: >
        Perp-only market data, present only for perp assets. Values are decimal strings for precision and are null until a market snapshot has populated them.
      properties:
        funding_rate:
          type: string
          nullable: true
          description: Current hourly funding rate.
        open_interest:
          type: string
          nullable: true
          description: Open interest in base units.
        volume_24h:
          type: string
          nullable: true
          description: 24h notional volume.
        max_leverage:
          type: integer
          nullable: true
          description: Maximum leverage supported for this perp.
    AssetSocials:
      type: object
      description: Social media links
      properties:
        x_username:
          type: string
        facebook_username:
          type: string
        subreddit_url:
          type: string
        official_forum_url:
          type: string
    AssetNetwork:
      type: object
      description: >
        A deposit/withdrawal network supported for a CeFi asset, together with any additional networks whose deposits route to the same address. This is the source of truth for the `network` field when creating a CeFi transfer via [`createTransfer`](#operation/createTransfer): that field must match this `network` or one of its `compatible_networks` (case-insensitive).
      required: [network, compatible_networks]
      properties:
        network:
          type: string
          description: Canonical network name for this deposit/withdrawal rail (e.g. `bitcoin`).
          example: "bitcoin"
        compatible_networks:
          type: array
          items:
            type: string
          description: >
            Additional network names whose deposits route to the same address as `network`, including `network` itself. Any of these is an accepted `network` value for a CeFi transfer.
    AssetItem:
      type: object
      description: A single tradeable asset
      required:
        - networks
      properties:
        id:
          type: string
          format: uuid
          description: Unique asset identifier; pass as `asset_id` when creating an order.
        chain:
          type: string
          nullable: true
          description: Blockchain network (null for CeFi assets)
        address:
          type: string
          nullable: true
          description: Token contract address (null for CeFi assets)
        symbol:
          type: string
          description: Asset ticker symbol (e.g. BTC, SOL)
        name:
          type: string
          description: Human-readable asset name
        decimals:
          type: integer
          minimum: 0
          maximum: 255
          description: Token decimal precision
        slug:
          type: string
          description: URL-safe asset identifier
        is_active:
          type: boolean
        status:
          type: string
          enum:
            - active
            - preview
            - sell_only
            - transfer_only
            - disabled
          description: >
            Per-listing trading status. `GET /assets` lists only `active` listings, while `GET /assets/{chain}/{address}` returns any status, so clients gate on this field directly.
        description:
          type: string
        website:
          type: string
        icon:
          type: string
          nullable: true
          description: Icon image URL
        tradeable:
          type: boolean
          description: Whether this asset can be traded directly
        stable:
          type: boolean
          description: Whether this is a stablecoin
        venue:
          $ref: "#/components/schemas/Venue"
        type:
          $ref: "#/components/schemas/ProductType"
        asset_class:
          $ref: "#/components/schemas/AssetClass"
        image:
          $ref: "#/components/schemas/AssetImage"
        market_data:
          $ref: "#/components/schemas/AssetMarketData"
        perp:
          type: object
          allOf:
            - $ref: "#/components/schemas/AssetPerpData"
          nullable: true
          description: Perp-only market data; present only for perp assets.
        socials:
          $ref: "#/components/schemas/AssetSocials"
        networks:
          type: array
          items:
            $ref: "#/components/schemas/AssetNetwork"
    AssetAvailability:
      type: object
      description: Asset families the caller's country is allowed to trade
      required:
        - country
        - allowed_product_types
        - allowed_asset_classes
      properties:
        country:
          type: string
          pattern: "^[A-Z]{2}$"
          description: >-
            ISO 3166-1 alpha-2 country the request resolved to, or `XX` when it could not be resolved.
          example: US
        allowed_product_types:
          type: array
          description: Product types the country may trade. Empty means none.
          example: [spot, perp]
          items:
            $ref: "#/components/schemas/ProductType"
        allowed_asset_classes:
          type: array
          description: Asset classes the country may trade. Empty means none.
          example: [crypto]
          items:
            $ref: "#/components/schemas/AssetClass"
    ListAssetsResponse:
      type: object
      description: Paginated list of tradeable assets
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AssetItem"
        pagination:
          $ref: "#/components/schemas/Pagination"
    TransferStatus:
      type: string
      enum: [awaiting_signature, pending, completed, failed]
      example: "pending"
      description: >
        The current status of the transfer.

        * **awaiting_signature** — Transfer has been created and is waiting for the client to sign the unsigned payloads and call the execute endpoint.

        * **pending** — Signed transaction has been submitted and is awaiting on-chain confirmation.

        * **completed** — Transfer has been confirmed on-chain.

        * **failed** — Transfer failed due to an on-chain error or rejection.
    CreateDepositRequest:
      type: object
      description: Request to commit wallet balance to CeFi trading
      required:
        - asset_id
        - amount
      properties:
        asset_id:
          type: string
          format: uuid
          description: DeFi listing identifier (UUID)
          example: "b3d9e5f2-1a4c-4e7b-9f0d-2c8a6b3e5f91"
        amount:
          type: string
          description: Amount to commit, as a positive decimal string
          example: "100.00"

    DepositStatus:
      type: string
      enum: [allocating, crediting, releasing, completed, rejected, stranded]
      example: "crediting"
      description: >
        Where the deposit stands between the DeFi allocation and the CeFi credit.

        * **allocating** — The DeFi allocation raise is in flight.

        * **crediting** — The allocation is raised and the exchange has been asked to credit it.

        * **releasing** — The exchange refused the deposit and the allocation is still owed back.

        * **completed** — The exchange credited the deposit.

        * **rejected** — The exchange refused the deposit and the allocation has been released.

        * **stranded** — The outcome is unknown and an operator has to resolve it.

    DepositDetail:
      type: object
      description: A deposit and what it has left behind on each side so far.
      required:
        - id
        - status
        - asset_id
        - asset_symbol
        - amount
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Deposit identifier
          example: "c1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
        status:
          $ref: "#/components/schemas/DepositStatus"
        asset_id:
          type: string
          format: uuid
          description: DeFi listing identifier (UUID)
          example: "b3d9e5f2-1a4c-4e7b-9f0d-2c8a6b3e5f91"
        asset_symbol:
          type: string
          description: Symbol of the listing
          example: "USDC"
        amount:
          type: string
          description: Amount committed by this deposit, as a decimal string
          example: "100.00"
        allocation:
          type: string
          description: The caller's whole allocation of the listing once raised, as a decimal string
          example: "250.00"
        transfer:
          $ref: "#/components/schemas/CustodyTransfer"
        failure_reason:
          type: string
          description: Why the deposit was refused or stranded
          example: "cefi REJECTED"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    CustodyTransfer:
      type: object
      description: The CeFi transfer a deposit or withdrawal started, under the exchange's id
      required:
        - id
        - status
      properties:
        id:
          type: string
          description: Exchange transfer identifier
          example: "a7f3c2e1-9b4d-4e6f-8a1c-3d5e7f9b2c4a"
        status:
          type: string
          enum: [INITIALIZED, PENDING, PROCESSING, COMPLETED, REJECTED, FAILED]
          description: Status as last seen from the exchange
          example: "COMPLETED"

    ListDepositsResponse:
      type: object
      description: Paginated list of deposits
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DepositDetail"
          description: List of deposits
        pagination:
          $ref: "#/components/schemas/Pagination"
    CreateWithdrawalRequest:
      type: object
      description: Request to take committed balance back out of CeFi trading
      required:
        - asset_id
        - amount
      properties:
        asset_id:
          type: string
          format: uuid
          description: DeFi listing identifier (UUID)
          example: "b3d9e5f2-1a4c-4e7b-9f0d-2c8a6b3e5f91"
        amount:
          type: string
          description: Amount to take out, as a positive decimal string
          example: "100.00"

    WithdrawalStatus:
      type: string
      enum: [debiting, completed, rejected, stranded]
      example: "debiting"
      description: >
        Where the withdrawal stands.

        * **debiting** — The exchange has been asked to withdraw the amount.

        * **completed** — The exchange released the allocation and debited the amount.

        * **rejected** — The exchange refused the withdrawal; the amount stays committed.

        * **stranded** — The outcome is unknown and an operator has to resolve it.

    WithdrawalDetail:
      type: object
      description: A withdrawal and the CeFi transfer it started.
      required:
        - id
        - status
        - asset_id
        - asset_symbol
        - amount
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Withdrawal identifier
          example: "c1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
        status:
          $ref: "#/components/schemas/WithdrawalStatus"
        asset_id:
          type: string
          format: uuid
          description: DeFi listing identifier (UUID)
          example: "b3d9e5f2-1a4c-4e7b-9f0d-2c8a6b3e5f91"
        asset_symbol:
          type: string
          description: Symbol of the listing
          example: "USDC"
        amount:
          type: string
          description: Amount taken out by this withdrawal, as a decimal string
          example: "100.00"
        transfer:
          $ref: "#/components/schemas/CustodyTransfer"
        failure_reason:
          type: string
          description: Why the withdrawal was refused or stranded
          example: "cefi REJECTED"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    ListWithdrawalsResponse:
      type: object
      description: Paginated list of withdrawals
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WithdrawalDetail"
          description: List of withdrawals
        pagination:
          $ref: "#/components/schemas/Pagination"
    CreateTransferRequest:
      type: object
      description: Request to create a new on-chain transfer
      required:
        - asset_id
        - qty
        - qty_unit
        - to
      properties:
        asset_id:
          type: string
          format: uuid
          description: Asset identifier (UUID)
          example: "b3d9e5f2-1a4c-4e7b-9f0d-2c8a6b3e5f91"
        qty:
          type: string
          description: Transfer quantity as a positive decimal string
          example: "100.00"
        qty_unit:
          type: string
          enum: [base, quote]
          description: >
            Unit of the quantity.

            * **base** — Quantity is denominated in the base asset.

            * **quote** — Quantity is denominated in the quote asset.
          example: "base"
        to:
          type: string
          description: Destination wallet address
          example: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
        network:
          type: string
          description: >
            Destination network for the withdrawal. **Required for CeFi transfers** and **must be omitted for DeFi transfers** (DeFi derives the network from the asset's chain).


            The set of supported networks is asset-specific and is retrieved from the [`listAssets`](#operation/listAssets) (`GET /assets`) response: for the asset whose `id` equals this request's `asset_id`, `network` must match one of that asset's `networks[].network` values or any of their `networks[].compatible_networks` values. Matching is case-insensitive. Supplying an unsupported network returns `400 Bad Request`.
          example: "bitcoin"
    ExecuteTransferRequest:
      type: object
      description: >
        Request to execute a transfer that is in `awaiting_signature` status. The client must sign each payload returned by the create endpoint and submit the signatures in the same order.
      required:
        - signatures
        - auth_type
      properties:
        signatures:
          type: array
          items:
            type: string
          minItems: 1
          description: >
            Signed stamps for the unsigned payloads, in the same order as the payloads returned by the create endpoint.
        auth_type:
          $ref: "#/components/schemas/SigningMethod"
    TransferDetail:
      type: object
      description: Canonical representation of a transfer.
      required:
        - id
        - status
        - venue
        - asset_id
        - asset_symbol
        - chain
        - network
        - to
        - qty
        - qty_unit
        - sent
        - fee
        - received
        - tx_hash
        - payloads
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique transfer identifier
        status:
          $ref: "#/components/schemas/TransferStatus"
        venue:
          $ref: "#/components/schemas/Venue"
        asset_id:
          type: string
          format: uuid
          description: Asset identifier
        asset_symbol:
          type: string
          description: Asset ticker symbol (e.g. `USDC`, `SOL`)
        chain:
          type: string
          nullable: true
          description: Blockchain network (e.g. `solana`, `base`) for DeFi transfers, or null for CeFi transfers
        network:
          type: string
          nullable: true
          description: >
            Destination network the CeFi withdrawal was submitted on (one of the asset's supported networks from `GET /assets`), or null for DeFi transfers.
          example: "bitcoin"
        to:
          type: string
          description: Destination wallet address
        qty:
          type: string
          description: Transfer quantity as a decimal string
        qty_unit:
          type: string
          enum: [base, quote]
          description: Unit of the quantity
        sent:
          type: string
          description: Amount sent as a decimal string
        fee:
          type: string
          description: Fee as a decimal string
        received:
          type: string
          description: Amount received as a decimal string
        tx_hash:
          type: string
          description: On-chain transaction hash
        explorer_url:
          type: string
          nullable: true
          description: Public block-explorer page for `tx_hash`, null until the transfer is broadcast
        payloads:
          type: array
          items:
            $ref: "#/components/schemas/UnsignedPayload"
          description: >
            Unsigned transaction payloads for the client to sign. Present when status is `awaiting_signature`; empty array after execution.
        created_at:
          type: string
          format: date-time
          description: Timestamp when the transfer was created (RFC 3339)
        updated_at:
          type: string
          format: date-time
          description: Timestamp of the last status update (RFC 3339)
    ListTransfersResponse:
      type: object
      description: Paginated list of transfers
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TransferDetail"
          description: List of transfers
        pagination:
          $ref: "#/components/schemas/Pagination"
    CreateRampRequest:
      type: object
      description: Request to create a ramp
      required:
        - payment_method
        - direction
        - amount
      properties:
        payment_method:
          $ref: "#/components/schemas/RampPaymentMethod"
        direction:
          type: string
          enum:
            - onramp
            - offramp
          description: "`onramp` buys crypto with fiat. `offramp` sells crypto for fiat."
        amount:
          type: string
          description: >
            Decimal string. Fiat to spend on an onramp, or settlement stablecoin to sell on an offramp.
          example: "100.50"
        channel:
          type: string
          enum:
            - web
            - ios
            - android
          description: Surface the request originates from. Required for `APPLE_PAY` and `GOOGLE_PAY`.
          example: ios
    CreateRampResponse:
      type: object
      description: A created ramp, with the provider page to complete it on
      required:
        - id
        - redirect_url
      properties:
        id:
          type: string
          format: uuid
          description: Ramp ID, used by every other ramp endpoint
        redirect_url:
          type: string
          description: Provider page the user completes the sale on
        bridge_plan:
          $ref: "#/components/schemas/RampBridgePlan"
    RampBridgePlan:
      type: object
      description: >
        Present when the user's own funds must move onto the settlement chain before the offramp transfer. Sign every payload and submit the signatures to `POST /ramps/{id}/bridge/execute`.
      required:
        - id
        - payloads
        - steps
        - shortfall
      properties:
        id:
          type: string
          description: Bridge ID
        payloads:
          type: array
          items:
            $ref: "#/components/schemas/UnsignedPayload"
        steps:
          type: array
          items:
            $ref: "#/components/schemas/RampBridgeStep"
        shortfall:
          $ref: "#/components/schemas/RampBridgeShortfall"
    RampBridgeStep:
      type: object
      description: One fund movement in a bridge plan
      required:
        - kind
        - amount
        - asset_symbol
        - src_chain
      properties:
        kind:
          type: string
          description: The kind of movement, e.g. a same-chain swap or a cross-chain bridge
        amount:
          type: string
          description: Amount moved in this step, as a decimal string
        asset_symbol:
          type: string
          description: Symbol debited in this step
        dst_asset_symbol:
          type: string
          description: Symbol credited in this step, when it differs from the debited one
        src_chain:
          type: string
          description: Chain the step debits from
    RampBridgeShortfall:
      type: object
      description: The amount of the settlement asset the bridge plan covers
      required:
        - amount
        - asset_symbol
      properties:
        amount:
          type: string
          description: Amount to be bridged, as a decimal string
        asset_symbol:
          type: string
          description: Settlement asset symbol
    RampBridgeExecuteRequest:
      type: object
      description: Signatures over a bridge plan's payloads, in the same order
      required:
        - signatures
        - auth_type
      properties:
        signatures:
          type: array
          items:
            type: string
          minItems: 1
        auth_type:
          $ref: "#/components/schemas/SigningMethod"
    RampBridgeExecuteResponse:
      type: object
      description: The executed bridge
      required:
        - bridge_id
      properties:
        bridge_id:
          type: string
    RampTransferPrepareResponse:
      type: object
      description: Unsigned payloads for the transfer that sends funds to the provider
      required:
        - transfer_id
        - payloads
      properties:
        transfer_id:
          type: string
        payloads:
          type: array
          items:
            $ref: "#/components/schemas/UnsignedPayload"
    RampTransferExecuteRequest:
      type: object
      description: The prepared transfer and the signatures over its payloads
      required:
        - transfer_id
        - signatures
        - auth_type
      properties:
        transfer_id:
          type: string
          description: Transfer ID returned by the prepare endpoint
        signatures:
          type: array
          items:
            type: string
          minItems: 1
        auth_type:
          $ref: "#/components/schemas/SigningMethod"
    RampTransferExecuteResponse:
      type: object
      description: The settled on-chain transfer to the provider
      required:
        - tx_hash
        - chain
        - asset
        - from
        - to
        - sent
        - fee
        - received
      properties:
        tx_hash:
          type: string
        chain:
          type: string
        asset:
          type: string
        from:
          type: string
        to:
          type: string
        sent:
          type: string
        fee:
          type: string
        received:
          type: string
    RampDetail:
      type: object
      description: >
        Canonical representation of a ramp, served from the Gateway's own record. The settlement fields are filled in as the ramp progresses, so they are absent on a freshly created ramp and present once it settles.
      required:
        - id
        - payment_method
        - direction
        - status
        - amount
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
        payment_method:
          $ref: "#/components/schemas/RampPaymentMethod"
        direction:
          type: string
          enum:
            - onramp
            - offramp
        status:
          $ref: "#/components/schemas/RampStatus"
        amount:
          type: string
          description: Amount requested at creation, in the settlement asset
        asset_symbol:
          type: string
        asset_amount:
          type: string
          description: Amount actually settled
        fiat_currency:
          type: string
        fiat_amount:
          type: string
        fee_amount:
          type: string
        fee_currency:
          type: string
        exchange_rate:
          type: string
        wallet_address:
          type: string
          description: Address the ramp settles against
        provider_wallet_address:
          type: string
          description: Provider deposit address the offramp transfer sends to
        tx_hash:
          type: string
        redirect_url:
          type: string
        failure_reason:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
    AssetFlow:
      type: string
      description: >
        Direction the row's asset moved relative to the caller's holdings, for rendering a row without reading the typed object. Scoped to `asset_symbol`, so a buy is `in` even though value moved out. Compose your own label from `type` and this field.
      enum:
        - in
        - out
    TransactionType:
      type: string
      description: Kind of activity a transaction-feed row represents.
      enum:
        - order
        - transfer
        - ramp
    TransactionStatus:
      type: string
      description: >
        Lifecycle bucket shared by all three types. Each type's native status stays verbatim inside the row's typed object.
      enum:
        - pending
        - completed
        - failed
        - canceled
    TransactionDetail:
      type: object
      description: >
        One feed row. Exactly one of `order`, `transfer`, or `ramp` is present, matching `type`, and holds the same shape that type's own endpoint returns.
      properties:
        id:
          type: string
          format: uuid
          description: Id of the underlying order, transfer, or ramp
        type:
          $ref: "#/components/schemas/TransactionType"
        asset_flow:
          $ref: "#/components/schemas/AssetFlow"
        status:
          $ref: "#/components/schemas/TransactionStatus"
        created_at:
          type: string
          format: date-time
          description: When the row was created
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: When the row reached a terminal status; null while in flight
        qty:
          type: string
          nullable: true
          description: >
            Quantity denominated in `asset_symbol`: executed quantity for a filled order, requested quantity for an unfilled one, transferred quantity for a transfer, settled amount for a ramp. Null when none is known yet — an unfilled quote-denominated order, or an unsettled ramp.
        asset_id:
          type: string
          format: uuid
          nullable: true
          description: Null for ramps until they carry an asset id
        asset_symbol:
          type: string
          nullable: true
        tx_hash:
          type: string
          nullable: true
          description: Set once the row settles on-chain
        explorer_url:
          type: string
          nullable: true
          description: >
            Public block-explorer page for the row: the order's or transfer's, or the Solana page for a ramp. Null while `tx_hash` is null and for CeFi orders.
        failure_reason:
          type: string
          nullable: true
          description: Venue-supplied reason, set only on a failed row
        order:
          allOf:
            - $ref: "#/components/schemas/OrderDetail"
          description: Present only when `type` is `order`
        transfer:
          allOf:
            - $ref: "#/components/schemas/TransferDetail"
          description: Present only when `type` is `transfer`
        ramp:
          allOf:
            - $ref: "#/components/schemas/RampDetail"
          description: Present only when `type` is `ramp`
    ListTransactionsResponse:
      type: object
      description: Paginated unified feed of orders, transfers, and ramps
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TransactionDetail"
          description: List of transactions, newest first
        pagination:
          $ref: "#/components/schemas/Pagination"
    OrganizationTransaction:
      allOf:
        - $ref: "#/components/schemas/TransactionDetail"
        - type: object
          description: A transaction with the served user it belongs to
          required:
            - user_id
          properties:
            user_id:
              type: string
              format: uuid
              description: The served user this transaction belongs to
    ListOrganizationTransactionsResponse:
      type: object
      description: Paginated feed across an organization's users
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/OrganizationTransaction"
          description: Transactions, newest first
        pagination:
          $ref: "#/components/schemas/Pagination"
    ListRampsResponse:
      type: object
      description: Paginated list of ramps
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/RampDetail"
          description: List of ramps
        pagination:
          $ref: "#/components/schemas/Pagination"
    RampPaymentMethod:
      type: string
      description: >
        Rail the ramp is funded or paid out through. DeFi routes the provider from it, so it is the caller's only choice of venue. `APPLE_PAY` and `GOOGLE_PAY` are onramp-only and require a `channel`.
      enum:
        - COINBASE
        - PAYPAL
        - APPLE_PAY
        - GOOGLE_PAY
    RampStatus:
      type: string
      description: >
        Ramp lifecycle: `created` until funds move, `pending` while the provider settles, then `completed`, `failed`, or `expired` if it was abandoned before any funds moved.
      enum:
        - created
        - pending
        - completed
        - failed
        - expired
    Error:
      type: object
      description: Shared API error envelope
      required:
        - type
        - message
        - request_id
      properties:
        type:
          type: string
          description: Closed error category fixing the HTTP status
          enum:
            - invalid_argument
            - unauthenticated
            - permission_denied
            - not_found
            - method_not_allowed
            - conflict
            - failed_precondition
            - resource_exhausted
            - unavailable
            - internal
        code:
          type: string
          description: >-
            Specific error condition from the fleet code registry. Extensible: clients MUST tolerate values not listed here and fall back to type-based handling. Omitted when no code applies.
          x-extensible-enum:
            - allowance_approval_required
            - already_submitted
            - amount_above_maximum
            - amount_below_minimum
            - buy_not_allowed
            - chain_not_supported
            - guest_checkout_limit_exceeded
            - guest_checkout_unavailable
            - insufficient_balance
            - insufficient_native_balance
            - invalid_leverage
            - invalid_otp_code
            - invalid_qty_precision
            - kyc_required
            - no_liquidity
            - order_rejected
            - phone_not_verified
            - phone_verification_expired
            - prepared_action_not_found
            - price_out_of_range
            - quote_stale
            - reduce_only_exceeds_position
            - same_asset
            - sell_not_allowed
            - session_expired
            - wallet_exported
        message:
          type: string
          description: Human-readable error message
        metadata:
          type: object
          description: >-
            Machine-readable context scoped to `code`; values are always strings. Which keys appear is determined by `code`.
          additionalProperties:
            type: string
        field_violations:
          type: array
          description: >-
            Per-field rejections, present on `invalid_argument` when the request failed field validation.
          items:
            type: object
            required:
              - field
              - message
            properties:
              field:
                type: string
                description: Dotted path to the offending field, as the client sent it
              message:
                type: string
                description: Human-readable reason the field was rejected
        request_id:
          type: string
          description: Per-request correlation ID, empty when unavailable
