{
  "openapi": "3.1.0",
  "info": {
    "title": "LayerHop API",
    "version": "0.1.0",
    "summary": "Best-price cross-chain and same-chain swaps through one non-custodial API.",
    "description": "LayerHop is a meta-aggregator. `GET /v1/quote` asks every liquidity provider that supports the\nroute (Jupiter, Relay, deBridge, 0x, KyberSwap, LI.FI) in parallel and ranks the answers by time-adjusted\noutput for the user. `POST /v1/orders` turns a quote into a transaction the user's own wallet\nsigns. LayerHop never holds funds.\n\nConventions:\n- Amounts are integer strings in base units (never floats).\n- Chains are given as a numeric id or a slug (`base`, `solana`). Solana uses LayerHop's\n  internal id `7565164`.\n- Tokens are given as an address / mint, a symbol from the curated token list (`USDC`), or the\n  chain's native symbol (`ETH`, `BERA`). Search every token with `GET /v1/tokens`.\n- Every response carries an `x-request-id` header; error bodies repeat it as `requestId`.\n- Errors use one shape, `{ \"error\": { code, message, requestId, docsUrl } }`, with a stable\n  `code` (see the `ErrorCode` schema).\n",
    "contact": {
      "name": "LayerHop",
      "url": "https://docs.layerhop.com"
    }
  },
  "servers": [
    {
      "url": "https://api.layerhop.com",
      "description": "Hosted API (production)"
    },
    {
      "url": "http://localhost:8787",
      "description": "Local API (`pnpm --filter @layerhop/api dev`)"
    }
  ],
  "tags": [
    {
      "name": "Meta",
      "description": "Liveness."
    },
    {
      "name": "Assets",
      "description": "Chains, tokens, USD prices and wallet balances: every chain and token LayerHop's providers can\nroute, for chain and token pickers and balance displays.\n"
    },
    {
      "name": "Quotes",
      "description": "Ask every provider for a price."
    },
    {
      "name": "Orders",
      "description": "Build, submit and track the transaction for a quote."
    },
    {
      "name": "Checkout",
      "description": "Pay with any token: a merchant creates a checkout session (an amount in USDC or USDT on one\nchain, paid to their address) and shares its hosted link. The payer pays with any token on any\nchain; LayerHop routes it so the merchant receives at least the amount due, verifies the\ndelivery on the settlement chain, then marks the session `paid` and sends\n`checkout.session.completed`. Creating and managing sessions needs an API key; the payer-facing\nroutes (`GET` a session, `POST …/quote`) do not. Paid sessions can be refunded (in full or in\npart) from the merchant's own wallet with `POST /v1/checkout/sessions/{id}/refunds`.\n"
    },
    {
      "name": "Invoices",
      "description": "Bill a customer by email: line items in a settlement stablecoin, a hosted invoice page\n(`https://layerhop.com/invoice/{id}`) where they pay with any token on any chain, an emailed\nreceipt and a PDF. Managing invoices needs an API key; the customer-facing routes (`…/public`,\n`…/pay`, `…/receipt.pdf`) do not.\n"
    },
    {
      "name": "Limit orders",
      "description": "Solana limit orders through Jupiter Trigger (beta): sell a token once it reaches your price, with\npartial fills and an optional expiry. The order lives on chain and the wallet signs every step;\nLayerHop never holds funds. Each fill becomes an order (`quoteId` starting with `lof_`,\n`limitOrderId` set) and sends `limit_order.filled`. Recurring (DCA) orders are not offered: no\nDCA API lets integrators charge a fee yet.\n"
    },
    {
      "name": "Subscriptions",
      "description": "Recurring billing in crypto. A wallet can't be charged automatically, so each period LayerHop\nissues an invoice for the subscription and emails its pay link; the customer pays it with any\ntoken on any chain. Unpaid past its due date the subscription becomes `past_due`, the customer\ngets reminders 1 and 3 days after the due date, and after 7 days it is canceled. Managing\nsubscriptions needs an API key; an `lh_test_` key creates test-mode subscriptions whose invoices\nare paid in the sandbox.\n"
    },
    {
      "name": "Deposit addresses",
      "description": "Swap or bridge by sending tokens to an address, without connecting a wallet (beta). Each deposit\nbecomes an order (`quoteId` starting with `dep_`, `depositAddressId` set) with the usual\n`order.*` webhooks. The address belongs to the liquidity provider (Relay); LayerHop never holds\nfunds. Needs an API key; live mode is rolling out (test keys always work).\n"
    },
    {
      "name": "Status",
      "description": "Public platform status, the data behind status.layerhop.com."
    },
    {
      "name": "Webhooks",
      "description": "Developer tools for webhooks with an API key: stream your account's events to your laptop\n(`layerhop listen`) and trigger sample events in test mode (`layerhop trigger`).\n"
    },
    {
      "name": "Auth",
      "description": "Wallet sign-in (SIWE for EVM, the same message format for Solana) for the developer dashboard.\nSets an HttpOnly `lh_session` cookie. These routes exist only when the operator runs the API with\na database (`DATABASE_URL`); otherwise they return 404.\n"
    },
    {
      "name": "Dashboard",
      "description": "Developer dashboard: API keys, usage, request logs, orders, webhooks and the partner profile.\nEvery route needs the `lh_session` cookie (401 otherwise). Browser calls must come from the\ndashboard origin with `credentials: \"include\"`; writes from any other `Origin` get `FORBIDDEN`.\nResources of other accounts return `NOT_FOUND`.\n"
    },
    {
      "name": "Admin",
      "description": "Operator-only partner registry and fee ledger (D-020). Every admin route returns 404 unless\nthe operator sets `ADMIN_TOKEN`, and 401 without the matching `Authorization: Bearer` token.\n"
    }
  ],
  "security": [
    {},
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "tags": [
          "Meta"
        ],
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Liveness probe. Lists the providers loaded in this API instance.",
        "responses": {
          "200": {
            "description": "The API is up.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "ok": true,
                  "providers": [
                    "jupiter",
                    "relay",
                    "debridge",
                    "zerox",
                    "kyberswap",
                    "lifi"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/chains": {
      "get": {
        "tags": [
          "Assets"
        ],
        "operationId": "listChains",
        "summary": "List chains",
        "description": "Every chain at least one loaded provider can quote from or to. The registry merges the chain\nlists of Relay, LI.FI, deBridge, KyberSwap, Mayan, 0x and Jupiter, is refreshed every 6 hours\nand falls back to the static list in `@layerhop/shared` when a provider list is unavailable.\nPopular chains come first, then the rest alphabetically. `providers` lists the providers that\nsupport the chain in either direction.\n",
        "responses": {
          "200": {
            "description": "The chain registry.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChainsResponse"
                },
                "example": {
                  "chains": [
                    {
                      "id": 8453,
                      "slug": "base",
                      "name": "Base",
                      "vm": "evm",
                      "nativeSymbol": "ETH",
                      "nativeDecimals": 18,
                      "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/chains/base.svg",
                      "explorerTx": "https://basescan.org/tx/",
                      "explorerAddress": "https://basescan.org/address/",
                      "providers": [
                        "debridge",
                        "kyberswap",
                        "lifi",
                        "mayan",
                        "relay",
                        "zerox"
                      ],
                      "popular": true
                    },
                    {
                      "id": 80094,
                      "slug": "berachain",
                      "name": "Berachain",
                      "vm": "evm",
                      "nativeSymbol": "BERA",
                      "nativeDecimals": 18,
                      "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/chains/bera.svg",
                      "explorerTx": "https://berascan.com/tx/",
                      "explorerAddress": "https://berascan.com/address/",
                      "providers": [
                        "kyberswap",
                        "lifi",
                        "relay",
                        "zerox"
                      ],
                      "popular": true
                    },
                    {
                      "id": 7565164,
                      "slug": "solana",
                      "name": "Solana",
                      "vm": "svm",
                      "nativeSymbol": "SOL",
                      "nativeDecimals": 9,
                      "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/chains/solana.svg",
                      "explorerTx": "https://solscan.io/tx/",
                      "explorerAddress": "https://solscan.io/account/",
                      "providers": [
                        "debridge",
                        "jupiter",
                        "lifi",
                        "mayan",
                        "relay"
                      ],
                      "popular": true
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      }
    },
    "/v1/tokens": {
      "get": {
        "tags": [
          "Assets"
        ],
        "operationId": "listTokens",
        "summary": "List tokens",
        "description": "Tokens on one chain, from LI.FI's token list (all chains, with prices), Jupiter's verified\nlist (Solana) and LayerHop's curated list, de-duplicated by `chainId:address` and cached for\n1 hour. Without `q`, tokens are ordered popular first (native coin, curated, stables and\nmajors), then verified, then by liquidity or price presence.\n\n`q` matches the symbol or name (case-insensitive substring) or an exact address / mint.\nRanking: exact symbol, then popular, then verified, then liquidity / price presence.\nTokens not on any list can still be used: read them with\n[`GET /v1/tokens/lookup`](#look-up-a-token) and quote them by address.\n",
        "parameters": [
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "description": "Chain id or slug.",
            "schema": {
              "type": "string"
            },
            "example": "berachain"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Symbol, name or address to search for.",
            "schema": {
              "type": "string"
            },
            "example": "HONEY"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of tokens.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokensResponse"
                },
                "example": {
                  "tokens": [
                    {
                      "chainId": 80094,
                      "address": "0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce",
                      "symbol": "HONEY",
                      "name": "HONEY",
                      "decimals": 18,
                      "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/tokens/honey.svg",
                      "priceUsd": 0.9979,
                      "verified": true
                    }
                  ],
                  "nextCursor": "1"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      }
    },
    "/v1/tokens/lookup": {
      "get": {
        "tags": [
          "Assets"
        ],
        "operationId": "lookupToken",
        "summary": "Look up a token",
        "description": "One token by address / mint. Listed tokens come from the token list. Anything else is read\non-chain: ERC-20 `symbol`, `name` and `decimals` through Multicall3 on EVM chains; on Solana,\nthe mint account's decimals plus name and symbol from Jupiter's token search (or the\nToken-2022 metadata extension). Tokens read on-chain have `verified: false`; show a warning\nbefore a user trades them.\n",
        "parameters": [
          {
            "name": "chain",
            "in": "query",
            "required": true,
            "description": "Chain id or slug.",
            "schema": {
              "type": "string"
            },
            "example": "base"
          },
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Token address (EVM) or mint (Solana).",
            "schema": {
              "type": "string"
            },
            "example": "0x4200000000000000000000000000000000000006"
          }
        ],
        "responses": {
          "200": {
            "description": "The token.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenLookupResponse"
                },
                "example": {
                  "token": {
                    "chainId": 8453,
                    "address": "0x4200000000000000000000000000000000000006",
                    "symbol": "WETH",
                    "name": "Wrapped Ether",
                    "decimals": 18,
                    "priceUsd": 2423.34,
                    "verified": true,
                    "popular": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "`INVALID_PARAMS` (malformed address), `UNSUPPORTED_CHAIN`, or `UNSUPPORTED_TOKEN` (the\naddress is not an ERC-20 contract / SPL mint).\n",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      }
    },
    "/v1/prices": {
      "get": {
        "tags": [
          "Assets"
        ],
        "operationId": "getPrices",
        "summary": "Get USD prices",
        "description": "USD prices for up to 100 tokens: LI.FI prices for EVM chains, Jupiter Price API v3 for\nSolana, with the hourly token-list price as a fallback. Cached for 60 seconds. Ids without a\nknown price are left out of the response.\n",
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated `chainId:address` (the chain may also be a slug). At most 100.",
            "schema": {
              "type": "string"
            },
            "example": "8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913,7565164:So11111111111111111111111111111111111111112"
          }
        ],
        "responses": {
          "200": {
            "description": "Prices keyed by the ids exactly as requested.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricesResponse"
                },
                "example": {
                  "prices": {
                    "8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": 0.9998,
                    "7565164:So11111111111111111111111111111111111111112": 103.88
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      }
    },
    "/v1/balances": {
      "get": {
        "tags": [
          "Assets"
        ],
        "operationId": "getBalances",
        "summary": "Get wallet balances",
        "description": "Non-zero balances of a wallet with token metadata, USD price and value, sorted by value.\n\n- EVM address: the native coin plus a Multicall3 `balanceOf` over each chain's top ~200\n  popular and verified tokens, on every requested chain in parallel. Default chains: the\n  popular EVM chains.\n- Solana address: SOL plus every Token and Token-2022 account (summed per mint). Default\n  chain: Solana. Unlisted mints get metadata from Jupiter and `verified: false`; NFTs are skipped.\n\nA chain that fails or times out is reported in `errors` and never fails the request.\nResults are cached per address and chain for 20 seconds.\n",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "EVM address or Solana wallet address.",
            "schema": {
              "type": "string"
            },
            "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
          },
          {
            "name": "chains",
            "in": "query",
            "description": "Comma-separated chain ids or slugs (at most 25), all of the address's VM.",
            "schema": {
              "type": "string"
            },
            "example": "base,arbitrum,berachain"
          }
        ],
        "responses": {
          "200": {
            "description": "The wallet's balances.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalancesResponse"
                },
                "example": {
                  "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
                  "vm": "evm",
                  "balances": [
                    {
                      "chainId": 8453,
                      "address": "0x0000000000000000000000000000000000000000",
                      "symbol": "ETH",
                      "name": "ETH",
                      "decimals": 18,
                      "priceUsd": 2423.34,
                      "verified": true,
                      "popular": true,
                      "amount": "3128821803472737280",
                      "valueUsd": 7582.2
                    },
                    {
                      "chainId": 8453,
                      "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "symbol": "USDC",
                      "name": "USD Coin",
                      "decimals": 6,
                      "priceUsd": 0.9998,
                      "verified": true,
                      "popular": true,
                      "amount": "2500000",
                      "valueUsd": 2.4995
                    }
                  ],
                  "totalUsd": 7584.7,
                  "errors": [
                    {
                      "chainId": 80094,
                      "message": "Berachain: timed out after 8000 ms"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      }
    },
    "/v1/quote": {
      "get": {
        "tags": [
          "Quotes"
        ],
        "operationId": "getQuote",
        "summary": "Get quotes",
        "description": "Fans the request out to every provider that supports the route, in parallel, with a\nper-provider timeout (8 s by default). Successful quotes are ranked best-for-the-user\nfirst by time-adjusted output (1 bp penalty per minute of ETA beyond the first minute,\ncapped at 50 bps), then by speed. Providers that failed are listed in `errors` and do not\nfail the request, unless every provider failed (`NO_ROUTE`). With gas on arrival requested,\nquotes that deliver it (`gasOnArrival` set) rank before those that don't.\n\nEach quote has its own `quoteId`; pass it to `POST /v1/orders` before `expiresAt`.\n",
        "parameters": [
          {
            "name": "srcChain",
            "in": "query",
            "required": true,
            "description": "Source chain id or slug (any chain from `GET /v1/chains`).",
            "schema": {
              "type": "string"
            },
            "example": "base"
          },
          {
            "name": "srcToken",
            "in": "query",
            "required": true,
            "description": "Source token address / mint (any token, see `GET /v1/tokens`), a curated symbol (`USDC`) or the native symbol (`ETH`). Unknown symbols return `UNSUPPORTED_TOKEN`.",
            "schema": {
              "type": "string"
            },
            "example": "USDC"
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "description": "Input amount, integer string in base units of `srcToken`. Must be greater than 0.",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            },
            "example": "100000000"
          },
          {
            "name": "dstChain",
            "in": "query",
            "required": true,
            "description": "Destination chain id or slug.",
            "schema": {
              "type": "string"
            },
            "example": "solana"
          },
          {
            "name": "dstToken",
            "in": "query",
            "required": true,
            "description": "Destination token address / mint, curated symbol or native symbol.",
            "schema": {
              "type": "string"
            },
            "example": "SOL"
          },
          {
            "name": "sender",
            "in": "query",
            "required": true,
            "description": "Address that signs and pays on the source chain.",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "0x1111111111111111111111111111111111111111"
          },
          {
            "name": "recipient",
            "in": "query",
            "required": true,
            "description": "Address that receives the output on the destination chain.",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
          },
          {
            "name": "slippageBps",
            "in": "query",
            "required": false,
            "description": "Maximum slippage in basis points.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000,
              "default": 50
            },
            "example": 50
          },
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Where the trade comes from. Decides the LayerHop fee (see `FeeChannel`).",
            "schema": {
              "$ref": "#/components/schemas/FeeChannel"
            },
            "example": "api"
          },
          {
            "name": "integrator",
            "in": "query",
            "required": false,
            "description": "Partner id (`[a-z0-9-]{1,32}`). When it is a registered partner, that partner's fee is added\non top of LayerHop's and reported as `fees.integratorFeeBps`. Unknown or malformed ids are\nignored (never an error). An `x-api-key` that belongs to a partner takes precedence.\n",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,32}$"
            },
            "example": "myapp"
          },
          {
            "name": "integratorFeeBps",
            "in": "query",
            "required": false,
            "description": "Partner fee override in bps. Honored only when `x-api-key` belongs to a partner, and must be\nwithin that partner's `maxFeeBps` (otherwise `INVALID_PARAMS`). Ignored for label-only\npartners. LayerHop fee + partner fee is capped at 150 bps by default; the partner part is\ntrimmed to fit.\n",
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "example": 50
          },
          {
            "name": "gasOnArrival",
            "in": "query",
            "required": false,
            "description": "Gas on arrival: `true` also delivers $2 of the destination chain's native gas token (ETH on\nArbitrum, POL on Polygon…) to `recipient`, paid out of the swap, so the recipient can\ntransact right away. Applies only to cross-chain routes to an EVM chain whose output token is\nnot already native; otherwise it is ignored. Providers that can't deliver gas ignore it;\nquotes that include it carry `gasOnArrival`. Today: Relay. See the gas-on-arrival guide.\n",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "gasOnArrivalUsd",
            "in": "query",
            "required": false,
            "description": "USD value of native gas to deliver (implies `gasOnArrival=true`). Default 2.",
            "schema": {
              "type": "number",
              "minimum": 0.5,
              "maximum": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked quotes.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponse"
                },
                "example": {
                  "best": {
                    "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                    "provider": "relay",
                    "dstAmount": "612345678",
                    "dstAmountMin": "609283949",
                    "estimatedSeconds": 8,
                    "fees": {
                      "ourFeeBps": 20,
                      "providerFeeUsd": 0.12,
                      "gasUsd": 0.03
                    },
                    "expiresAt": 1760000030
                  },
                  "quotes": [
                    {
                      "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                      "provider": "relay",
                      "dstAmount": "612345678",
                      "dstAmountMin": "609283949",
                      "estimatedSeconds": 8,
                      "fees": {
                        "ourFeeBps": 20,
                        "providerFeeUsd": 0.12,
                        "gasUsd": 0.03
                      },
                      "expiresAt": 1760000030
                    },
                    {
                      "quoteId": "q_0b9a4f7e-1d2c-4e3b-8a6f-5c4d3e2b1a09",
                      "provider": "debridge",
                      "dstAmount": "611900000",
                      "dstAmountMin": "611900000",
                      "estimatedSeconds": 6,
                      "fees": {
                        "ourFeeBps": 20
                      },
                      "expiresAt": 1760000030
                    }
                  ],
                  "errors": [
                    {
                      "provider": "lifi",
                      "code": "PROVIDER_TIMEOUT",
                      "message": "Timed out: li.quest"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NoRoute"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      },
      "post": {
        "tags": [
          "Quotes"
        ],
        "operationId": "postQuote",
        "summary": "Get quotes (JSON body, destination calls)",
        "description": "The same as `GET /v1/quote` with the parameters as a JSON body, plus **destination calls**:\ncontract calls run on the destination chain with the output, in the same user action (for\nexample bridge USDC and supply it to Aave for `recipient`). See the destination-calls guide.\n\nWith `calls` or `action`, send `dstAmount` (the exact amount of `dstToken` the calls receive)\ninstead of `amount`; each quote then reports `srcAmount` (what `sender` pays, fees included).\nOnly providers that run destination calls are asked (today: Relay); the others are skipped.\nDestination calls are cross-chain only, to EVM chains (not Solana or Hyperliquid), and\ncan't be combined with gas on arrival.\n\n**Trust model.** The calls are made by the provider's executor contract (`calls.executor`),\nnot by the user: `msg.sender` is the executor. Targets must credit `recipient` from a\nparameter (e.g. Aave `supply(..., onBehalfOf)`), never `msg.sender`. For an ERC-20 output,\napprove the target first (`approve(target, dstAmount)` on `dstToken`). Calls that move or\nauthorize third-party assets (`transferFrom`, `safeTransferFrom`, `permit`, Permit2) are\nrejected.\n\n**Mandatory simulation.** Before a quote is returned, its calls run in a read-only\n`eth_simulateV1` on the destination chain, from the executor, after giving it exactly\n`dstAmount` of the output. A call that would revert fails the request with `CALLS_REVERTED`\n(naming the call and the revert reason); if the simulation can't run, `PROVIDER_ERROR`.\nIf a call still reverts at fill time (state changed), the provider refunds `sender`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequestBody"
              },
              "example": {
                "srcChain": "base",
                "srcToken": "USDC",
                "dstChain": "arbitrum",
                "dstToken": "USDC",
                "dstAmount": "10000000",
                "sender": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
                "recipient": "0x1111111111111111111111111111111111111111",
                "action": {
                  "type": "aave-v3-supply"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked quotes. With destination calls every quote carries `srcAmount` and `calls`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponse"
                },
                "example": {
                  "best": {
                    "quoteId": "q_713598a2-7493-4cf5-8412-7e44015c9c88",
                    "provider": "relay",
                    "dstAmount": "10000000",
                    "dstAmountMin": "10000000",
                    "srcAmount": "10083608",
                    "estimatedSeconds": 1,
                    "fees": {
                      "ourFeeBps": 25,
                      "providerFeeUsd": 0.0586,
                      "gasUsd": 0.001194
                    },
                    "expiresAt": 1792430763,
                    "calls": {
                      "items": [
                        {
                          "to": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
                          "data": "0x095ea7b3000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad0000000000000000000000000000000000000000000000000000000000989680",
                          "value": "0"
                        },
                        {
                          "to": "0x794a61358d6845594f94dc1db02a252b5b4814ad",
                          "data": "0x617ba037000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000098968000000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000",
                          "value": "0"
                        }
                      ],
                      "executor": "0xb92fe925dc43a0ecde6c8b1a2709c170ec4fff4f",
                      "executed": true,
                      "simulation": {
                        "ok": true,
                        "gasUsed": "288491",
                        "leftover": "0"
                      }
                    }
                  },
                  "quotes": [
                    {
                      "quoteId": "q_713598a2-7493-4cf5-8412-7e44015c9c88",
                      "provider": "relay",
                      "dstAmount": "10000000",
                      "dstAmountMin": "10000000",
                      "srcAmount": "10083608",
                      "estimatedSeconds": 1,
                      "fees": {
                        "ourFeeBps": 25,
                        "providerFeeUsd": 0.0586,
                        "gasUsd": 0.001194
                      },
                      "expiresAt": 1792430763
                    }
                  ],
                  "errors": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "`FORBIDDEN`: destination calls are not enabled in live mode on this deployment yet (test keys always work).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NoRoute"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "502": {
            "description": "`PROVIDER_ERROR`: a provider failed, or the destination calls could not be simulated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "listOrders",
        "summary": "List orders by address",
        "description": "Orders built through LayerHop that were sent from or to `address`, newest first. EVM addresses\nmatch case-insensitively. Only public fields are returned. Requires the operator to run the API\nwith a database; otherwise this route returns 404.\n",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "description": "Sender or recipient address.",
            "schema": {
              "type": "string"
            },
            "example": "0x1111111111111111111111111111111111111111"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only orders with this status.",
            "schema": {
              "$ref": "#/components/schemas/OrderLifecycleStatus"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of orders.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderList"
                },
                "example": {
                  "orders": [
                    {
                      "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                      "status": "filled",
                      "provider": "relay",
                      "channel": "api",
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "dstChainId": 7565164,
                      "dstToken": "So11111111111111111111111111111111111111112",
                      "sender": "0x1111111111111111111111111111111111111111",
                      "recipient": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
                      "amount": "100000000",
                      "dstAmount": "612345678",
                      "ourFeeBps": 20,
                      "partnerFeeBps": 0,
                      "srcTxHash": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f",
                      "dstTxHash": "3nKqYdW1hS8vZ4cT2pXeR7mB9uJfL6aG5oN1wQ8kE3sD7yH2xV4tC6bM9rP1zA5uF8jL2gK7eW3qS6dN4hT9vB1",
                      "createdAt": "2026-10-17T10:00:00.000Z",
                      "updatedAt": "2026-10-17T10:00:42.000Z"
                    }
                  ],
                  "nextCursor": "MjAyNi0xMC0xN1QxMDowMDowMC4wMDBafHFfNmYxYzJkMGU"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "buildOrder",
        "summary": "Build the transaction",
        "description": "Returns the transaction for a quote, for the user's wallet to sign. EVM transactions may\ncarry an `approval` (an ERC-20 `approve` to send first). Solana transactions are a base64\nserialized `VersionedTransaction`; when `submitViaApi` is true, sign it and send it to\n`POST /v1/orders/submit` instead of an RPC node.\n\nThe quote must not be expired. Some providers ask you to submit within ~30 s of building.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuildOrderRequest"
              },
              "example": {
                "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The transaction to sign.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BuildOrderResponse"
                },
                "example": {
                  "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                  "provider": "relay",
                  "tx": {
                    "vm": "evm",
                    "chainId": 8453,
                    "to": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
                    "data": "0x58109c...",
                    "value": "0",
                    "approval": {
                      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "spender": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
                      "amount": "100000000"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/QuoteNotFound"
          },
          "410": {
            "$ref": "#/components/responses/QuoteExpired"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          },
          "504": {
            "$ref": "#/components/responses/ProviderTimeout"
          }
        }
      }
    },
    "/v1/orders/submit": {
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "submitOrder",
        "summary": "Submit a signed transaction",
        "description": "Only for Solana transactions built with `submitViaApi: true` (today: Jupiter, whose RFQ and\ngasless transactions are co-signed and never land through a plain RPC node). Send the\nwallet-signed transaction as base64; LayerHop forwards it to the provider and returns the\ntransaction signature. For every other provider this returns `INVALID_PARAMS` — broadcast\nfrom the wallet instead.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitOrderRequest"
              },
              "example": {
                "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                "signedTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The provider accepted and executed the transaction.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitOrderResponse"
                },
                "example": {
                  "provider": "jupiter",
                  "txHash": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/QuoteNotFound"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          },
          "504": {
            "$ref": "#/components/responses/ProviderTimeout"
          }
        }
      }
    },
    "/v1/orders/{provider}/{id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "getOrderStatus",
        "summary": "Get order status",
        "description": "Asks the provider for the current state of an order. What `id` means depends on the\nprovider:\n\n- `relay`: Relay request id or the source deposit tx hash.\n- `debridge`: source tx hash (EVM hash or Solana signature) or a DLN order id.\n- `lifi`: source tx hash.\n- `jupiter`, `zerox`, `kyberswap`: same-chain swaps have nothing to track off-chain; the state is always\n  `unknown`. Confirm the transaction on chain instead.\n\nPoll until `state` is `filled`, `refunded` or `failed`.\n",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "description": "The `provider` from the quote. Must be a provider loaded in this API instance.",
            "schema": {
              "$ref": "#/components/schemas/ProviderId"
            },
            "example": "relay"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Provider order id or source tx hash (see above). URL-encode it.",
            "schema": {
              "type": "string"
            },
            "example": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f"
          }
        ],
        "responses": {
          "200": {
            "description": "Current order state.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderStatus"
                },
                "example": {
                  "provider": "relay",
                  "id": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f",
                  "state": "filled",
                  "srcTxHash": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f",
                  "dstTxHash": "3nKqYdW1hS8vZ4cT2pXeR7mB9uJfL6aG5oN1wQ8kE3sD7yH2xV4tC6bM9rP1zA5uF8jL2gK7eW3qS6dN4hT9vB1"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/OrderNotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          },
          "504": {
            "$ref": "#/components/responses/ProviderTimeout"
          }
        }
      }
    },
    "/v1/orders/{quoteId}/events": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "streamOrder",
        "summary": "Stream an order's status",
        "description": "Server-Sent Events: a `ready` event, then an `order` event (`OrderSummary`) with the current\nstate and one more on every change, until the order is final (`filled`, `refunded`, `failed`,\n`expired`), when the stream closes. Comment lines (`: ping`) keep the connection alive every\n15 s; streams last at most 30 minutes (reconnect to continue). Anyone with the `quoteId` can\nwatch; at most 20 open streams per API key or IP.\n",
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "The order's quote id.",
            "schema": {
              "type": "string"
            },
            "example": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"
          }
        ],
        "responses": {
          "200": {
            "description": "An event stream (`event: order`, `data: <OrderSummary JSON>`).",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/OrderNotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/orders/{quoteId}/submitted": {
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "reportSubmitted",
        "summary": "Report the broadcast transaction",
        "description": "Call this after the user's wallet broadcast the transaction from `POST /v1/orders`, so LayerHop\ncan track the order to completion (status, webhooks, partner earnings). The SDK's\n`reportSubmitted(quoteId, txHash)` does it for you; `POST /v1/orders/submit` does it automatically.\n\nSets the order's `status` to `submitted`. Idempotent for the same hash. A different hash for an\norder that already has one returns `CONFLICT`. Orders already past `submitted` keep their status.\n",
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "The quote the transaction was built from.",
            "schema": {
              "type": "string"
            },
            "example": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportSubmittedRequest"
              },
              "example": {
                "txHash": "0x3f1e6a2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded (or already recorded).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportSubmittedResponse"
                },
                "example": {
                  "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                  "status": "submitted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/OrderNotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          }
        }
      }
    },
    "/v1/simulate": {
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "simulateOrder",
        "summary": "Simulate the transaction",
        "description": "Builds the transaction for a quote (like `POST /v1/orders`, but without recording an order) and\ndry-runs it from the sender on a public RPC. Nothing is signed or sent.\n\n- **EVM:** `eth_call` + `eth_estimateGas`. When the transaction needs an ERC-20 `approval` and the\n  sender's allowance is too low, the swap is simulated with an allowance state override and\n  `needsApproval` is true. If the RPC cannot override state, only the approval is simulated\n  (`simulated: \"approval\"`).\n- **Solana:** `simulateTransaction` with `sigVerify: false` and `replaceRecentBlockhash: true`;\n  `computeUnits` is reported, and failure logs are returned in `error.logs`.\n\nA failing simulation is still a `200` with `ok: false`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuildOrderRequest"
              },
              "example": {
                "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Simulation result and the transaction that was simulated.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimulationResponse"
                },
                "example": {
                  "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                  "provider": "relay",
                  "ok": true,
                  "vm": "evm",
                  "gasEstimate": "184233",
                  "needsApproval": true,
                  "simulated": "tx",
                  "tx": {
                    "vm": "evm",
                    "chainId": 8453,
                    "to": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
                    "data": "0x58109c...",
                    "value": "0",
                    "approval": {
                      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "spender": "0xa5F565650890fBA1824Ee0F21EbBbF660a179934",
                      "amount": "100000000"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/QuoteNotFound"
          },
          "410": {
            "$ref": "#/components/responses/QuoteExpired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      }
    },
    "/v1/checkout/sessions": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "createCheckoutSession",
        "summary": "Create a checkout session",
        "description": "Creates a payment request for `amount` (base units) of a settlement stablecoin (USDC or USDT on\na supported chain), paid to `recipient`. Returns the session with its hosted `url`; send your\ncustomer there. Needs an API key: an `lh_test_` key creates a test-mode session (`cs_test_…`)\nthat is paid through the sandbox.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionCreateRequest"
              },
              "example": {
                "amount": "49000000",
                "settleChain": "base",
                "settleToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "description": "Pro plan, 1 month",
                "reference": "order_1042",
                "successUrl": "https://shop.example.com/thanks"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                },
                "example": {
                  "id": "cs_01k7t9m2c4x8q6r0v3b5n7p9d",
                  "object": "checkout.session",
                  "livemode": true,
                  "status": "open",
                  "amount": "49000000",
                  "settlement": {
                    "chainId": 8453,
                    "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                    "symbol": "USDC",
                    "decimals": 6
                  },
                  "recipient": "0x2222222222222222222222222222222222222222",
                  "description": "Pro plan, 1 month",
                  "url": "https://layerhop.com/pay/cs_01k7t9m2c4x8q6r0v3b5n7p9d",
                  "successUrl": "https://shop.example.com/thanks",
                  "expiresAt": "2026-10-18T11:00:00.000Z",
                  "reference": "order_1042",
                  "refundedAmount": "0",
                  "createdAt": "2026-10-18T10:00:00.000Z",
                  "updatedAt": "2026-10-18T10:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "listCheckoutSessions",
        "summary": "List checkout sessions",
        "description": "Your account's sessions of the key's mode (live or test), newest first.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only sessions with this status.",
            "schema": {
              "$ref": "#/components/schemas/CheckoutStatus"
            }
          },
          {
            "name": "productId",
            "in": "query",
            "required": false,
            "description": "Only sessions started from this product.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}": {
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutSession",
        "summary": "Get a checkout session",
        "description": "Public: the hosted page and your own code can poll it. Without your API key the response omits\n`reference` and `metadata`. An `open` session past `expiresAt` reads as `expired`.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/checkout/products": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "createCheckoutProduct",
        "summary": "Create a product",
        "description": "A fixed price for payment buttons, `layerhop.com/buy/{id}` links and store plugins. The amount,\nsettlement token, payout address and redirect URLs live on the product, so anyone may start a\nsession from it (see `POST /v1/checkout/products/{id}/sessions`) without being able to change\nthe price. `allowedOrigins` (https origins, empty = any) limits which websites may start sessions\nfrom a browser. The key's mode decides the product's mode.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutProductCreateRequest"
              },
              "example": {
                "name": "Pro plan",
                "description": "1 month",
                "amount": "49000000",
                "settleChain": "base",
                "settleToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "successUrl": "https://shop.example.com/thanks",
                "allowedOrigins": [
                  "https://shop.example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Product created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutProduct"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "listCheckoutProducts",
        "summary": "List products",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "required": false,
            "description": "`true` or `false` to filter.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CheckoutProduct"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/checkout/products/{id}": {
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutProduct",
        "summary": "Get a product",
        "description": "Public (CORS open to any origin): name, price and settlement for a payment button. With the owner's key: every field.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Product id.",
            "schema": {
              "type": "string"
            },
            "example": "prod_01m57hq2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutProduct"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Checkout"
        ],
        "operationId": "updateCheckoutProduct",
        "summary": "Update a product",
        "description": "Change any field (the payout is re-validated). `active: false` stops new sessions. Existing sessions keep their terms.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Product id.",
            "schema": {
              "type": "string"
            },
            "example": "prod_01m57hq2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutProductCreateRequest"
              },
              "example": {
                "active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutProduct"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/checkout/products/{id}/sessions": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "startProductCheckout",
        "summary": "Start a checkout for a product",
        "description": "Public, no key, CORS open to any origin (unless the product sets `allowedOrigins`; then other\nbrowser origins get `FORBIDDEN`). Creates a checkout session with the product's amount, token,\npayout address and URLs; the caller may only add `reference` and `metadata`. Inactive products\nreturn `CONFLICT`. Send the payer to the returned `url`, or open it with the embedded checkout.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Product id.",
            "schema": {
              "type": "string"
            },
            "example": "prod_01m57hq2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reference": {
                    "type": "string",
                    "maxLength": 128,
                    "description": "Your order id, returned in the session and its webhooks."
                  },
                  "metadata": {
                    "type": "object",
                    "description": "Up to 10 string values."
                  }
                }
              },
              "example": {
                "reference": "order_1042"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/checkout/products": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCheckoutProducts",
        "summary": "List products",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateCheckoutProduct",
        "summary": "Create a product",
        "description": "`CheckoutProductCreateRequest` plus `mode` (`live` or `test`).",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutProductCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Product created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutProduct"
                }
              }
            }
          }
        }
      }
    },
    "/v1/dashboard/checkout/products/{id}": {
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardUpdateCheckoutProduct",
        "summary": "Update a product",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Product id.",
            "schema": {
              "type": "string"
            },
            "example": "prod_01m57hq2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutProductCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutProduct"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}/events": {
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "streamCheckoutSession",
        "summary": "Stream a checkout session",
        "description": "Server-Sent Events: `ready`, then a `session` event (`CheckoutSession`, payer view) now and on\nevery change until the session is `paid`, `expired` or `needs_review`. Same limits as the order\nstream.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "An event stream (`event: session`).",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/webhooks/stream": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "streamWebhookEvents",
        "summary": "Stream your webhook events",
        "description": "Server-Sent Events: every webhook event of the API key's account and mode (live or test),\nas it is created, as `event: event` with the exact payload your endpoints receive. This is what\n`layerhop listen --forward-to <url>` uses to deliver events to your laptop without a public URL.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "An event stream (`event: event`).",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/webhooks/trigger": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "triggerWebhookEvent",
        "summary": "Trigger a sample event",
        "description": "Creates a realistic sample event of `type` in test mode (`livemode: false`, `sample: true`),\ndelivered to your test endpoints that subscribe to it and to open `listen` streams. Test keys\nonly, so a sample can never reach a live endpoint.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "$ref": "#/components/schemas/WebhookEventType"
                  }
                }
              },
              "example": {
                "type": "order.filled"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Event created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string"
                    },
                    "deliveries": {
                      "type": "integer",
                      "description": "Test endpoints the event was queued for."
                    },
                    "payload": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: a live key; use a test key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}/expire": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "expireCheckoutSession",
        "summary": "Expire a checkout session",
        "description": "Cancels an `open` session so it can no longer be paid (`CONFLICT` for any other status).",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The expired session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}/quote": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "quoteCheckoutSession",
        "summary": "Quote a payment for a session",
        "description": "Public (the payer's side). Prices paying the session with `srcToken` on `srcChain` from\n`sender`. Every quote delivers at least the amount due to the session's recipient (set by the\nsession, never by the payer) and overpays by at most about 3%. Paying in the settlement token\non the settlement chain is a direct transfer (`provider: direct`): the recipient gets exactly\nthe amount due, and LayerHop's same-token fee (0.5% of the amount due, `fees.ourFeeBps: 50`) is\na second transfer on top, so `srcAmount` is the amount due plus the fee. On Solana both\ntransfers are in one transaction; on EVM chains the fee transfer is in the built transaction's\n`extraTxs`. Then build\nthe transaction with `POST /v1/orders` and report it with `POST /v1/orders/{quoteId}/submitted`;\nthe session moves to `processing`.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutQuoteRequest"
              },
              "example": {
                "srcChain": "arbitrum",
                "srcToken": "ETH",
                "sender": "0x1111111111111111111111111111111111111111"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quotes, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutQuoteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/NoRoute"
          }
        }
      }
    },
    "/v1/auth/nonce": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "authNonce",
        "summary": "Get a sign-in message",
        "description": "Step 1 of wallet sign-in for the developer dashboard. Returns a single-use nonce and the exact\nmessage to sign: EIP-4361 (Sign-In with Ethereum) text for EVM wallets, the same layout for\nSolana. The message expires after 10 minutes.\n",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NonceRequest"
              },
              "example": {
                "vm": "evm",
                "address": "0x1111111111111111111111111111111111111111"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The message to sign.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NonceResponse"
                },
                "example": {
                  "nonce": "4fQx9LmZ2pT7cV1aB",
                  "message": "dashboard.layerhop.com wants you to sign in with your Ethereum account:\n0x1111111111111111111111111111111111111111\n\nSign in to the LayerHop developer dashboard.\n\nURI: https://dashboard.layerhop.com\nVersion: 1\nChain ID: 1\nNonce: 4fQx9LmZ2pT7cV1aB\nIssued At: 2026-10-17T10:00:00.000Z\nExpiration Time: 2026-10-17T10:10:00.000Z",
                  "expiresAt": "2026-10-17T10:10:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/PlatformDisabled"
          }
        }
      }
    },
    "/v1/auth/verify": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "authVerify",
        "summary": "Verify the signature and sign in",
        "description": "Step 2. Send back the message from `POST /v1/auth/nonce` unchanged with the wallet's signature\n(EVM: hex `personal_sign`; Solana: ed25519 `signMessage`, base58 or base64). On success the\naccount is found or created for this wallet and the `lh_session` cookie is set (HttpOnly,\nSecure, SameSite=Lax, 7 days). The nonce is consumed even when verification fails.\n",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              },
              "example": {
                "vm": "evm",
                "message": "dashboard.layerhop.com wants you to sign in with your Ethereum account:\n…",
                "signature": "0x5c1a…1b"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in. The response sets the `lh_session` cookie.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                },
                "example": {
                  "account": {
                    "id": "acc_01m54s12tq01zx09z5jr07jxg1",
                    "createdAt": "2026-10-17T10:00:05.000Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/PlatformDisabled"
          }
        }
      }
    },
    "/v1/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "operationId": "authMe",
        "summary": "Current account",
        "description": "The signed-in account, its wallets and its partner profile (or `null`).",
        "security": [
          {
            "Session": []
          }
        ],
        "responses": {
          "200": {
            "description": "The session's account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                },
                "example": {
                  "account": {
                    "id": "acc_01m54s12tq01zx09z5jr07jxg1",
                    "createdAt": "2026-10-17T10:00:05.000Z"
                  },
                  "wallets": [
                    {
                      "vm": "evm",
                      "address": "0x1111111111111111111111111111111111111111",
                      "createdAt": "2026-10-17T10:00:05.000Z"
                    }
                  ],
                  "partner": {
                    "id": "myapp",
                    "name": "My App",
                    "feeBps": 20,
                    "maxFeeBps": 50,
                    "payoutEvm": "0x1111111111111111111111111111111111111111",
                    "status": "active",
                    "createdAt": "2026-10-17T10:05:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "authLogout",
        "summary": "Sign out",
        "description": "Clears the `lh_session` cookie.",
        "security": [
          {
            "Session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Signed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                },
                "example": {
                  "ok": true
                }
              }
            }
          }
        }
      }
    },
    "/v1/dashboard/account": {
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "updateAccount",
        "summary": "Update the account",
        "description": "Optional display name and contact email (not used for sign-in). Send `null` to clear a field.",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountUpdateRequest"
              },
              "example": {
                "displayName": "Acme Wallet",
                "email": "dev@acme.example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/wallets": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "linkWallet",
        "summary": "Link another wallet",
        "description": "Links another wallet to the signed-in account. Get a message from `POST /v1/auth/nonce` for the\nnew wallet, sign it with that wallet, and send the same body as `POST /v1/auth/verify`.\n`CONFLICT` if the wallet already belongs to another account.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              },
              "example": {
                "vm": "svm",
                "message": "dashboard.layerhop.com wants you to sign in with your Solana account:\n…",
                "signature": "3Bv7…base58"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The account's wallets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletsResponse"
                },
                "example": {
                  "wallets": [
                    {
                      "vm": "evm",
                      "address": "0x1111111111111111111111111111111111111111",
                      "createdAt": "2026-10-17T10:00:05.000Z"
                    },
                    {
                      "vm": "svm",
                      "address": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
                      "createdAt": "2026-10-17T10:02:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/overview": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardOverview",
        "summary": "30-day overview",
        "description": "Totals for the last 30 days: API requests and errors made with this account's keys, quotes,\norders built and filled, filled volume per source token, and (for partners) fee earnings.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          }
        ],
        "responses": {
          "200": {
            "description": "Overview.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Overview"
                },
                "example": {
                  "from": "2026-09-17T10:00:00.000Z",
                  "to": "2026-10-17T10:00:00.000Z",
                  "requests": 1520,
                  "errors": 12,
                  "quotes": 1311,
                  "orders": {
                    "built": 42,
                    "filled": 39,
                    "byStatus": {
                      "filled": 39,
                      "submitted": 1,
                      "expired": 2
                    }
                  },
                  "volume": [
                    {
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "orders": 39,
                      "amount": "3900000000"
                    }
                  ],
                  "activeKeys": 2
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/keys": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "listApiKeys",
        "summary": "List API keys",
        "description": "Every key of the account, newest first, including revoked ones. Secrets are never returned.",
        "security": [
          {
            "Session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                },
                "example": {
                  "keys": [
                    {
                      "id": "key_01m54s12va302av4ay4epqndye",
                      "name": "production",
                      "prefix": "lh_live_7Hq2",
                      "rateLimitRpm": 120,
                      "createdAt": "2026-10-17T10:01:00.000Z",
                      "lastUsedAt": "2026-10-17T11:20:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "createApiKey",
        "summary": "Create an API key",
        "description": "Returns the key's plaintext `secret` (`lh_live_` or, with `mode: test`, `lh_test_` + 32\ncharacters) **once**. LayerHop stores only its SHA-256 hash. At most 20 active keys per account.\nNew keys get 120 requests/minute. Test keys never reach a real provider (see the `ApiKey`\nsecurity scheme).\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateRequest"
              },
              "example": {
                "name": "staging",
                "mode": "test"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. Store the secret now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                },
                "example": {
                  "key": {
                    "id": "key_01m54s12va302av4ay4epqndye",
                    "name": "production",
                    "prefix": "lh_live_7Hq2",
                    "rateLimitRpm": 120,
                    "createdAt": "2026-10-17T10:01:00.000Z"
                  },
                  "secret": "lh_live_7Hq2mX9pLr4TcV8bN1wQ6zKs3dF5gJ0a"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/keys/{id}": {
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "renameApiKey",
        "summary": "Rename an API key",
        "description": "Only the name can be changed here; rate limits are set by LayerHop.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Key id.",
            "schema": {
              "type": "string"
            },
            "example": "key_01m54s12va302av4ay4epqndye"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyNameRequest"
              },
              "example": {
                "name": "staging"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "revokeApiKey",
        "summary": "Revoke an API key",
        "description": "The key stops working immediately on this API instance (and within 60 s everywhere).",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Key id.",
            "schema": {
              "type": "string"
            },
            "example": "key_01m54s12va302av4ay4epqndye"
          }
        ],
        "responses": {
          "200": {
            "description": "The revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/usage": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardUsage",
        "summary": "Usage time series",
        "description": "Request counts per hour or day (UTC), gap-filled with zeros. Defaults: the last 24 hours for\n`bucket=hour`, the last 30 days for `bucket=day`. At most 800 buckets per call.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive start, ISO 8601 or unix seconds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Exclusive end, ISO 8601 or unix seconds. Default now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "keyId",
            "in": "query",
            "required": false,
            "description": "Only requests made with this key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bucket",
            "in": "query",
            "required": false,
            "description": "Bucket size.",
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "day"
              ],
              "default": "hour"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The series.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                },
                "example": {
                  "bucket": "hour",
                  "from": "2026-10-16T10:00:00.000Z",
                  "to": "2026-10-17T10:00:00.000Z",
                  "series": [
                    {
                      "ts": "2026-10-17T09:00:00.000Z",
                      "requests": 61,
                      "errors": 1,
                      "quotes": 55,
                      "orders": 3
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/logs": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardLogs",
        "summary": "Request logs",
        "description": "Requests made with this account's keys, newest first (kept 30 days).",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "keyId",
            "in": "query",
            "required": false,
            "description": "Only requests made with this key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "An exact code (`429`), a class (`4xx`), or `error` (any status >= 400).",
            "schema": {
              "type": "string"
            },
            "example": "error"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of log rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RequestLogList"
                },
                "example": {
                  "logs": [
                    {
                      "id": "1042",
                      "ts": "2026-10-17T09:59:58.120Z",
                      "keyId": "key_01m54s12va302av4ay4epqndye",
                      "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                      "method": "GET",
                      "path": "/v1/quote",
                      "query": {
                        "srcChain": "base",
                        "dstChain": "solana"
                      },
                      "status": 200,
                      "latencyMs": 412,
                      "provider": "relay"
                    }
                  ],
                  "nextCursor": "MjAyNi0xMC0xN1QwOTo1OTo1OC4xMjBafDEwNDI"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/orders": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardOrders",
        "summary": "Account orders",
        "description": "Orders built with this account's keys, newest first, with attribution fields.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only orders with this status.",
            "schema": {
              "$ref": "#/components/schemas/OrderLifecycleStatus"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of orders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountOrderList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/webhooks": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "listWebhooks",
        "summary": "List webhook endpoints",
        "description": "The account's endpoints. Signing secrets are only shown at creation.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoints.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "webhooks": [
                    {
                      "id": "whe_01m54s1a2b3c4d5e6f7g8h9j0k",
                      "url": "https://example.com/layerhop",
                      "events": [
                        "order.filled",
                        "order.failed"
                      ],
                      "active": true,
                      "createdAt": "2026-10-17T10:03:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "createWebhook",
        "summary": "Create a webhook endpoint",
        "description": "`url` must be public `https`. `events` empty or omitted = every order event. Returns the\nsigning `secret` (`whsec_…`) once. Deliveries carry\n`LayerHop-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>`. At most 10 endpoints.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreateRequest"
              },
              "example": {
                "url": "https://example.com/layerhop",
                "events": [
                  "order.filled",
                  "order.failed"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. Store the secret now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreated"
                },
                "example": {
                  "webhook": {
                    "id": "whe_01m54s1a2b3c4d5e6f7g8h9j0k",
                    "url": "https://example.com/layerhop",
                    "events": [
                      "order.filled",
                      "order.failed"
                    ],
                    "active": true,
                    "createdAt": "2026-10-17T10:03:00.000Z"
                  },
                  "secret": "whsec_Z8kQ1mN4pR7tV0xB3dF6hJ9lC2eG5iK8"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}": {
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "updateWebhook",
        "summary": "Update a webhook endpoint",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdateRequest"
              },
              "example": {
                "active": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook endpoint",
        "description": "Deletes the endpoint and its delivery history.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/test": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "testWebhook",
        "summary": "Send a test event",
        "description": "Queues an event for this endpoint only: `webhook.test` by default, or a realistic sample of any\nevent type (`sample: true` in the payload, `livemode` of the endpoint). Delivery is asynchronous\n(within seconds).\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "An event type (see `WebhookEventType`) or `webhook.test`.",
                    "default": "webhook.test"
                  }
                }
              },
              "example": {
                "type": "checkout.session.completed"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestResponse"
                },
                "example": {
                  "eventId": "evt_01m54s1b2c3d4e5f6g7h8j9k0m",
                  "deliveryId": "whd_01m54s1b2c3d4e5f6g7h8j9k0n"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/deliveries": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "listWebhookDeliveries",
        "summary": "List deliveries",
        "description": "Delivery attempts for this endpoint, newest first.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of deliveries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryList"
                },
                "example": {
                  "deliveries": [
                    {
                      "id": "whd_01m54s1b2c3d4e5f6g7h8j9k0n",
                      "endpointId": "whe_01m54s1a2b3c4d5e6f7g8h9j0k",
                      "eventId": "evt_01m54s1b2c3d4e5f6g7h8j9k0m",
                      "eventType": "webhook.test",
                      "attempt": 1,
                      "status": "success",
                      "responseCode": 200,
                      "responseSnippet": "ok",
                      "createdAt": "2026-10-17T10:04:00.000Z",
                      "deliveredAt": "2026-10-17T10:04:02.000Z"
                    }
                  ],
                  "nextCursor": "MjAyNi0xMC0xN1QxMDowNDowMC4wMDBafHdoZF8wMW01NHMxYjJj"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/rotate-secret": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "rotateWebhookSecret",
        "summary": "Rotate the signing secret",
        "description": "Issues a new `whsec_` secret (shown once). For `graceHours` (default 24, 0 = none, max 168) the\nold secret keeps signing too: the `LayerHop-Signature` header carries two `v1` values, so\nreceivers verify with either while you update yours.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "graceHours": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 168,
                    "default": 24
                  }
                }
              },
              "example": {
                "graceHours": 24
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new secret.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "type": "object"
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/deliveries/{deliveryId}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "getWebhookDelivery",
        "summary": "Get one delivery",
        "description": "The delivery with the request that was sent (URL, headers, exact body) and the event.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "description": "Delivery id.",
            "schema": {
              "type": "string"
            },
            "example": "whd_01m54s1b2c3d4e5f6g7h8j9k0n"
          }
        ],
        "responses": {
          "200": {
            "description": "The delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivery": {
                      "$ref": "#/components/schemas/WebhookDelivery"
                    },
                    "request": {
                      "type": "object",
                      "description": "`method`, `url`, `headers` and `body` as sent."
                    },
                    "event": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/stats": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "webhookStats",
        "summary": "Endpoint health",
        "description": "Deliveries in the last 24 hours and 7 days (success, failed, pending, success rate, average and p95 latency), last success and failure.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          }
        ],
        "responses": {
          "200": {
            "description": "Stats.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/events": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "listWebhookEvents",
        "summary": "List events",
        "description": "Every webhook event of your account (newest first) with a delivery summary.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Only events of this type.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/dashboard/events/{id}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "getWebhookEvent",
        "summary": "Get an event",
        "description": "The event payload and every delivery of it.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Event id.",
            "schema": {
              "type": "string"
            },
            "example": "evt_01m54s1b2c3d4e5f6g7h8j9k0m"
          }
        ],
        "responses": {
          "200": {
            "description": "The event.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/events/{id}/resend": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "resendWebhookEvent",
        "summary": "Resend an event",
        "description": "Queues the event again for one endpoint (`endpointId`, same mode) or for every active endpoint of its mode that subscribes to its type.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Event id.",
            "schema": {
              "type": "string"
            },
            "example": "evt_01m54s1b2c3d4e5f6g7h8j9k0m"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "endpointId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "replayWebhookDelivery",
        "summary": "Replay a delivery",
        "description": "Queues a new delivery of the same event to this endpoint (the original row is kept).",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Endpoint id.",
            "schema": {
              "type": "string"
            },
            "example": "whe_01m54s1a2b3c4d5e6f7g8h9j0k"
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "description": "Delivery id.",
            "schema": {
              "type": "string"
            },
            "example": "whd_01m54s1b2c3d4e5f6g7h8j9k0n"
          }
        ],
        "responses": {
          "202": {
            "description": "Queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/partner": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "getPartnerProfile",
        "summary": "Partner profile",
        "description": "The account's partner (integrator) profile, or `null`.",
        "security": [
          {
            "Session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Profile or null.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerProfileResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "applyPartner",
        "summary": "Apply as a partner",
        "description": "Creates the account's partner profile. `id` is the public label used as `integrator=<id>`.\nThe profile is `active` at once with a starter `maxFeeBps` (50 bps by default) and `feeBps` 0:\nset your fee with `PATCH` to start earning. LayerHop can raise the cap or suspend a profile.\nWhen the operator turns instant activation off, the profile starts `pending` instead.\nOne profile per account.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerApplyRequest"
              },
              "example": {
                "id": "myapp",
                "name": "My App",
                "payoutEvm": "0x1111111111111111111111111111111111111111"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created (`active`, or `pending` under manual review).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerProfileResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "updatePartnerProfile",
        "summary": "Update the partner profile",
        "description": "`feeBps` must be <= `maxFeeBps`. At least one payout address must remain.",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerUpdateRequest"
              },
              "example": {
                "feeBps": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerProfileResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/earnings": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "partnerEarnings",
        "summary": "Partner earnings",
        "description": "Partner fee estimates (input-token base units) per source token and per month (UTC), from orders\ncarrying this partner's fee. `filled` orders are confirmed; `unconfirmed` = built, submitted or\npending. Default range: the last 365 days. Payouts are reconciled by LayerHop.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive start, ISO 8601 or unix seconds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive end, ISO 8601 or unix seconds.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Earnings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EarningsResponse"
                },
                "example": {
                  "partner": "myapp",
                  "from": "2025-10-17T10:00:00.000Z",
                  "to": "2026-10-17T10:00:00.000Z",
                  "basis": "estimate",
                  "byToken": [
                    {
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "filled": {
                        "orders": 39,
                        "partnerFee": "7800000"
                      },
                      "unconfirmed": {
                        "orders": 3,
                        "partnerFee": "600000"
                      }
                    }
                  ],
                  "byMonth": [
                    {
                      "month": "2026-10",
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "filled": {
                        "orders": 39,
                        "partnerFee": "7800000"
                      },
                      "unconfirmed": {
                        "orders": 3,
                        "partnerFee": "600000"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/earnings/statement.csv": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "partnerStatement",
        "summary": "Partner statement (CSV)",
        "description": "A CSV download of filled live orders that carried this partner's fee (`type` = `earning`) and\nthe payouts LayerHop recorded (`type` = `payout`, negative `partner_fee`), oldest first.\nColumns: `type,date,reference,provider,chain_id,token,amount_in,fee_bps,partner_fee,tx_hash,status`.\nAmounts are base units of `token`. Default range: the last 365 days.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive start, ISO 8601 or unix seconds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive end, ISO 8601 or unix seconds.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The statement.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "type,date,reference,provider,chain_id,token,amount_in,fee_bps,partner_fee,tx_hash,status\nearning,2026-10-17T10:00:00.000Z,q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10,relay,8453,0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913,100000000,20,200000,0xabab…,filled\npayout,2026-10-31T12:00:00.000Z,po_01hx…,,8453,0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913,,,-200000,0xcdcd…,paid\n"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/payouts": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "partnerPayouts",
        "summary": "Partner balances and payouts",
        "description": "What LayerHop owes this partner per token, and the payouts recorded so far. `earned` sums partner\nfees of filled live orders, `paid` sums recorded payouts, `owed` = `earned` - `paid`. LayerHop\ncollects partner fees in its fee wallets and pays them out to the profile's payout addresses.\nTest mode always returns empty lists (test earnings are never paid out).\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          }
        ],
        "responses": {
          "200": {
            "description": "Balances and payout history.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutsResponse"
                },
                "example": {
                  "partner": "myapp",
                  "balances": [
                    {
                      "chainId": 8453,
                      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "earned": "7800000",
                      "paid": "5000000",
                      "owed": "2800000",
                      "decimals": 6,
                      "owedUsd": 2.8
                    }
                  ],
                  "payouts": [
                    {
                      "id": "po_01hxexample",
                      "partnerId": "myapp",
                      "chainId": 8453,
                      "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "amount": "5000000",
                      "toAddress": "0x1111111111111111111111111111111111111111",
                      "txHash": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
                      "note": "September",
                      "paidAt": "2026-10-01T12:00:00.000Z",
                      "createdAt": "2026-10-01T12:00:05.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/checkout/sessions": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCheckoutSessions",
        "summary": "List checkout sessions",
        "description": "The same list as `GET /v1/checkout/sessions`, with the dashboard session and `mode`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only sessions with this status.",
            "schema": {
              "$ref": "#/components/schemas/CheckoutStatus"
            }
          },
          {
            "name": "productId",
            "in": "query",
            "required": false,
            "description": "Only sessions started from this product.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateCheckoutSession",
        "summary": "Create a payment link",
        "description": "Creates a checkout session from the dashboard: the `CheckoutSessionCreateRequest` body plus `mode` (`live` or `test`).",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/CheckoutSessionCreateRequest"
                  }
                ],
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "default": "live"
                  }
                }
              },
              "example": {
                "amount": "49000000",
                "settleChain": "base",
                "settleToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "description": "Pro plan, 1 month",
                "mode": "test"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/checkout/sessions/{id}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardGetCheckoutSession",
        "summary": "Get a payment link",
        "description": "One of your sessions (either mode), with reference, metadata, `refundedAmount` and `invoiceId`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_test_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/checkout/sessions/{id}/expire": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardExpireCheckoutSession",
        "summary": "Expire a payment link",
        "description": "Expires one of your `open` sessions.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_test_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The expired session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}/refunds": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "createCheckoutRefund",
        "summary": "Refund a paid session",
        "description": "Starts a full or partial refund of a `paid` session. Non-custodial: LayerHop never holds the\nmoney, so you send the refund from your own wallet (`from`, default the session's payout\naddress). By default it is routed from the settlement token back to the payer's original chain\nand token (`to: original`); `to: settlement` sends the settlement token to the payer's address on\nthe settlement chain (same chain family only). The response carries a `quote`: build its\ntransaction with `POST /v1/orders { quoteId }`, sign it from `quote.from`, then report it with\n`POST /v1/orders/{quoteId}/submitted`. When the transfer lands the refund is `completed`, the\nsession's `refundedAmount` grows and `checkout.session.refunded` is sent. LayerHop takes no fee\non refunds. Test-mode sessions refund through the sandbox.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundCreateRequest"
              },
              "example": {
                "amount": "20000000",
                "reason": "Partial refund: one seat cancelled"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Refund created (`pending` until you report its transaction).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundCreateResponse"
                },
                "example": {
                  "refund": {
                    "id": "re_01k7v2a8c4x8q6r0v3b5n7p9d",
                    "object": "refund",
                    "sessionId": "cs_01k7t9m2c4x8q6r0v3b5n7p9d",
                    "livemode": true,
                    "status": "pending",
                    "amount": "20000000",
                    "reason": "Partial refund: one seat cancelled",
                    "quoteId": "q_01k7v2a8d1y3m5p7r9t1v3x5z",
                    "to": {
                      "chainId": 42161,
                      "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
                      "address": "0x1111111111111111111111111111111111111111"
                    },
                    "createdAt": "2026-10-18T12:00:00.000Z",
                    "updatedAt": "2026-10-18T12:00:00.000Z"
                  },
                  "quote": {
                    "quoteId": "q_01k7v2a8d1y3m5p7r9t1v3x5z",
                    "provider": "relay",
                    "srcAmount": "20000000",
                    "dstAmount": "19968000",
                    "dstAmountMin": "19768320",
                    "estimatedSeconds": 12,
                    "expiresAt": 1792324830,
                    "from": "0x2222222222222222222222222222222222222222"
                  },
                  "next": "Build the transaction with POST /v1/orders { quoteId }, sign it from the `from` wallet, then report it with POST /v1/orders/{quoteId}/submitted."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "listCheckoutRefunds",
        "summary": "List a session's refunds",
        "description": "Every refund of one of your sessions, newest first.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The refunds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/invoices": {
      "post": {
        "tags": [
          "Invoices"
        ],
        "operationId": "createInvoice",
        "summary": "Create an invoice",
        "description": "Bills a customer for line items in a settlement stablecoin (USDC or USDT on a supported chain),\npaid to `recipient`. The invoice starts as a `draft` with the next number of the key's mode\n(`INV-0001`, …); pass `send: true` to finalize and email it at once. The total `amount` is the\nsum of `quantity × unitAmount`. An `lh_test_` key creates a test-mode invoice (`inv_test_…`).\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvoiceCreateRequest"
              },
              "example": {
                "customerEmail": "ap@acme.example",
                "customerName": "Acme Corp",
                "merchantName": "Studio Nine",
                "lineItems": [
                  {
                    "description": "Design retainer, October",
                    "quantity": 1,
                    "unitAmount": "1500000000"
                  },
                  {
                    "description": "Extra revision",
                    "quantity": 2,
                    "unitAmount": "100000000"
                  }
                ],
                "settleChain": "base",
                "settleToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "dueAt": "2026-11-01",
                "memo": "Thank you!",
                "send": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                },
                "example": {
                  "id": "inv_01k7v0c2c4x8q6r0v3b5n7p9d",
                  "object": "invoice",
                  "livemode": true,
                  "number": "INV-0001",
                  "status": "open",
                  "merchantName": "Studio Nine",
                  "customerName": "Acme Corp",
                  "customerEmail": "ap@acme.example",
                  "memo": "Thank you!",
                  "lineItems": [
                    {
                      "description": "Design retainer, October",
                      "quantity": 1,
                      "unitAmount": "1500000000"
                    },
                    {
                      "description": "Extra revision",
                      "quantity": 2,
                      "unitAmount": "100000000"
                    }
                  ],
                  "amount": "1700000000",
                  "settlement": {
                    "chainId": 8453,
                    "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                    "symbol": "USDC",
                    "decimals": 6
                  },
                  "recipient": "0x2222222222222222222222222222222222222222",
                  "dueAt": "2026-11-01T23:59:59.000Z",
                  "url": "https://layerhop.com/invoice/inv_01k7v0c2c4x8q6r0v3b5n7p9d",
                  "sentAt": "2026-10-18T10:00:00.000Z",
                  "createdAt": "2026-10-18T10:00:00.000Z",
                  "updatedAt": "2026-10-18T10:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "get": {
        "tags": [
          "Invoices"
        ],
        "operationId": "listInvoices",
        "summary": "List invoices",
        "description": "Your account's invoices of the key's mode (live or test), newest first.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only invoices with this status.",
            "schema": {
              "$ref": "#/components/schemas/InvoiceStatus"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/invoices/{id}": {
      "get": {
        "tags": [
          "Invoices"
        ],
        "operationId": "getInvoice",
        "summary": "Get an invoice",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Invoices"
        ],
        "operationId": "updateInvoice",
        "summary": "Update a draft invoice",
        "description": "Change any field of a `draft` (other statuses return `CONFLICT`). The total and the payout are re-validated; `null` clears an optional field.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvoiceUpdateRequest"
              },
              "example": {
                "dueAt": "2026-11-15",
                "memo": "Net 30"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/invoices/{id}/send": {
      "post": {
        "tags": [
          "Invoices"
        ],
        "operationId": "sendInvoice",
        "summary": "Send an invoice",
        "description": "Finalizes a `draft` (it becomes `open` and can no longer be edited) and emails it to\n`customerEmail` from billing@layerhop.com with a link to the hosted page\n`https://layerhop.com/invoice/{id}`. Sending an `open` invoice again re-sends the email. Sends\n`invoice.sent`. Paid and void invoices return `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The open invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/invoices/{id}/void": {
      "post": {
        "tags": [
          "Invoices"
        ],
        "operationId": "voidInvoice",
        "summary": "Void an invoice",
        "description": "Cancels a `draft` or `open` invoice for good; an open checkout session paying it is expired. Paid and void invoices return `CONFLICT`.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The void invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/invoices/{id}/public": {
      "get": {
        "tags": [
          "Invoices"
        ],
        "operationId": "getPublicInvoice",
        "summary": "Get the customer's view of an invoice",
        "description": "Public, no key: what the hosted invoice page shows. Drafts return `NOT_FOUND`. Omits the customer email, the payout address and the session.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicInvoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/invoices/{id}/pay": {
      "post": {
        "tags": [
          "Invoices"
        ],
        "operationId": "payInvoice",
        "summary": "Start paying an invoice",
        "description": "Public, no key: returns the checkout session that pays this invoice. A session that is still\nopen (with more than 5 minutes left) or already processing is reused (200); otherwise a new\none is created (201). Send the customer to `url`; when it is paid the invoice becomes `paid`,\nthe receipt is emailed and `invoice.paid` is sent. Paid and void invoices return `CONFLICT`.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The existing session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoicePayResponse"
                }
              }
            }
          },
          "201": {
            "description": "A new session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoicePayResponse"
                },
                "example": {
                  "sessionId": "cs_01k7v1f4c4x8q6r0v3b5n7p9d",
                  "url": "https://layerhop.com/pay/cs_01k7v1f4c4x8q6r0v3b5n7p9d"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/invoices/{id}/receipt.pdf": {
      "get": {
        "tags": [
          "Invoices"
        ],
        "operationId": "getInvoiceReceipt",
        "summary": "Download a receipt",
        "description": "Public, no key: a one-page PDF receipt of a `paid` invoice (the `receiptUrl` of the invoice). Unpaid invoices return `NOT_FOUND`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/subscriptions": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "createSubscription",
        "summary": "Create a subscription",
        "description": "Starts billing a customer every `intervalCount` × `interval` (day, week, month or year) in a\nsettlement stablecoin. Pass `productId` to bill a product's price, settlement token and payout\naddress, or `amount`, `settleChain`, `settleToken`, `recipient` and `description` directly.\nThe first invoice is issued and emailed at `startAt` (default: now, within a minute); each next\none at the end of the period. Invoices are due `daysUntilDue` days after they are issued\n(default 3). Sends `subscription.created`. An `lh_test_` key creates a test-mode subscription\n(`sub_test_…`).\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionCreateRequest"
              },
              "example": {
                "customerEmail": "ada@example.com",
                "customerName": "Ada Lovelace",
                "merchantName": "Studio Nine",
                "description": "Pro plan",
                "amount": "49000000",
                "settleChain": "base",
                "settleToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "interval": "month",
                "metadata": {
                  "plan": "pro"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "listSubscriptions",
        "summary": "List subscriptions",
        "description": "Your account's subscriptions of the key's mode (live or test), newest first.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only subscriptions with this status.",
            "schema": {
              "$ref": "#/components/schemas/SubscriptionStatus"
            }
          },
          {
            "name": "customerEmail",
            "in": "query",
            "required": false,
            "description": "Only this customer's subscriptions.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of subscriptions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/subscriptions/{id}": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "getSubscription",
        "summary": "Get a subscription",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "updateSubscription",
        "summary": "Update a subscription",
        "description": "Changes apply from the next invoice: the customer, `description`, `memo`, `amount`, `daysUntilDue`\nand `metadata`. `cancelAtPeriodEnd: true` schedules a cancel at the end of the current period and\n`false` undoes it. The interval and the settlement can't change (create a new subscription).\nCanceled subscriptions return `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionUpdateRequest"
              },
              "example": {
                "amount": "59000000",
                "cancelAtPeriodEnd": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/subscriptions/{id}/invoices": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "listSubscriptionInvoices",
        "summary": "List a subscription's invoices",
        "description": "The invoices issued for this subscription (up to 100), newest first.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "Its invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionInvoiceList"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/subscriptions/{id}/cancel": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "cancelSubscription",
        "summary": "Cancel a subscription",
        "description": "Cancels now (`atPeriodEnd` false, the default): no more invoices and `subscription.canceled`.\nInvoices already sent stay open; void them with `POST /v1/invoices/{id}/void` if the customer\nshouldn't pay them. With `atPeriodEnd: true` it stays active until `currentPeriodEnd` and is\ncanceled instead of renewed (`cancelAtPeriodEnd` true). Already canceled returns `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionCancelRequest"
              },
              "example": {
                "atPeriodEnd": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/subscriptions/{id}/pause": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "pauseSubscription",
        "summary": "Pause a subscription",
        "description": "Stops issuing invoices and sending reminders. Only `active` subscriptions can be paused (a\n`past_due` one must be paid or canceled first); others return `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/subscriptions/{id}/resume": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "resumeSubscription",
        "summary": "Resume a subscription",
        "description": "Resumes a `paused` subscription. If the current period hasn't ended, billing continues on the\nold schedule; otherwise a new period starts now and its invoice goes out right away (paused\ntime is never billed). Invoices still open get a fresh due date. Other statuses return `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/deposit-addresses": {
      "post": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "createDepositAddress",
        "summary": "Create a deposit address",
        "description": "Returns an address on `srcChain` that your user sends `srcToken` to; each deposit is swapped or\nbridged to `dstToken` on `dstChain` and delivered to `recipient`. The address is created by the\nliquidity provider (Relay); LayerHop never holds the funds. The fee is the API channel fee plus\nyour partner fee (`integrator`, `integratorFeeBps`, resolved exactly as for `GET /v1/quote`).\n`reusable: true` (default) accepts any number of deposits of any amount on the same route;\n`reusable: false` is a one-time address for exactly `amount` (underpayments are refunded to\n`refundTo`). Deposits must be worth at least $1. The response adds an `estimate` for `amount`\n(default: about $100 of `srcToken`). An `lh_test_` key creates a test-mode address (provider\n`sandbox`, a fake address you can `simulate` deposits to); live keys get `FORBIDDEN` until\ndeposit addresses are enabled for live mode on your account (rolling out, available on\nrequest). Uses the strict rate-limit bucket.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositAddressCreateRequest"
              },
              "example": {
                "srcChain": "base",
                "srcToken": "USDC",
                "dstChain": "arbitrum",
                "dstToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "refundTo": "0x3333333333333333333333333333333333333333",
                "label": "user-4821",
                "metadata": {
                  "userId": "4821"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Deposit address created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressCreated"
                },
                "example": {
                  "id": "da_01k7x2m4c4x8q6r0v3b5n7p9d",
                  "object": "deposit_address",
                  "livemode": true,
                  "status": "active",
                  "provider": "relay",
                  "address": "0x7d3a9f0c1b2e4d5f6a7b8c9d0e1f2a3b4c5d6e7f",
                  "chainId": 8453,
                  "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                  "dstChainId": 42161,
                  "dstToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
                  "recipient": "0x2222222222222222222222222222222222222222",
                  "refundTo": "0x3333333333333333333333333333333333333333",
                  "reusable": true,
                  "fees": {
                    "ourFeeBps": 20,
                    "integratorFeeBps": 0
                  },
                  "label": "user-4821",
                  "metadata": {
                    "userId": "4821"
                  },
                  "depositCount": 0,
                  "createdAt": "2026-10-19T10:00:00.000Z",
                  "estimate": {
                    "amount": "100000000",
                    "dstAmount": "99780000",
                    "dstAmountMin": "99280000",
                    "estimatedSeconds": 12
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: deposit addresses are not enabled for live mode on this account yet; use a test key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      },
      "get": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "listDepositAddresses",
        "summary": "List deposit addresses",
        "description": "Your account's deposit addresses of the key's mode (live or test), newest first.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only addresses with this status.",
            "schema": {
              "$ref": "#/components/schemas/DepositAddressStatus"
            }
          },
          {
            "name": "label",
            "in": "query",
            "required": false,
            "description": "Only addresses with exactly this label.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–200, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of deposit addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/deposit-addresses/{id}": {
      "get": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "getDepositAddress",
        "summary": "Get a deposit address",
        "description": "The address and its 20 most recent deposits (each one an order), newest first.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The deposit address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressWithDeposits"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/deposit-addresses/{id}/refresh": {
      "post": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "refreshDepositAddress",
        "summary": "Check for deposits now",
        "description": "Deposits are detected every ~15 seconds while an address is busy, backing off to every 15 minutes\nwhen it is idle. Call this when your user says they sent funds: the next check runs right away\nand the backoff resets. Disabled addresses return `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "202": {
            "description": "Check scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/deposit-addresses/{id}/disable": {
      "post": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "disableDepositAddress",
        "summary": "Disable a deposit address",
        "description": "Stops tracking the address (`status: disabled`). Stop showing it to your user: the provider may\nstill process funds sent to it later, but LayerHop no longer reports them.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The disabled address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/deposit-addresses/{id}/simulate": {
      "post": {
        "tags": [
          "Deposit addresses"
        ],
        "operationId": "simulateDeposit",
        "summary": "Simulate a deposit (test mode)",
        "description": "Test keys only (live addresses return `FORBIDDEN`). Records a deposit of `amount` as a new\n`submitted` order that settles like any test order: an amount ending in `4001` is refunded,\n`4002` fails, anything else fills, with the usual `order.*` webhooks. A one-time address needs\nexactly its `amount` and accepts a single deposit (`CONFLICT` after that); disabled addresses\nreturn `CONFLICT`.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateDepositRequest"
              },
              "example": {
                "amount": "25000000"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Test deposit recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "order"
                  ],
                  "properties": {
                    "order": {
                      "$ref": "#/components/schemas/AccountOrder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: a live address; simulate works in test mode only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/limit-orders": {
      "post": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "createLimitOrder",
        "summary": "Create a limit order",
        "description": "Builds a Solana limit order (Jupiter Trigger): sell `amount` of `srcToken` for at least\n`dstAmount` of `dstToken` (the limit price is `dstAmount / amount`), optionally until\n`expiresAt`. Returns the order and an unsigned transaction (`tx.submitViaApi: true`): the\n`wallet` signs it and you send it to `POST /v1/limit-orders/{id}/submit`. Nothing is on chain\nuntil then. Orders may fill in several parts. The fee is the channel fee plus your partner fee\n(`integrator`, `integratorFeeBps`, resolved as for `GET /v1/quote`), written into the on-chain\norder and charged in `dstToken` on every fill. It applies when `dstToken` is SOL, USDC or USDT;\nfor other output tokens the order carries no fee and `fees` reports 0. Orders must be worth at\nleast $5. An API key is optional (orders are attributed to its account); an `lh_test_` key\ncreates a test-mode order (provider `sandbox`, a fake transaction). Uses the strict rate-limit bucket.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LimitOrderCreateRequest"
              },
              "example": {
                "wallet": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
                "srcToken": "SOL",
                "dstToken": "USDC",
                "amount": "1000000000",
                "dstAmount": "250000000",
                "expiresAt": 1792540800
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order built; sign `tx` with `wallet` and submit it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrderCreated"
                },
                "example": {
                  "id": "lo_01k7x2m4c4x8q6r0v3b5n7p9d",
                  "object": "limit_order",
                  "livemode": true,
                  "status": "built",
                  "provider": "jupiter",
                  "chainId": 7565164,
                  "wallet": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
                  "srcToken": "So11111111111111111111111111111111111111112",
                  "dstToken": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
                  "amount": "1000000000",
                  "dstAmount": "250000000",
                  "expiresAt": "2026-10-20T00:00:00.000Z",
                  "fees": {
                    "ourFeeBps": 20,
                    "integratorFeeBps": 0
                  },
                  "providerOrderId": "hU7b1KJtdhUazueSB85CYFdt8osnpAQYmvNGde7U3Ut",
                  "filledAmount": "0",
                  "filledDstAmount": "0",
                  "fillCount": 0,
                  "channel": "api",
                  "createdAt": "2026-10-19T10:00:00.000Z",
                  "updatedAt": "2026-10-19T10:00:00.000Z",
                  "tx": {
                    "vm": "svm",
                    "serializedTx": "AQAAAAAAAAAA…",
                    "submitViaApi": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      },
      "get": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "listLimitOrders",
        "summary": "List limit orders",
        "description": "Orders of `wallet` (any caller, like `GET /v1/orders?address=`), or without `wallet` the orders\nof your API key's account. Only orders of the caller's mode (live, or test with an `lh_test_`\nkey), newest first.\n",
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "required": false,
            "description": "The maker wallet. Required without an API key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only orders with this status.",
            "schema": {
              "$ref": "#/components/schemas/LimitOrderStatus"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–200, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of limit orders.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrderList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/limit-orders/{id}": {
      "get": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "getLimitOrder",
        "summary": "Get a limit order",
        "description": "The order and its fills (each one an order whose `quoteId` starts with `lof_`), newest first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Limit order id.",
            "schema": {
              "type": "string"
            },
            "example": "lo_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The limit order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrderWithFills"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/limit-orders/{id}/submit": {
      "post": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "submitLimitOrder",
        "summary": "Submit a signed limit order transaction",
        "description": "Sends the wallet-signed create or cancel transaction (whichever was built last) to the provider,\nwhich lands it. Creating: the order becomes `open` and `limit_order.opened` is sent. Cancelling:\n`cancelTxHash` is set right away and the order becomes `cancelled` (with any fills recorded first)\nonce the provider confirms, usually within seconds. `CONFLICT` when there is nothing to submit.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Limit order id.",
            "schema": {
              "type": "string"
            },
            "example": "lo_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LimitOrderSubmitRequest"
              },
              "example": {
                "signedTransaction": "AQAB…"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Landed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrderSubmitResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      }
    },
    "/v1/limit-orders/{id}/cancel": {
      "post": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "cancelLimitOrder",
        "summary": "Cancel a limit order",
        "description": "An `open` order returns an unsigned cancel transaction (`tx`) for the order's wallet: sign it and\nsend it to `POST /v1/limit-orders/{id}/submit`; the unfilled input goes back to the wallet. A\n`built` order (never submitted) is cancelled at once and `tx` is null. Other statuses return `CONFLICT`.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Limit order id.",
            "schema": {
              "type": "string"
            },
            "example": "lo_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "Cancel transaction built (or the order cancelled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrderCancelResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      }
    },
    "/v1/limit-orders/{id}/simulate": {
      "post": {
        "tags": [
          "Limit orders"
        ],
        "operationId": "simulateLimitOrder",
        "summary": "Simulate a fill or expiry (test mode)",
        "description": "Test-mode orders only (live orders return `FORBIDDEN`). The order must be `open`. Within a few\nseconds the worker applies `outcome`: `fill` fills the rest, `partial_fill` fills half of the\nrest (the order stays `open`), `expire` expires it, with the usual `limit_order.*` webhooks and a\nfill order for each fill.\n",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Limit order id.",
            "schema": {
              "type": "string"
            },
            "example": "lo_01k7x2m4c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LimitOrderSimulateRequest"
              },
              "example": {
                "outcome": "fill"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Outcome scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LimitOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: a live order; simulate works in test mode only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "operationId": "getStatus",
        "summary": "Get platform status",
        "description": "Public, no key, CORS open, cached for 30 seconds: the data behind status.layerhop.com. Every\ncomponent is probed each minute; `status` is `outage` when a component is down, `degraded` when\none failed its latest probe, else `operational`. Includes 90 days of daily uptime per component\nand the incidents of the last 14 days.\n",
        "responses": {
          "200": {
            "description": "Current status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusResponse"
                },
                "example": {
                  "status": "operational",
                  "updatedAt": "2026-10-18T10:00:00.000Z",
                  "components": [
                    {
                      "id": "api",
                      "name": "API",
                      "group": "Core",
                      "status": "operational",
                      "latencyMs": 84,
                      "uptime90d": 99.98,
                      "days": [
                        {
                          "date": "2026-10-18",
                          "uptime": 100
                        }
                      ]
                    },
                    {
                      "id": "provider:relay",
                      "name": "Relay",
                      "group": "Liquidity providers",
                      "status": "operational",
                      "latencyMs": 412,
                      "uptime90d": 99.9,
                      "days": [
                        {
                          "date": "2026-10-18",
                          "uptime": 100
                        }
                      ]
                    }
                  ],
                  "incidents": [
                    {
                      "id": "inc_01k7r1a8c4x8q6r0v3b5n7p9d",
                      "componentId": "provider:relay",
                      "component": "Relay",
                      "title": "Relay quotes failing",
                      "startedAt": "2026-10-12T08:10:00.000Z",
                      "resolvedAt": "2026-10-12T08:24:00.000Z"
                    }
                  ],
                  "url": "https://layerhop.com/status"
                }
              }
            }
          }
        }
      }
    },
    "/v1/dashboard/checkout/sessions/{id}/refunds": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateCheckoutRefund",
        "summary": "Refund a paid session",
        "description": "The same as `POST /v1/checkout/sessions/{id}/refunds`, with the dashboard session; the dashboard then asks your connected wallet to sign the refund.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Refund created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundCreateResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardListCheckoutRefunds",
        "summary": "List a session's refunds",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Session id.",
            "schema": {
              "type": "string"
            },
            "example": "cs_01k7t9m2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The refunds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundList"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/checkout/analytics": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCheckoutAnalytics",
        "summary": "Checkout analytics",
        "description": "Revenue of sessions created in `[from, to)` (default the last 30 days, at most 366 days): totals,\nrevenue per UTC day, by the token and chain customers paid with, and by settlement. Settlement\ntokens are USD stablecoins, so amounts are summed as USD.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start (ISO 8601 or unix seconds). Default `to` minus 30 days.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End, exclusive (ISO 8601 or unix seconds). Default now.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The analytics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutAnalytics"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/checkout/analytics/sessions.csv": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCheckoutSessionsCsv",
        "summary": "Export sessions as CSV",
        "description": "Sessions created in `[from, to)` as a CSV download (at most 50,000 rows, newest first) with the\ncolumns `id, created_at, status, amount, currency, settlement_chain, amount_usd, refunded,\ndescription, reference, product_id, invoice_id, payer, paid_with_chain, paid_with_token,\npaid_with_amount, src_tx_hash, dst_tx_hash, paid_at, livemode`. `status=paid` exports payments only.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start (ISO 8601 or unix seconds). Default `to` minus 30 days.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End, exclusive (ISO 8601 or unix seconds). Default now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only sessions with this status.",
            "schema": {
              "$ref": "#/components/schemas/CheckoutStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The CSV file.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/invoices": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardInvoices",
        "summary": "List invoices",
        "description": "The same list as `GET /v1/invoices`, with the dashboard session and `mode`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only invoices with this status.",
            "schema": {
              "$ref": "#/components/schemas/InvoiceStatus"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateInvoice",
        "summary": "Create an invoice",
        "description": "`InvoiceCreateRequest` plus `mode` (`live` or `test`).",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/InvoiceCreateRequest"
                  }
                ],
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "default": "live"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/dashboard/invoices/{id}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardGetInvoice",
        "summary": "Get an invoice",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardUpdateInvoice",
        "summary": "Update a draft invoice",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvoiceUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/invoices/{id}/send": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardSendInvoice",
        "summary": "Send an invoice",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The open invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/invoices/{id}/void": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardVoidInvoice",
        "summary": "Void an invoice",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Invoice id.",
            "schema": {
              "type": "string"
            },
            "example": "inv_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The void invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invoice"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateSubscription",
        "summary": "Create a subscription",
        "description": "`SubscriptionCreateRequest` plus `mode` (`live` or `test`).\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/SubscriptionCreateRequest"
                  }
                ],
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "default": "live"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardListSubscriptions",
        "summary": "List subscriptions",
        "description": "The same as `GET /v1/subscriptions`, with the dashboard session and `mode`.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only subscriptions with this status.",
            "schema": {
              "$ref": "#/components/schemas/SubscriptionStatus"
            }
          },
          {
            "name": "customerEmail",
            "in": "query",
            "required": false,
            "description": "Only this customer's subscriptions.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of subscriptions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions/{id}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardGetSubscription",
        "summary": "Get a subscription",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardUpdateSubscription",
        "summary": "Update a subscription",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions/{id}/invoices": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardListSubscriptionInvoices",
        "summary": "List a subscription's invoices",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "Its invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionInvoiceList"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions/{id}/cancel": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCancelSubscription",
        "summary": "Cancel a subscription",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionCancelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions/{id}/pause": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardPauseSubscription",
        "summary": "Pause a subscription",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/subscriptions/{id}/resume": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardResumeSubscription",
        "summary": "Resume a subscription",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Subscription id.",
            "schema": {
              "type": "string"
            },
            "example": "sub_test_01k7v0c2c4x8q6r0v3b5n7p9d"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subscription"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/deposit-addresses": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardDepositAddresses",
        "summary": "List deposit addresses",
        "description": "The same list as `GET /v1/deposit-addresses`, with the dashboard session and `mode`. It includes addresses created with API keys and from the dashboard.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Mode"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only addresses with this status.",
            "schema": {
              "$ref": "#/components/schemas/DepositAddressStatus"
            }
          },
          {
            "name": "label",
            "in": "query",
            "required": false,
            "description": "Only addresses with exactly this label.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`nextCursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–200, default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of deposit addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardCreateDepositAddress",
        "summary": "Create a deposit address",
        "description": "`DepositAddressCreateRequest` plus `mode` (`live` or `test`; default the `mode` query parameter,\nthen live), with the same validation as `POST /v1/deposit-addresses`. The address belongs to the\nsigned-in account and has no API key. Live mode returns `FORBIDDEN` until deposit addresses are\nenabled for live mode. Uses the strict rate-limit bucket.\n",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/DepositAddressCreateRequest"
                  }
                ],
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "default": "live"
                  }
                }
              },
              "example": {
                "mode": "test",
                "srcChain": "base",
                "srcToken": "USDC",
                "dstChain": "arbitrum",
                "dstToken": "USDC",
                "recipient": "0x2222222222222222222222222222222222222222",
                "refundTo": "0x3333333333333333333333333333333333333333",
                "label": "user-4821"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Deposit address created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: live mode before deposit addresses are enabled for live, or a cross-origin request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/ProviderError"
          }
        }
      }
    },
    "/v1/dashboard/deposit-addresses/{id}": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardGetDepositAddress",
        "summary": "Get a deposit address",
        "description": "The address and its 20 most recent deposits (each one an order), newest first. Addresses of other accounts return `NOT_FOUND`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`live` or `test`. When given, an address of the other mode returns `NOT_FOUND`.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The deposit address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddressWithDeposits"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/deposit-addresses/{id}/refresh": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardRefreshDepositAddress",
        "summary": "Check a deposit address for deposits now",
        "description": "Same as `POST /v1/deposit-addresses/{id}/refresh`. Disabled addresses return `CONFLICT`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`live` or `test`. When given, an address of the other mode returns `NOT_FOUND`.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Check scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/dashboard/deposit-addresses/{id}/disable": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardDisableDepositAddress",
        "summary": "Disable a deposit address",
        "description": "Same as `POST /v1/deposit-addresses/{id}/disable`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`live` or `test`. When given, an address of the other mode returns `NOT_FOUND`.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The disabled address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositAddress"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard/deposit-addresses/{id}/simulate": {
      "post": {
        "tags": [
          "Dashboard"
        ],
        "operationId": "dashboardSimulateDeposit",
        "summary": "Simulate a deposit (test mode)",
        "description": "Same as `POST /v1/deposit-addresses/{id}/simulate`. Live addresses return `FORBIDDEN`.",
        "security": [
          {
            "Session": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Deposit address id.",
            "schema": {
              "type": "string"
            },
            "example": "da_01k7x2m4c4x8q6r0v3b5n7p9d"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`live` or `test`. When given, an address of the other mode returns `NOT_FOUND`.",
            "schema": {
              "type": "string",
              "enum": [
                "live",
                "test"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateDepositRequest"
              },
              "example": {
                "amount": "25000000"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Test deposit recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "order"
                  ],
                  "properties": {
                    "order": {
                      "$ref": "#/components/schemas/AccountOrder"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`FORBIDDEN`: a live address; simulate works in test mode only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/admin/partners": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listPartners",
        "summary": "List partners",
        "description": "The partner registry (`PARTNERS_JSON`) without API keys.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Registered partners.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnersResponse"
                },
                "example": {
                  "partners": [
                    {
                      "id": "myapp",
                      "name": "My App",
                      "feeBps": 20,
                      "maxFeeBps": 100,
                      "payoutEvm": "0x1111111111111111111111111111111111111111",
                      "hasApiKey": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Admin routes are disabled (`ADMIN_TOKEN` is not set)."
          }
        }
      }
    },
    "/v1/admin/partners/{id}/ledger": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "getPartnerLedger",
        "summary": "Partner fee ledger",
        "description": "Ledger entries for one partner plus per-source-token totals. `basis` is `built`: entries mean a\ntransaction was built (`POST /v1/orders`) or submitted (`POST /v1/orders/submit`) through\nLayerHop, not that the swap filled. Reconcile against order status before paying out.\n",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,32}$"
            },
            "example": "myapp"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Inclusive start, ISO 8601 date/time or unix seconds.",
            "schema": {
              "type": "string"
            },
            "example": "2026-10-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Inclusive end, ISO 8601 date/time or unix seconds.",
            "schema": {
              "type": "string"
            },
            "example": "2026-10-31T23:59:59Z"
          }
        ],
        "responses": {
          "200": {
            "description": "Entries and totals.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerLedgerResponse"
                },
                "example": {
                  "partner": "myapp",
                  "basis": "built",
                  "from": "2026-10-01T00:00:00.000Z",
                  "entries": [
                    {
                      "type": "built",
                      "quoteId": "q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10",
                      "partner": "myapp",
                      "provider": "relay",
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "dstChainId": 7565164,
                      "dstToken": "So11111111111111111111111111111111111111112",
                      "amount": "100000000",
                      "dstAmount": "612345678",
                      "ourFeeBps": 30,
                      "integratorFeeBps": 20,
                      "partnerFeeEstimate": "200000",
                      "createdAt": "2026-10-17T10:00:00.000Z"
                    }
                  ],
                  "totals": [
                    {
                      "srcChainId": 8453,
                      "srcToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                      "builtCount": 1,
                      "submittedCount": 0,
                      "partnerFeeEstimate": "200000"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Admin routes are disabled (`ADMIN_TOKEN` is not set)."
          }
        }
      }
    },
    "/v1/admin/partners/{id}/approve": {
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "approvePartner",
        "summary": "Approve a partner",
        "description": "Sets a DB partner `active` with `maxFeeBps` (<= `MAX_TOTAL_FEE_BPS`); `feeBps` is clamped to it. Needs a database.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id.",
            "schema": {
              "type": "string"
            },
            "example": "myapp"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApproveRequest"
              },
              "example": {
                "maxFeeBps": 50
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated partner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminPartnerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/admin/partners/{id}/suspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "suspendPartner",
        "summary": "Suspend a partner",
        "description": "Sets a DB partner `suspended`; its fee stops applying within 60 s.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id.",
            "schema": {
              "type": "string"
            },
            "example": "myapp"
          }
        ],
        "responses": {
          "200": {
            "description": "The updated partner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminPartnerResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/admin/partners/{id}/payouts": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listPartnerPayouts",
        "summary": "Partner balances and payouts",
        "description": "Balances per token (as in `GET /v1/dashboard/payouts`) and every recorded payout, voided ones included. Needs a database.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id (DB or `PARTNERS_JSON`).",
            "schema": {
              "type": "string"
            },
            "example": "myapp"
          }
        ],
        "responses": {
          "200": {
            "description": "Balances and payouts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "recordPartnerPayout",
        "summary": "Record a payout",
        "description": "Records a transfer the operator already made to the partner (LayerHop never sends it). It\nreduces the partner's `owed` balance for that token. `token` and `toAddress` must be valid for\n`chainId`; `txHash` is a 0x hash on EVM chains or a base58 signature on Solana.\n",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id.",
            "schema": {
              "type": "string"
            },
            "example": "myapp"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutRequest"
              },
              "example": {
                "chainId": 8453,
                "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "amount": "5000000",
                "toAddress": "0x1111111111111111111111111111111111111111",
                "txHash": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
                "note": "September"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The recorded payout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/admin/partners/{id}/payouts/{payoutId}/void": {
      "post": {
        "tags": [
          "Admin"
        ],
        "operationId": "voidPartnerPayout",
        "summary": "Void a payout",
        "description": "Marks a payout recorded by mistake as void. It stops counting toward `paid` but stays in the admin history.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Partner id.",
            "schema": {
              "type": "string"
            },
            "example": "myapp"
          },
          {
            "name": "payoutId",
            "in": "path",
            "required": true,
            "description": "Payout id.",
            "schema": {
              "type": "string"
            },
            "example": "po_01hxexample"
          }
        ],
        "responses": {
          "200": {
            "description": "The voided payout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/admin/payouts/owed": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "listOwedPayouts",
        "summary": "Partners owed a payout",
        "description": "Every partner with a positive `owed` balance in at least one token, with only those balances.",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Partners to pay.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "partners"
                  ],
                  "properties": {
                    "partners": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "partner",
                          "balances"
                        ],
                        "properties": {
                          "partner": {
                            "type": "string"
                          },
                          "balances": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/PartnerBalance"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "partners": [
                    {
                      "partner": "myapp",
                      "balances": [
                        {
                          "chainId": 8453,
                          "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                          "earned": "7800000",
                          "paid": "5000000",
                          "owed": "2800000",
                          "decimals": 6,
                          "owedUsd": 2.8
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/admin/traffic": {
      "get": {
        "tags": [
          "Admin"
        ],
        "operationId": "getTraffic",
        "summary": "API traffic per day",
        "description": "Per UTC day (oldest first, today last, days without traffic as zeros): requests to the public\nAPI, unique clients, successful `GET /v1/quote` responses and orders built, each split into\nrequests with and without an API key.\n\nUnique clients are distinct daily client hashes: an HMAC-SHA256 of the client IP under a key\nderived from `SESSION_SECRET` and the UTC date, truncated to 16 hex chars. IPs are never stored\nand hashes can't be linked across days. A client that called both with and without a key\ncounts once in `total` and once in each of `withKey` and `withoutKey`.\n",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Number of days, 1 to 90 (default 30).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Traffic per day.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "days"
                  ],
                  "properties": {
                    "days": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TrafficDay"
                      }
                    }
                  }
                },
                "example": {
                  "days": [
                    {
                      "date": "2026-10-19",
                      "requests": {
                        "total": 1840,
                        "withKey": 1210,
                        "withoutKey": 630
                      },
                      "uniqueClients": {
                        "total": 96,
                        "withKey": 12,
                        "withoutKey": 88
                      },
                      "quotes": {
                        "total": 702,
                        "withKey": 455,
                        "withoutKey": 247
                      },
                      "ordersBuilt": {
                        "total": 41,
                        "withKey": 29,
                        "withoutKey": 12
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/admin/keys/{id}": {
      "patch": {
        "tags": [
          "Admin"
        ],
        "operationId": "setKeyRateLimit",
        "summary": "Set a key's rate limit",
        "security": [
          {
            "AdminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Key id.",
            "schema": {
              "type": "string"
            },
            "example": "key_01m54s12va302av4ay4epqndye"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RateLimitRequest"
              },
              "example": {
                "rateLimitRpm": 600
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminKeyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Mode": {
        "name": "mode",
        "in": "query",
        "required": false,
        "description": "`live` (default) or `test`: which data to show. Test-mode data comes from `lh_test_` keys and never mixes with live data.",
        "schema": {
          "type": "string",
          "enum": [
            "live",
            "test"
          ],
          "default": "live"
        }
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Optional. An `lh_live_…` key from the dashboard attributes requests and orders to your account\nand raises your rate limit (per key, default 120 requests/minute; without a key the limit is\nper IP). An invalid or revoked key is rejected with `UNAUTHORIZED`. If your account has an\nactive partner profile, the key selects your partner fee and allows `integratorFeeBps`.\n\nAn `lh_test_…` key switches every request to **test mode**: quotes come from the `sandbox`\nprovider (priced from live USD prices), built transactions are placeholders that move no funds\n(`tx.sandbox: true`), and reported orders run a simulated lifecycle (pending, then filled in about\n10 seconds) with webhooks sent to your test endpoints only. Amounts ending in `4001` refund,\n`4002` fail and `4004` return `NO_ROUTE`. Test and live data never mix: a quote, order or\nwebhook of one mode is invisible to the other.\n"
      },
      "Session": {
        "type": "apiKey",
        "in": "cookie",
        "name": "lh_session",
        "description": "Dashboard session cookie set by `POST /v1/auth/verify` (HttpOnly, Secure, SameSite=Lax,\n7 days). Auth and Dashboard routes only.\n"
      },
      "AdminBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Operator `ADMIN_TOKEN`. Admin routes only."
      }
    },
    "headers": {
      "RequestId": {
        "description": "Unique id for this request. Quote it when you report a problem.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request (`INVALID_PARAMS`, `UNSUPPORTED_CHAIN`, `UNSUPPORTED_TOKEN`,\n`AMOUNT_TOO_SMALL`, `AMOUNT_TOO_LARGE`).\n",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "INVALID_PARAMS",
                "message": "amount: amount must be an integer string in base units",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/INVALID_PARAMS"
              }
            }
          }
        }
      },
      "UnsupportedChain": {
        "description": "The chain is unknown (`UNSUPPORTED_CHAIN`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "UNSUPPORTED_CHAIN",
                "message": "Unsupported chain: avalanche",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/UNSUPPORTED_CHAIN"
              }
            }
          }
        }
      },
      "NoRoute": {
        "description": "No provider supports the route, or every provider failed (`NO_ROUTE`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "NO_ROUTE",
                "message": "No provider returned a quote",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/NO_ROUTE"
              }
            }
          }
        }
      },
      "QuoteNotFound": {
        "description": "Unknown `quoteId`, or the provider can no longer build it (`QUOTE_NOT_FOUND`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "QUOTE_NOT_FOUND",
                "message": "Unknown quoteId",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/QUOTE_NOT_FOUND"
              }
            }
          }
        }
      },
      "QuoteExpired": {
        "description": "The quote is past `expiresAt` (`QUOTE_EXPIRED`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "QUOTE_EXPIRED",
                "message": "Quote expired, request a new one",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/QUOTE_EXPIRED"
              }
            }
          }
        }
      },
      "OrderNotFound": {
        "description": "The provider does not know this order (`ORDER_NOT_FOUND`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "ORDER_NOT_FOUND",
                "message": "deBridge: order not found",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/ORDER_NOT_FOUND"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "The upstream provider rate-limited LayerHop (`RATE_LIMITED`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "RATE_LIMITED",
                "message": "li.quest 429",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/RATE_LIMITED"
              }
            }
          }
        }
      },
      "ProviderError": {
        "description": "The upstream provider failed (`PROVIDER_ERROR`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "PROVIDER_ERROR",
                "message": "api.relay.link 500",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/PROVIDER_ERROR"
              }
            }
          }
        }
      },
      "ProviderTimeout": {
        "description": "The upstream provider did not answer in time (`PROVIDER_TIMEOUT`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "PROVIDER_TIMEOUT",
                "message": "Timed out: dln.debridge.finance",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/PROVIDER_TIMEOUT"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or wrong credentials (`UNAUTHORIZED`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "UNAUTHORIZED",
                "message": "Invalid admin token",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/UNAUTHORIZED"
              }
            }
          }
        }
      },
      "Internal": {
        "description": "Unexpected server error (`INTERNAL`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "INTERNAL",
                "message": "Internal error",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/INTERNAL"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource does not exist or belongs to another account (`NOT_FOUND`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "NOT_FOUND",
                "message": "API key not found",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/NOT_FOUND"
              }
            }
          }
        }
      },
      "PlatformDisabled": {
        "description": "The operator runs the API without a database, so platform routes are off (`NOT_FOUND`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "NOT_FOUND",
                "message": "No route for POST /v1/auth/nonce",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/NOT_FOUND"
              }
            }
          }
        }
      },
      "Conflict": {
        "description": "The request conflicts with existing state (`CONFLICT`).",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "CONFLICT",
                "message": "A different txHash was already reported for this order",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/CONFLICT"
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Over your rate limit (`RATE_LIMITED`): the key's `rateLimitRpm`, or `ANON_RATE_LIMIT_RPM` per IP\nwithout a key. Wait `retry-after` seconds.\n",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/RequestId"
          },
          "retry-after": {
            "description": "Seconds until a request will be accepted.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "RATE_LIMITED",
                "message": "Rate limit of 120 requests/minute exceeded; retry in 1s",
                "requestId": "0d5e1f6a-3b2c-4d1e-8f9a-7b6c5d4e3f21",
                "docsUrl": "https://docs.layerhop.com/errors/RATE_LIMITED"
              }
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorCode": {
        "type": "string",
        "description": "Stable error code. Each has a page at `https://docs.layerhop.com/errors/{code}`.",
        "enum": [
          "INVALID_PARAMS",
          "UNSUPPORTED_CHAIN",
          "UNSUPPORTED_TOKEN",
          "AMOUNT_TOO_SMALL",
          "AMOUNT_TOO_LARGE",
          "CALLS_REVERTED",
          "NO_ROUTE",
          "QUOTE_NOT_FOUND",
          "QUOTE_EXPIRED",
          "ORDER_NOT_FOUND",
          "PROVIDER_ERROR",
          "PROVIDER_TIMEOUT",
          "RATE_LIMITED",
          "UNAUTHORIZED",
          "FORBIDDEN",
          "NOT_FOUND",
          "CONFLICT",
          "INTERNAL"
        ]
      },
      "Error": {
        "type": "object",
        "description": "Every non-2xx response has this body.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "requestId",
              "docsUrl"
            ],
            "properties": {
              "code": {
                "$ref": "#/components/schemas/ErrorCode"
              },
              "message": {
                "type": "string",
                "description": "Human-readable detail. Do not parse it."
              },
              "requestId": {
                "type": "string",
                "format": "uuid",
                "description": "Same value as the `x-request-id` header."
              },
              "docsUrl": {
                "type": "string",
                "format": "uri",
                "description": "Error catalog page, `https://docs.layerhop.com/errors/{code}`."
              }
            }
          }
        }
      },
      "ProviderId": {
        "type": "string",
        "description": "Liquidity provider. Loaded by default: `jupiter`, `relay`, `debridge`, `zerox`, `kyberswap`, `lifi`, `mayan`.\n`odos` is shut down; `mock` exists only in local\ndevelopment (`LAYERHOP_ENABLE_MOCK=1`). `sandbox` serves every request made with an `lh_test_` key.\n`direct` is a plain token transfer, used by checkout when the payer already holds the settlement token.\n",
        "enum": [
          "jupiter",
          "relay",
          "debridge",
          "mayan",
          "zerox",
          "kyberswap",
          "odos",
          "lifi",
          "mock",
          "sandbox",
          "direct"
        ]
      },
      "FeeChannel": {
        "type": "string",
        "description": "Where the trade comes from; decides LayerHop's fee. Defaults: `web` 30 bps, `widget`\n30 bps, `api` 20 bps, `bot` 90 bps (operators can override them).\n",
        "enum": [
          "web",
          "widget",
          "bot",
          "api"
        ],
        "default": "api"
      },
      "Vm": {
        "type": "string",
        "enum": [
          "evm",
          "svm"
        ],
        "description": "Virtual machine family. `svm` is Solana."
      },
      "Chain": {
        "type": "object",
        "description": "A chain in the registry (`ChainInfo`).",
        "required": [
          "id",
          "slug",
          "name",
          "vm",
          "nativeSymbol",
          "nativeDecimals",
          "logoURI",
          "explorerTx",
          "explorerAddress",
          "providers",
          "popular"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "EVM chain id, or `7565164` for Solana (LayerHop internal id)."
          },
          "slug": {
            "type": "string",
            "description": "Unique lowercase short name usable anywhere a chain is expected, e.g. `base`, `berachain`."
          },
          "name": {
            "type": "string"
          },
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "nativeSymbol": {
            "type": "string"
          },
          "nativeDecimals": {
            "type": "integer"
          },
          "logoURI": {
            "type": "string",
            "format": "uri",
            "description": "Chain logo (provider CDN)."
          },
          "explorerTx": {
            "type": "string",
            "format": "uri",
            "description": "Block explorer prefix; append a tx hash."
          },
          "explorerAddress": {
            "type": "string",
            "format": "uri",
            "description": "Block explorer prefix; append an address."
          },
          "providers": {
            "type": "array",
            "description": "Providers that can route from or to this chain.",
            "items": {
              "$ref": "#/components/schemas/ProviderId"
            }
          },
          "popular": {
            "type": "boolean",
            "description": "Shown first in chain pickers."
          },
          "destinationOnly": {
            "type": "boolean",
            "description": "Present (`true`) for chains you can deliver to but not send from, e.g. Hyperliquid (`1337`). Hide them from source pickers."
          }
        }
      },
      "Token": {
        "type": "object",
        "description": "A token (`TokenInfo`).",
        "required": [
          "chainId",
          "address",
          "symbol",
          "name",
          "decimals",
          "verified"
        ],
        "properties": {
          "chainId": {
            "type": "integer"
          },
          "address": {
            "type": "string",
            "description": "Token address or mint. EVM addresses are checksummed; the native coin is\n`0x0000000000000000000000000000000000000000`. On Solana, native SOL is the wrapped-SOL\nmint `So11111111111111111111111111111111111111112`.\n"
          },
          "symbol": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "decimals": {
            "type": "integer"
          },
          "logoURI": {
            "type": "string",
            "format": "uri"
          },
          "priceUsd": {
            "type": "number",
            "description": "USD price when known (token list, refreshed hourly)."
          },
          "verified": {
            "type": "boolean",
            "description": "On a provider list or LayerHop's curated list. `false` for tokens read on-chain only."
          },
          "popular": {
            "type": "boolean",
            "description": "Stables, wrapped native and majors on that chain."
          }
        }
      },
      "Balance": {
        "description": "A non-zero wallet balance.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Token"
          },
          {
            "type": "object",
            "required": [
              "amount"
            ],
            "properties": {
              "amount": {
                "type": "string",
                "pattern": "^[0-9]+$",
                "description": "Balance in base units (integer string, > 0)."
              },
              "valueUsd": {
                "type": "number",
                "description": "`amount` × `priceUsd`, when the price is known."
              }
            }
          }
        ]
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "ok",
          "providers"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProviderId"
            }
          }
        }
      },
      "ChainsResponse": {
        "type": "object",
        "required": [
          "chains"
        ],
        "properties": {
          "chains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Chain"
            }
          }
        }
      },
      "TokensResponse": {
        "type": "object",
        "required": [
          "tokens",
          "nextCursor"
        ],
        "properties": {
          "tokens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Token"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` to get the next page; `null` on the last page."
          }
        }
      },
      "TokenLookupResponse": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "$ref": "#/components/schemas/Token"
          }
        }
      },
      "PricesResponse": {
        "type": "object",
        "required": [
          "prices"
        ],
        "properties": {
          "prices": {
            "type": "object",
            "description": "USD price per requested `chainId:address` id. Ids without a price are omitted.",
            "additionalProperties": {
              "type": "number"
            }
          }
        }
      },
      "BalancesResponse": {
        "type": "object",
        "required": [
          "address",
          "vm",
          "balances",
          "totalUsd",
          "errors"
        ],
        "properties": {
          "address": {
            "type": "string",
            "description": "The wallet (EVM addresses checksummed)."
          },
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "balances": {
            "type": "array",
            "description": "Non-zero balances, highest USD value first.",
            "items": {
              "$ref": "#/components/schemas/Balance"
            }
          },
          "totalUsd": {
            "type": "number",
            "description": "Sum of `valueUsd`."
          },
          "errors": {
            "type": "array",
            "description": "Chains that could not be read; the other chains are still returned.",
            "items": {
              "type": "object",
              "required": [
                "chainId",
                "message"
              ],
              "properties": {
                "chainId": {
                  "type": "integer"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "FeeBreakdown": {
        "type": "object",
        "required": [
          "ourFeeBps"
        ],
        "properties": {
          "ourFeeBps": {
            "type": "integer",
            "description": "LayerHop's fee in bps of the input amount actually applied to this quote. Can be lower\nthan the channel fee (or 0) when a provider cannot carry it.\n"
          },
          "providerFeeUsd": {
            "type": "number",
            "description": "Provider / protocol fees in USD, when the provider reports them."
          },
          "gasUsd": {
            "type": "number",
            "description": "Estimated network gas in USD, when known."
          },
          "integratorFeeBps": {
            "type": "integer",
            "description": "Partner fee in bps of the input amount, on top of `ourFeeBps`. Present only when the request\nselected a registered partner. When the provider could not apply the fee, both parts are 0;\nwhen it applied less than requested, the applied fee is split pro rata.\n"
          },
          "integrator": {
            "type": "string",
            "description": "Partner id earning `integratorFeeBps`. Present only with a partner."
          }
        }
      },
      "Quote": {
        "type": "object",
        "required": [
          "quoteId",
          "provider",
          "dstAmount",
          "dstAmountMin",
          "estimatedSeconds",
          "fees",
          "expiresAt"
        ],
        "properties": {
          "quoteId": {
            "type": "string",
            "pattern": "^q_",
            "description": "Pass to `POST /v1/orders`. Test-mode ids start with `q_test_`."
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Expected output in base units of the destination token, after all fees."
          },
          "dstAmountMin": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Minimum output after slippage."
          },
          "estimatedSeconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Estimated time until funds arrive."
          },
          "fees": {
            "$ref": "#/components/schemas/FeeBreakdown"
          },
          "expiresAt": {
            "type": "integer",
            "description": "Unix seconds. Build the order before this time."
          },
          "gasOnArrival": {
            "$ref": "#/components/schemas/GasOnArrival"
          },
          "srcAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "What `sender` pays in base units of the source token, fees included. Present on destination-call quotes (exact output); otherwise the input is the request's `amount`."
          },
          "calls": {
            "$ref": "#/components/schemas/DestinationCallsPlan"
          }
        }
      },
      "QuoteRequestBody": {
        "type": "object",
        "description": "`POST /v1/quote` body. The fields of `GET /v1/quote` (chains may also be numbers), plus\ndestination calls. Send `amount` for a plain quote, or `dstAmount` with `calls` or `action`.\n",
        "required": [
          "srcChain",
          "srcToken",
          "dstChain",
          "dstToken",
          "sender",
          "recipient"
        ],
        "properties": {
          "srcChain": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ],
            "description": "Source chain id or slug."
          },
          "srcToken": {
            "type": "string",
            "description": "Source token address, curated symbol or native symbol."
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Input amount in base units of `srcToken`. Not allowed with `calls` / `action`."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Exact amount of `dstToken` the destination calls receive, in base units. Required with `calls` / `action`."
          },
          "dstChain": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ],
            "description": "Destination chain id or slug. EVM only with calls."
          },
          "dstToken": {
            "type": "string",
            "description": "Destination token address, curated symbol or native symbol."
          },
          "sender": {
            "type": "string",
            "minLength": 1,
            "description": "Address that signs and pays on the source chain (receives refunds)."
          },
          "recipient": {
            "type": "string",
            "minLength": 1,
            "description": "Who the output (or what the calls produce) is for. An EVM address with calls."
          },
          "slippageBps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000,
            "default": 50
          },
          "channel": {
            "$ref": "#/components/schemas/FeeChannel"
          },
          "integrator": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,32}$",
            "description": "Partner id, as for `GET /v1/quote`."
          },
          "integratorFeeBps": {
            "type": "integer",
            "minimum": 0,
            "description": "Partner fee override, as for `GET /v1/quote`."
          },
          "gasOnArrival": {
            "type": "boolean",
            "description": "As for `GET /v1/quote`. Not allowed with calls."
          },
          "gasOnArrivalUsd": {
            "type": "number",
            "minimum": 0.5,
            "maximum": 20,
            "description": "As for `GET /v1/quote`. Not allowed with calls."
          },
          "calls": {
            "type": "array",
            "minItems": 1,
            "maxItems": 8,
            "description": "Destination calls, run in order by the provider's executor with the output. At most 8, at\nmost 10,000 bytes of calldata each and 24,000 in total. Not with `action`.\n",
            "items": {
              "$ref": "#/components/schemas/DestinationCall"
            }
          },
          "action": {
            "$ref": "#/components/schemas/DestinationAction"
          }
        }
      },
      "DestinationCall": {
        "type": "object",
        "description": "One contract call on the destination chain. `msg.sender` is the provider's executor, not the user.",
        "required": [
          "to",
          "data"
        ],
        "properties": {
          "to": {
            "type": "string",
            "pattern": "^0x[0-9a-fA-F]{40}$",
            "description": "Target contract. Not the zero address, a precompile or Permit2."
          },
          "data": {
            "type": "string",
            "pattern": "^0x([0-9a-fA-F]{2})*$",
            "description": "ABI-encoded calldata. `transferFrom`, `safeTransferFrom`, `safeBatchTransferFrom` and `permit` are rejected."
          },
          "value": {
            "type": "string",
            "pattern": "^\\d+$",
            "default": "0",
            "description": "Native coin to send with the call, in wei. Only when `dstToken` is the native coin; the values together must not exceed `dstAmount`."
          }
        }
      },
      "DestinationAction": {
        "type": "object",
        "description": "A preset that builds the calls server-side. `aave-v3-supply`: `approve(pool, dstAmount)` on\n`dstToken`, then `supply(dstToken, dstAmount, recipient, 0)` on the chain's Aave v3 Pool, so the\naTokens go to `recipient`. Chains: Ethereum, Optimism, BNB Chain, Polygon, Base, Arbitrum.\n`dstToken` must be an ERC-20 that Aave lists on that chain (else `CALLS_REVERTED`).\n",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "aave-v3-supply"
            ]
          }
        }
      },
      "DestinationCallsPlan": {
        "type": "object",
        "description": "The destination calls of a quote, as the provider committed to them, and their simulation.",
        "required": [
          "items",
          "executor",
          "executed"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DestinationCall"
            },
            "description": "The calls (normalized to lowercase hex)."
          },
          "executor": {
            "type": "string",
            "description": "Contract that receives the output and makes the calls: their `msg.sender`."
          },
          "executed": {
            "type": "boolean",
            "description": "The provider runs the calls as part of the fill. Always true: quotes that can't are dropped."
          },
          "simulation": {
            "type": "object",
            "description": "Result of the mandatory pre-quote simulation on the destination chain.",
            "required": [
              "ok",
              "gasUsed"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "gasUsed": {
                "type": "string",
                "description": "Gas the calls used together (decimal string)."
              },
              "leftover": {
                "type": "string",
                "description": "ERC-20 output left in the executor after the calls (decimal string). Anything above 0 is not delivered to anyone you control; spend exactly `dstAmount`."
              }
            }
          }
        }
      },
      "GasOnArrival": {
        "type": "object",
        "description": "Native gas the route delivers to the recipient on top of `dstAmount` (present only when gas\non arrival was requested and this provider includes it). Its cost is already taken out of\n`dstAmount`.\n",
        "required": [
          "amount",
          "token",
          "symbol",
          "decimals"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Base units of the destination chain's native token."
          },
          "token": {
            "type": "string",
            "description": "Native token address on the destination chain (`0x000…000`)."
          },
          "symbol": {
            "type": "string",
            "example": "ETH"
          },
          "decimals": {
            "type": "integer",
            "example": 18
          },
          "usd": {
            "type": "number",
            "description": "USD value at quote time."
          }
        }
      },
      "ProviderError": {
        "type": "object",
        "description": "A provider that failed while the request as a whole succeeded.",
        "required": [
          "provider",
          "code",
          "message"
        ],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "QuoteResponse": {
        "type": "object",
        "required": [
          "best",
          "quotes",
          "errors"
        ],
        "properties": {
          "best": {
            "$ref": "#/components/schemas/Quote",
            "description": "Same object as `quotes[0]`."
          },
          "quotes": {
            "type": "array",
            "minItems": 1,
            "description": "Every successful quote, best for the user first.",
            "items": {
              "$ref": "#/components/schemas/Quote"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProviderError"
            }
          },
          "livemode": {
            "type": "boolean",
            "description": "false in test mode (an `lh_test_` key): sandbox data, never a real provider or real funds."
          }
        }
      },
      "Approval": {
        "type": "object",
        "description": "An ERC-20 `approve(spender, amount)` on `token` that must be mined before the main transaction.",
        "required": [
          "token",
          "spender",
          "amount"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "ERC-20 contract to call `approve` on."
          },
          "spender": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Base units."
          }
        }
      },
      "EvmTx": {
        "type": "object",
        "required": [
          "vm",
          "chainId",
          "to",
          "data",
          "value"
        ],
        "properties": {
          "vm": {
            "type": "string",
            "const": "evm"
          },
          "chainId": {
            "type": "integer"
          },
          "to": {
            "type": "string"
          },
          "data": {
            "type": "string",
            "description": "Hex calldata."
          },
          "value": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Native value in wei."
          },
          "approval": {
            "$ref": "#/components/schemas/Approval"
          },
          "extraTxs": {
            "type": "array",
            "description": "Further calls to send from the same wallet after the main transaction, in order. Today only\nsame-token checkout payments carry one: LayerHop's fee transfer (an ERC-20 `transfer` to\nLayerHop's fee wallet). Wallets with EIP-5792 `wallet_sendCalls` may batch them with the main\ncall. Report the main transaction's hash.\n",
            "items": {
              "$ref": "#/components/schemas/EvmCall"
            }
          },
          "sandbox": {
            "type": "boolean",
            "const": true,
            "description": "Test mode only: a placeholder that moves no funds. Never broadcast it."
          }
        }
      },
      "TrafficSplit": {
        "type": "object",
        "required": [
          "total",
          "withKey",
          "withoutKey"
        ],
        "properties": {
          "total": {
            "type": "integer"
          },
          "withKey": {
            "type": "integer"
          },
          "withoutKey": {
            "type": "integer"
          }
        }
      },
      "TrafficDay": {
        "type": "object",
        "required": [
          "date",
          "requests",
          "uniqueClients",
          "quotes",
          "ordersBuilt"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "UTC day."
          },
          "requests": {
            "$ref": "#/components/schemas/TrafficSplit"
          },
          "uniqueClients": {
            "$ref": "#/components/schemas/TrafficSplit"
          },
          "quotes": {
            "$ref": "#/components/schemas/TrafficSplit"
          },
          "ordersBuilt": {
            "$ref": "#/components/schemas/TrafficSplit"
          }
        }
      },
      "EvmCall": {
        "type": "object",
        "required": [
          "to",
          "data",
          "value"
        ],
        "properties": {
          "to": {
            "type": "string"
          },
          "data": {
            "type": "string",
            "description": "Hex calldata."
          },
          "value": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Native value in wei."
          }
        }
      },
      "SvmTx": {
        "type": "object",
        "required": [
          "vm",
          "serializedTx"
        ],
        "properties": {
          "vm": {
            "type": "string",
            "const": "svm"
          },
          "serializedTx": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "Base64 serialized Solana `VersionedTransaction`, for the user's wallet to sign."
          },
          "submitViaApi": {
            "type": "boolean",
            "description": "When true the wallet must only sign; send the signed transaction to\n`POST /v1/orders/submit` (limit orders: `POST /v1/limit-orders/{id}/submit`). Plain RPC will not land it.\n"
          },
          "sandbox": {
            "type": "boolean",
            "const": true,
            "description": "Test mode only: a placeholder (zero blockhash, memo only) that can never land. Never broadcast it."
          }
        }
      },
      "BuiltTx": {
        "description": "The transaction for the user's wallet, discriminated by `vm`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/EvmTx"
          },
          {
            "$ref": "#/components/schemas/SvmTx"
          }
        ],
        "discriminator": {
          "propertyName": "vm",
          "mapping": {
            "evm": "#/components/schemas/EvmTx",
            "svm": "#/components/schemas/SvmTx"
          }
        }
      },
      "BuildOrderRequest": {
        "type": "object",
        "required": [
          "quoteId"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          }
        }
      },
      "BuildOrderResponse": {
        "type": "object",
        "required": [
          "quoteId",
          "provider",
          "tx"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "tx": {
            "$ref": "#/components/schemas/BuiltTx"
          },
          "livemode": {
            "type": "boolean",
            "description": "false in test mode (an `lh_test_` key): sandbox data, never a real provider or real funds."
          }
        }
      },
      "SubmitOrderRequest": {
        "type": "object",
        "required": [
          "quoteId",
          "signedTransaction"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "signedTransaction": {
            "type": "string",
            "minLength": 1,
            "contentEncoding": "base64",
            "description": "The wallet-signed transaction, base64."
          }
        }
      },
      "SubmitOrderResponse": {
        "type": "object",
        "required": [
          "provider",
          "txHash"
        ],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "txHash": {
            "type": "string",
            "description": "Solana transaction signature."
          }
        }
      },
      "OrderState": {
        "type": "string",
        "description": "`pending` in flight · `filled` delivered · `refunded` returned to the sender · `failed` ·\n`unknown` the provider cannot tell (yet), or does not track this kind of order.\n",
        "enum": [
          "pending",
          "filled",
          "refunded",
          "failed",
          "unknown"
        ]
      },
      "OrderStatus": {
        "type": "object",
        "required": [
          "provider",
          "id",
          "state"
        ],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "id": {
            "type": "string",
            "description": "The id you asked about."
          },
          "state": {
            "$ref": "#/components/schemas/OrderState"
          },
          "srcTxHash": {
            "type": "string"
          },
          "dstTxHash": {
            "type": "string"
          }
        }
      },
      "Partner": {
        "type": "object",
        "required": [
          "id",
          "name",
          "feeBps",
          "maxFeeBps",
          "hasApiKey"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,32}$"
          },
          "name": {
            "type": "string"
          },
          "feeBps": {
            "type": "integer",
            "description": "Default partner fee in bps."
          },
          "maxFeeBps": {
            "type": "integer",
            "description": "Highest `integratorFeeBps` an API-key request may ask for."
          },
          "payoutEvm": {
            "type": "string",
            "description": "EVM payout address."
          },
          "payoutSvm": {
            "type": "string",
            "description": "Solana payout address."
          },
          "hasApiKey": {
            "type": "boolean"
          }
        }
      },
      "PartnersResponse": {
        "type": "object",
        "required": [
          "partners"
        ],
        "properties": {
          "partners": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Partner"
            }
          }
        }
      },
      "LedgerEntry": {
        "type": "object",
        "description": "One line of the append-only ledger. `built` entries carry the trade and fee split;\n`submitted` entries link a `quoteId` to the `txHash` returned by `POST /v1/orders/submit`.\n",
        "required": [
          "type",
          "quoteId",
          "partner",
          "provider",
          "createdAt"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "built",
              "submitted"
            ]
          },
          "quoteId": {
            "type": "string"
          },
          "partner": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "srcChainId": {
            "type": "integer"
          },
          "srcToken": {
            "type": "string"
          },
          "dstChainId": {
            "type": "integer"
          },
          "dstToken": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Input amount, base units of `srcToken`."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "ourFeeBps": {
            "type": "integer"
          },
          "integratorFeeBps": {
            "type": "integer"
          },
          "partnerFeeEstimate": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "`amount × integratorFeeBps / 10000`, base units of `srcToken`, rounded down."
          },
          "txHash": {
            "type": "string",
            "description": "Only on `submitted` entries."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LedgerTokenTotal": {
        "type": "object",
        "required": [
          "srcChainId",
          "srcToken",
          "builtCount",
          "submittedCount",
          "partnerFeeEstimate"
        ],
        "properties": {
          "srcChainId": {
            "type": "integer"
          },
          "srcToken": {
            "type": "string"
          },
          "builtCount": {
            "type": "integer",
            "description": "Distinct quotes built (a quote built twice counts once)."
          },
          "submittedCount": {
            "type": "integer"
          },
          "partnerFeeEstimate": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Sum over distinct built quotes, base units of `srcToken`."
          }
        }
      },
      "PartnerLedgerResponse": {
        "type": "object",
        "required": [
          "partner",
          "basis",
          "entries",
          "totals"
        ],
        "properties": {
          "partner": {
            "type": "string"
          },
          "basis": {
            "type": "string",
            "const": "built",
            "description": "Entries are built/submitted txs, not proven fills."
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerEntry"
            }
          },
          "totals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerTokenTotal"
            }
          }
        }
      },
      "ReportSubmittedRequest": {
        "type": "object",
        "required": [
          "txHash"
        ],
        "properties": {
          "txHash": {
            "type": "string",
            "description": "Source-chain transaction hash: `0x` + 64 hex for EVM, a base58 signature for Solana."
          }
        }
      },
      "OrderLifecycleStatus": {
        "type": "string",
        "description": "`built` tx returned by `POST /v1/orders` · `submitted` tx hash reported · `pending` in flight ·\n`filled` · `refunded` · `failed` · `expired` built but never submitted within 1 h.\n",
        "enum": [
          "built",
          "submitted",
          "pending",
          "filled",
          "refunded",
          "failed",
          "expired"
        ]
      },
      "ReportSubmittedResponse": {
        "type": "object",
        "required": [
          "quoteId",
          "status"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/OrderLifecycleStatus"
          }
        }
      },
      "OrderSummary": {
        "type": "object",
        "description": "An order built through LayerHop (public fields only).",
        "required": [
          "quoteId",
          "status",
          "provider",
          "channel",
          "srcChainId",
          "srcToken",
          "dstChainId",
          "dstToken",
          "sender",
          "recipient",
          "amount",
          "dstAmount",
          "ourFeeBps",
          "partnerFeeBps",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/OrderLifecycleStatus"
          },
          "statusDetail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Extra detail, e.g. `timeout`."
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "channel": {
            "$ref": "#/components/schemas/FeeChannel"
          },
          "srcChainId": {
            "type": "integer"
          },
          "srcToken": {
            "type": "string"
          },
          "dstChainId": {
            "type": "integer"
          },
          "dstToken": {
            "type": "string"
          },
          "sender": {
            "type": "string",
            "description": "EVM addresses are lowercase."
          },
          "recipient": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Input amount in base units."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Quoted output in base units."
          },
          "ourFeeBps": {
            "type": "integer"
          },
          "partnerFeeBps": {
            "type": "integer"
          },
          "srcTxHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "dstTxHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "livemode": {
            "type": "boolean",
            "description": "false in test mode (an `lh_test_` key): sandbox data, never a real provider or real funds."
          },
          "checkoutSessionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The checkout session this order pays, if any."
          },
          "depositAddressId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The deposit address this order came from, if any (see `POST /v1/deposit-addresses`)."
          },
          "limitOrderId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The limit order this order is a fill of, if any (see `POST /v1/limit-orders`)."
          },
          "refundId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The checkout refund this order sends, if any."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrderList": {
        "type": "object",
        "required": [
          "orders",
          "nextCursor"
        ],
        "properties": {
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderSummary"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `cursor` for the next page; null on the last page."
          }
        }
      },
      "AccountOrder": {
        "description": "`OrderSummary` plus `keyId`, `partnerId` and `partnerFeeEstimate` (input-token base units).",
        "allOf": [
          {
            "$ref": "#/components/schemas/OrderSummary"
          }
        ],
        "type": "object",
        "properties": {
          "keyId": {
            "type": [
              "string",
              "null"
            ]
          },
          "partnerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "partnerFeeEstimate": {
            "type": "string",
            "pattern": "^\\d+$"
          }
        }
      },
      "AccountOrderList": {
        "type": "object",
        "required": [
          "orders",
          "nextCursor"
        ],
        "properties": {
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountOrder"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SimulationError": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "SIMULATION_FAILED",
              "RPC_ERROR"
            ],
            "description": "`SIMULATION_FAILED` the tx would fail · `RPC_ERROR` the simulation could not run."
          },
          "message": {
            "type": "string",
            "description": "Revert reason or RPC error."
          },
          "logs": {
            "type": "array",
            "description": "Solana program logs (last 50 lines).",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SimulationResponse": {
        "type": "object",
        "required": [
          "quoteId",
          "provider",
          "ok",
          "vm",
          "tx"
        ],
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "ok": {
            "type": "boolean",
            "description": "True when what was simulated succeeded."
          },
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "gasEstimate": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "EVM: gas units for what was simulated."
          },
          "computeUnits": {
            "type": "integer",
            "description": "Solana: compute units consumed."
          },
          "needsApproval": {
            "type": "boolean",
            "description": "EVM: the allowance is too low; send `tx.approval` first."
          },
          "simulated": {
            "type": "string",
            "enum": [
              "tx",
              "approval"
            ],
            "description": "EVM: `tx` the swap itself (with an allowance override if needed), `approval` only the approval."
          },
          "error": {
            "$ref": "#/components/schemas/SimulationError"
          },
          "tx": {
            "$ref": "#/components/schemas/BuiltTx"
          },
          "livemode": {
            "type": "boolean",
            "description": "Present (false) in test mode, where nothing is simulated on chain and the result is always ok."
          }
        }
      },
      "NonceRequest": {
        "type": "object",
        "required": [
          "vm",
          "address"
        ],
        "properties": {
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "address": {
            "type": "string",
            "description": "0x address (EVM) or base58 public key (Solana)."
          }
        }
      },
      "NonceResponse": {
        "type": "object",
        "required": [
          "nonce",
          "message",
          "expiresAt"
        ],
        "properties": {
          "nonce": {
            "type": "string"
          },
          "message": {
            "type": "string",
            "description": "Sign exactly this text."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VerifyRequest": {
        "type": "object",
        "required": [
          "vm",
          "message",
          "signature"
        ],
        "properties": {
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "message": {
            "type": "string",
            "description": "The unchanged message from `POST /v1/auth/nonce`."
          },
          "signature": {
            "type": "string",
            "description": "EVM: 0x hex. Solana: base58 or base64 ed25519 signature."
          }
        }
      },
      "Account": {
        "type": "object",
        "required": [
          "id",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^acc_"
          },
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AccountUpdateRequest": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Up to 64 characters."
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          }
        }
      },
      "Wallet": {
        "type": "object",
        "required": [
          "vm",
          "address",
          "createdAt"
        ],
        "properties": {
          "vm": {
            "$ref": "#/components/schemas/Vm"
          },
          "address": {
            "type": "string",
            "description": "EVM addresses are lowercase."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VerifyResponse": {
        "type": "object",
        "required": [
          "account"
        ],
        "properties": {
          "account": {
            "$ref": "#/components/schemas/Account"
          }
        }
      },
      "PartnerStatus": {
        "type": "string",
        "enum": [
          "pending",
          "active",
          "suspended"
        ],
        "description": "Only `active` partners earn fees."
      },
      "PartnerProfile": {
        "type": "object",
        "required": [
          "id",
          "name",
          "feeBps",
          "maxFeeBps",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,32}$",
            "description": "Public label, used as `integrator=<id>`."
          },
          "name": {
            "type": "string"
          },
          "feeBps": {
            "type": "integer",
            "description": "Partner fee in bps, on top of LayerHop's."
          },
          "maxFeeBps": {
            "type": "integer",
            "description": "Set by LayerHop on approval."
          },
          "payoutEvm": {
            "type": [
              "string",
              "null"
            ]
          },
          "payoutSvm": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/PartnerStatus"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MeResponse": {
        "type": "object",
        "required": [
          "account",
          "wallets",
          "partner"
        ],
        "properties": {
          "account": {
            "$ref": "#/components/schemas/Account"
          },
          "wallets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Wallet"
            }
          },
          "partner": {
            "description": "The partner profile, or null.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PartnerProfile"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "OkResponse": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "WalletsResponse": {
        "type": "object",
        "required": [
          "wallets"
        ],
        "properties": {
          "wallets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Wallet"
            }
          }
        }
      },
      "Overview": {
        "type": "object",
        "required": [
          "livemode",
          "from",
          "to",
          "requests",
          "errors",
          "quotes",
          "orders",
          "volume",
          "earnings",
          "activeKeys"
        ],
        "properties": {
          "livemode": {
            "type": "boolean",
            "description": "Which mode the numbers are for (see the `mode` parameter)."
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "requests": {
            "type": "integer",
            "description": "API requests made with the account's keys."
          },
          "errors": {
            "type": "integer",
            "description": "Of those, responses with status >= 400."
          },
          "quotes": {
            "type": "integer",
            "description": "Successful `GET /v1/quote` calls."
          },
          "orders": {
            "type": "object",
            "required": [
              "built",
              "filled",
              "byStatus"
            ],
            "properties": {
              "built": {
                "type": "integer",
                "description": "Orders built (any status)."
              },
              "filled": {
                "type": "integer"
              },
              "byStatus": {
                "type": "object",
                "description": "Order count per status."
              }
            }
          },
          "volume": {
            "type": "array",
            "description": "Filled input volume per source token (base units).",
            "items": {
              "type": "object",
              "properties": {
                "srcChainId": {
                  "type": "integer"
                },
                "srcToken": {
                  "type": "string"
                },
                "orders": {
                  "type": "integer"
                },
                "amount": {
                  "type": "string",
                  "pattern": "^\\d+$"
                }
              }
            }
          },
          "earnings": {
            "type": [
              "object",
              "null"
            ],
            "description": "For partners, 30-day fee estimates per token (same shape as `EarningsByToken`, flattened)."
          },
          "activeKeys": {
            "type": "integer"
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "required": [
          "id",
          "name",
          "prefix",
          "rateLimitRpm",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^key_"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string",
            "description": "First 12 characters of the key, for recognising it."
          },
          "rateLimitRpm": {
            "type": "integer",
            "description": "Requests per minute (token bucket)."
          },
          "livemode": {
            "type": "boolean",
            "description": "false for an `lh_test_` (test mode) key."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Updated at most once a minute."
          },
          "revokedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ApiKeyList": {
        "type": "object",
        "required": [
          "keys"
        ],
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          }
        }
      },
      "ApiKeyNameRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "1–64 characters."
          }
        }
      },
      "ApiKeyCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "1–64 characters."
          },
          "mode": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "default": "live",
            "description": "`test` creates an `lh_test_` sandbox key."
          }
        }
      },
      "ApiKeyCreated": {
        "type": "object",
        "required": [
          "key",
          "secret"
        ],
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ApiKey"
          },
          "secret": {
            "type": "string",
            "pattern": "^lh_(live|test)_[0-9A-Za-z]{32}$",
            "description": "Send as `x-api-key`. Shown once."
          }
        }
      },
      "ApiKeyResponse": {
        "type": "object",
        "required": [
          "key"
        ],
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ApiKey"
          }
        }
      },
      "UsagePoint": {
        "type": "object",
        "required": [
          "ts",
          "requests",
          "errors",
          "quotes",
          "orders"
        ],
        "properties": {
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "Bucket start (UTC)."
          },
          "requests": {
            "type": "integer"
          },
          "errors": {
            "type": "integer"
          },
          "quotes": {
            "type": "integer"
          },
          "orders": {
            "type": "integer",
            "description": "Successful `POST /v1/orders` calls."
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "required": [
          "bucket",
          "from",
          "to",
          "series"
        ],
        "properties": {
          "bucket": {
            "type": "string",
            "enum": [
              "hour",
              "day"
            ]
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsagePoint"
            }
          }
        }
      },
      "RequestLog": {
        "type": "object",
        "required": [
          "id",
          "ts",
          "requestId",
          "method",
          "path",
          "status",
          "latencyMs"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "ts": {
            "type": "string",
            "format": "date-time"
          },
          "keyId": {
            "type": [
              "string",
              "null"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string",
            "description": "Route pattern, e.g. `/v1/orders/:provider/:id`."
          },
          "query": {
            "type": [
              "object",
              "null"
            ],
            "description": "Query parameters (secrets redacted)."
          },
          "status": {
            "type": "integer"
          },
          "latencyMs": {
            "type": "integer"
          },
          "errorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "description": "Best provider for quotes, the provider for orders."
          },
          "livemode": {
            "type": "boolean"
          }
        }
      },
      "RequestLogList": {
        "type": "object",
        "required": [
          "logs",
          "nextCursor"
        ],
        "properties": {
          "logs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RequestLog"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "WebhookEventType": {
        "type": "string",
        "description": "Events you can subscribe to (`webhook.test` is always delivered to the endpoint it was sent to).\nOrder events carry `data.order`; checkout events carry `data.session` (a `CheckoutSession`);\n`checkout.session.refunded` adds `data.refund` (a `Refund`); `invoice.sent` carries\n`data.invoice` (an `Invoice`) and `invoice.paid` carries `data.invoice` and `data.session`.\n`subscription.created` and `subscription.canceled` carry `data.subscription` (a\n`Subscription`); `subscription.renewed` (a period's invoice was issued and emailed) and\n`subscription.past_due` add `data.invoice`.\n`limit_order.*` events carry `data.limitOrder` (a `LimitOrder`); `limit_order.filled` adds\n`data.fill` (the fill's `OrderSummary`) and is sent for every fill, partial ones included.\n",
        "enum": [
          "order.submitted",
          "order.filled",
          "order.refunded",
          "order.failed",
          "checkout.session.processing",
          "checkout.session.completed",
          "checkout.session.payment_failed",
          "checkout.session.expired",
          "checkout.session.refunded",
          "invoice.sent",
          "invoice.paid",
          "subscription.created",
          "subscription.renewed",
          "subscription.past_due",
          "subscription.canceled",
          "limit_order.opened",
          "limit_order.filled",
          "limit_order.cancelled",
          "limit_order.expired",
          "limit_order.failed"
        ]
      },
      "Webhook": {
        "type": "object",
        "required": [
          "id",
          "url",
          "events",
          "active",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^whe_"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "description": "Empty = every event.",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "active": {
            "type": "boolean"
          },
          "livemode": {
            "type": "boolean",
            "description": "Test endpoints receive only test-mode events, live endpoints only live ones."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookList": {
        "type": "object",
        "required": [
          "webhooks"
        ],
        "properties": {
          "webhooks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          }
        }
      },
      "WebhookCreateRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public https URL."
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "default": "live",
            "description": "`test` endpoints receive only test-mode events. Fixed after creation."
          }
        }
      },
      "WebhookUpdateRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "WebhookCreated": {
        "type": "object",
        "required": [
          "webhook",
          "secret"
        ],
        "properties": {
          "webhook": {
            "$ref": "#/components/schemas/Webhook"
          },
          "secret": {
            "type": "string",
            "pattern": "^whsec_",
            "description": "HMAC-SHA256 signing secret. Shown once."
          }
        }
      },
      "WebhookResponse": {
        "type": "object",
        "required": [
          "webhook"
        ],
        "properties": {
          "webhook": {
            "$ref": "#/components/schemas/Webhook"
          }
        }
      },
      "WebhookTestResponse": {
        "type": "object",
        "required": [
          "eventId",
          "deliveryId"
        ],
        "properties": {
          "eventId": {
            "type": "string",
            "pattern": "^evt_"
          },
          "deliveryId": {
            "type": "string",
            "pattern": "^whd_"
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "required": [
          "id",
          "endpointId",
          "eventId",
          "attempt",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^whd_"
          },
          "endpointId": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventType": {
            "type": "string",
            "description": "Event type, e.g. `order.filled` (list endpoint only)."
          },
          "attempt": {
            "type": "integer",
            "description": "Attempts made so far."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed"
            ]
          },
          "responseCode": {
            "type": [
              "integer",
              "null"
            ]
          },
          "responseSnippet": {
            "type": [
              "string",
              "null"
            ],
            "description": "First 500 characters of the response body."
          },
          "durationMs": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Last attempt, request start to response or error."
          },
          "nextAttemptAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "WebhookDeliveryList": {
        "type": "object",
        "required": [
          "deliveries",
          "nextCursor"
        ],
        "properties": {
          "deliveries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "WebhookDeliveryResponse": {
        "type": "object",
        "required": [
          "delivery"
        ],
        "properties": {
          "delivery": {
            "$ref": "#/components/schemas/WebhookDelivery"
          }
        }
      },
      "PartnerProfileResponse": {
        "type": "object",
        "required": [
          "partner"
        ],
        "properties": {
          "partner": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PartnerProfile"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "PartnerApplyRequest": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,32}$"
          },
          "name": {
            "type": "string",
            "minLength": 1
          },
          "payoutEvm": {
            "type": "string",
            "description": "EVM payout address. At least one payout address is required."
          },
          "payoutSvm": {
            "type": "string",
            "description": "Solana payout address."
          }
        }
      },
      "PartnerUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "feeBps": {
            "type": "integer",
            "minimum": 0,
            "description": "<= maxFeeBps."
          },
          "payoutEvm": {
            "type": [
              "string",
              "null"
            ]
          },
          "payoutSvm": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "EarningsBucket": {
        "type": "object",
        "required": [
          "orders",
          "partnerFee"
        ],
        "properties": {
          "orders": {
            "type": "integer"
          },
          "partnerFee": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Partner fee estimate in base units of the source token."
          }
        }
      },
      "EarningsByToken": {
        "type": "object",
        "required": [
          "srcChainId",
          "srcToken",
          "filled",
          "unconfirmed"
        ],
        "properties": {
          "srcChainId": {
            "type": "integer"
          },
          "srcToken": {
            "type": "string"
          },
          "filled": {
            "$ref": "#/components/schemas/EarningsBucket"
          },
          "unconfirmed": {
            "$ref": "#/components/schemas/EarningsBucket"
          }
        }
      },
      "EarningsByMonth": {
        "type": "object",
        "required": [
          "month",
          "srcChainId",
          "srcToken",
          "filled",
          "unconfirmed"
        ],
        "properties": {
          "month": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}$"
          },
          "srcChainId": {
            "type": "integer"
          },
          "srcToken": {
            "type": "string"
          },
          "filled": {
            "$ref": "#/components/schemas/EarningsBucket"
          },
          "unconfirmed": {
            "$ref": "#/components/schemas/EarningsBucket"
          }
        }
      },
      "EarningsResponse": {
        "type": "object",
        "required": [
          "partner",
          "from",
          "to",
          "basis",
          "byToken",
          "byMonth"
        ],
        "properties": {
          "partner": {
            "type": [
              "string",
              "null"
            ],
            "description": "Partner id, or null without a profile."
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "basis": {
            "type": "string",
            "const": "estimate"
          },
          "livemode": {
            "type": "boolean"
          },
          "byToken": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EarningsByToken"
            }
          },
          "byMonth": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EarningsByMonth"
            }
          }
        }
      },
      "PartnerBalance": {
        "type": "object",
        "required": [
          "chainId",
          "token",
          "earned",
          "paid",
          "owed",
          "decimals",
          "owedUsd"
        ],
        "properties": {
          "chainId": {
            "type": "integer"
          },
          "token": {
            "type": "string"
          },
          "earned": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Partner fees of filled live orders, base units."
          },
          "paid": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Sum of non-voided payouts, base units."
          },
          "owed": {
            "type": "string",
            "pattern": "^-?\\d+$",
            "description": "`earned` - `paid`; negative when overpaid."
          },
          "decimals": {
            "type": [
              "integer",
              "null"
            ]
          },
          "owedUsd": {
            "type": [
              "number",
              "null"
            ],
            "description": "USD value of `owed` when the price is known."
          }
        }
      },
      "Payout": {
        "type": "object",
        "required": [
          "id",
          "partnerId",
          "chainId",
          "token",
          "amount",
          "toAddress",
          "txHash",
          "note",
          "paidAt",
          "voidedAt",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "`po_…`"
          },
          "partnerId": {
            "type": "string"
          },
          "chainId": {
            "type": "integer"
          },
          "token": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Base units."
          },
          "toAddress": {
            "type": [
              "string",
              "null"
            ]
          },
          "txHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "paidAt": {
            "type": "string",
            "format": "date-time"
          },
          "voidedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PayoutsResponse": {
        "type": "object",
        "required": [
          "partner",
          "balances",
          "payouts"
        ],
        "properties": {
          "partner": {
            "type": [
              "string",
              "null"
            ],
            "description": "Partner id, or null without a profile."
          },
          "balances": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartnerBalance"
            }
          },
          "payouts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Payout"
            }
          }
        }
      },
      "PayoutRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "chainId",
          "token",
          "amount"
        ],
        "properties": {
          "chainId": {
            "type": "integer",
            "minimum": 1
          },
          "token": {
            "type": "string",
            "description": "Token address (EVM) or mint (Solana) that was paid."
          },
          "amount": {
            "type": "string",
            "pattern": "^[1-9]\\d*$",
            "description": "Base units."
          },
          "toAddress": {
            "type": "string"
          },
          "txHash": {
            "type": "string"
          },
          "note": {
            "type": "string",
            "maxLength": 200
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "description": "Defaults to now."
          }
        }
      },
      "PayoutResponse": {
        "type": "object",
        "required": [
          "payout"
        ],
        "properties": {
          "payout": {
            "$ref": "#/components/schemas/Payout"
          }
        }
      },
      "ApproveRequest": {
        "type": "object",
        "required": [
          "maxFeeBps"
        ],
        "properties": {
          "maxFeeBps": {
            "type": "integer",
            "minimum": 0,
            "description": "<= MAX_TOTAL_FEE_BPS."
          }
        }
      },
      "AdminPartnerResponse": {
        "type": "object",
        "required": [
          "partner"
        ],
        "properties": {
          "partner": {
            "type": "object",
            "description": "The partner row (includes `accountId`)."
          }
        }
      },
      "RateLimitRequest": {
        "type": "object",
        "required": [
          "rateLimitRpm"
        ],
        "properties": {
          "rateLimitRpm": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          }
        }
      },
      "AdminKeyResponse": {
        "type": "object",
        "required": [
          "key"
        ],
        "properties": {
          "key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "accountId": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "prefix": {
                "type": "string"
              },
              "rateLimitRpm": {
                "type": "integer"
              }
            }
          }
        }
      },
      "CheckoutStatus": {
        "type": "string",
        "description": "`open` (waiting for payment), `processing` (a payment was reported and is being tracked),\n`paid` (delivery to the recipient verified on chain), `expired`, `needs_review` (the payment\nfinished but the delivery could not be verified; contact support).\n",
        "enum": [
          "open",
          "processing",
          "paid",
          "expired",
          "needs_review"
        ]
      },
      "CheckoutSessionCreateRequest": {
        "type": "object",
        "required": [
          "amount",
          "settleChain",
          "settleToken",
          "recipient"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Amount due in base units of the settlement token (49 USDC = `49000000`)."
          },
          "settleChain": {
            "type": "string",
            "description": "Settlement chain id or slug: ethereum, arbitrum, base, optimism, bsc, polygon or solana."
          },
          "settleToken": {
            "type": "string",
            "description": "`USDC` or `USDT` (or its address) on that chain."
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address on the settlement chain."
          },
          "merchantName": {
            "type": "string",
            "maxLength": 64,
            "description": "Shown to the payer. Defaults to nothing."
          },
          "description": {
            "type": "string",
            "maxLength": 280,
            "description": "Shown to the payer, e.g. the product."
          },
          "reference": {
            "type": "string",
            "maxLength": 128,
            "description": "Your own order id. Never shown to the payer."
          },
          "metadata": {
            "type": "object",
            "description": "Up to 20 string values for your records. Never shown to the payer."
          },
          "successUrl": {
            "type": "string",
            "format": "uri",
            "description": "Where the hosted page sends the payer after paying (`?session_id=` is appended)."
          },
          "cancelUrl": {
            "type": "string",
            "format": "uri",
            "description": "Where the payer goes on Cancel."
          },
          "expiresInMinutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 10080,
            "default": 60
          }
        }
      },
      "CheckoutSettlement": {
        "type": "object",
        "required": [
          "chainId",
          "token",
          "symbol",
          "decimals"
        ],
        "properties": {
          "chainId": {
            "type": "integer"
          },
          "token": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "decimals": {
            "type": "integer"
          }
        }
      },
      "CheckoutPayment": {
        "type": "object",
        "description": "The current (or final) payment attempt.",
        "properties": {
          "quoteId": {
            "type": "string"
          },
          "payer": {
            "type": [
              "string",
              "null"
            ]
          },
          "srcChainId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "srcToken": {
            "type": [
              "string",
              "null"
            ]
          },
          "srcAmount": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the payer sent, in base units of `srcToken`."
          },
          "srcTxHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "dstTxHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "The verified delivery transaction once paid."
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "CheckoutSession": {
        "type": "object",
        "required": [
          "id",
          "object",
          "livemode",
          "status",
          "amount",
          "settlement",
          "recipient",
          "url",
          "expiresAt",
          "payment",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^cs_"
          },
          "object": {
            "type": "string",
            "const": "checkout.session"
          },
          "livemode": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/CheckoutStatus"
          },
          "statusDetail": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "settlement": {
            "$ref": "#/components/schemas/CheckoutSettlement"
          },
          "recipient": {
            "type": "string"
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The hosted checkout page."
          },
          "productId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The product the session was started from."
          },
          "invoiceId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The invoice the session pays."
          },
          "refundedAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Sum of completed refunds in base units of the settlement token (`0` when none)."
          },
          "successUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "cancelUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "payment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CheckoutPayment"
              },
              {
                "type": "null"
              }
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only with your API key."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "description": "Only with your API key."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CheckoutSessionList": {
        "type": "object",
        "required": [
          "sessions",
          "nextCursor"
        ],
        "properties": {
          "sessions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckoutSession"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CheckoutQuoteRequest": {
        "type": "object",
        "required": [
          "srcChain",
          "srcToken",
          "sender"
        ],
        "properties": {
          "srcChain": {
            "type": "string",
            "description": "The chain the payer pays from (id or slug)."
          },
          "srcToken": {
            "type": "string",
            "description": "Token address / mint, curated symbol or native symbol."
          },
          "sender": {
            "type": "string",
            "description": "The payer's address on `srcChain`."
          },
          "slippageBps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 50
          }
        }
      },
      "CheckoutQuote": {
        "type": "object",
        "required": [
          "quoteId",
          "provider",
          "srcAmount",
          "dstAmount",
          "dstAmountMin",
          "estimatedSeconds",
          "fees",
          "expiresAt"
        ],
        "properties": {
          "quoteId": {
            "type": "string",
            "description": "Pass to `POST /v1/orders`."
          },
          "provider": {
            "$ref": "#/components/schemas/ProviderId"
          },
          "srcAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "What the payer sends, base units of `srcToken`."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "dstAmountMin": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Guaranteed delivery to the recipient; always >= the amount due."
          },
          "estimatedSeconds": {
            "type": "integer"
          },
          "fees": {
            "$ref": "#/components/schemas/FeeBreakdown"
          },
          "expiresAt": {
            "type": "integer"
          }
        }
      },
      "CheckoutQuoteResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "livemode",
          "amountDue",
          "best",
          "quotes",
          "errors"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "livemode": {
            "type": "boolean"
          },
          "amountDue": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "best": {
            "$ref": "#/components/schemas/CheckoutQuote"
          },
          "quotes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CheckoutQuote"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProviderError"
            }
          }
        }
      },
      "CheckoutProductCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "amount",
          "settleChain",
          "settleToken",
          "recipient"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 280
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Price in base units of the settlement token."
          },
          "settleChain": {
            "type": "string"
          },
          "settleToken": {
            "type": "string",
            "description": "`USDC` or `USDT` (or its address)."
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address on the settlement chain."
          },
          "successUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "cancelUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "expiresInMinutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 10080,
            "default": 60,
            "description": "Lifetime of each session started from the product."
          },
          "allowedOrigins": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "https origins allowed to start sessions from a browser; empty = any."
          },
          "active": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "CheckoutProduct": {
        "type": "object",
        "required": [
          "id",
          "object",
          "livemode",
          "active",
          "name",
          "amount",
          "settlement",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^prod_"
          },
          "object": {
            "type": "string",
            "const": "checkout.product"
          },
          "livemode": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "settlement": {
            "$ref": "#/components/schemas/CheckoutSettlement"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "`https://layerhop.com/buy/{id}`: starts a session and opens the payment page."
          },
          "recipient": {
            "type": "string",
            "description": "Owner only."
          },
          "successUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owner only."
          },
          "cancelUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owner only."
          },
          "expiresInMinutes": {
            "type": "integer",
            "description": "Owner only."
          },
          "allowedOrigins": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Owner only."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InvoiceStatus": {
        "type": "string",
        "description": "`draft` (editable, invisible to the customer), `open` (sent, waiting for payment), `paid`\n(its checkout session was paid), `void` (cancelled).\n",
        "enum": [
          "draft",
          "open",
          "paid",
          "void"
        ]
      },
      "InvoiceLineItem": {
        "type": "object",
        "required": [
          "description",
          "quantity",
          "unitAmount"
        ],
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          },
          "unitAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Price of one unit in base units of the settlement token."
          }
        }
      },
      "InvoiceCreateRequest": {
        "type": "object",
        "required": [
          "lineItems",
          "settleChain",
          "settleToken",
          "recipient"
        ],
        "properties": {
          "customerEmail": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "maxLength": 254,
            "description": "Where the invoice and the receipt are emailed. Without it, share the hosted `url` yourself."
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64,
            "description": "Shown on the invoice and in emails."
          },
          "memo": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "description": "A note to the customer."
          },
          "lineItems": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItem"
            }
          },
          "settleChain": {
            "type": "string",
            "description": "Settlement chain id or slug: ethereum, arbitrum, base, optimism, bsc, polygon or solana."
          },
          "settleToken": {
            "type": "string",
            "description": "`USDC` or `USDT` (or its address) on that chain."
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address on the settlement chain."
          },
          "dueAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Due date: `YYYY-MM-DD` (end of that day, UTC) or an ISO 8601 timestamp. Informational; the invoice stays payable."
          },
          "send": {
            "type": "boolean",
            "default": false,
            "description": "Finalize and email it right away (as `POST /v1/invoices/{id}/send`)."
          }
        }
      },
      "InvoiceUpdateRequest": {
        "type": "object",
        "description": "Any `InvoiceCreateRequest` field except `send`; all optional. Drafts only.",
        "properties": {
          "customerEmail": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "memo": {
            "type": [
              "string",
              "null"
            ]
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItem"
            }
          },
          "settleChain": {
            "type": "string"
          },
          "settleToken": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          },
          "dueAt": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PublicInvoice": {
        "type": "object",
        "description": "The customer's view of an invoice.",
        "required": [
          "id",
          "object",
          "livemode",
          "number",
          "status",
          "lineItems",
          "amount",
          "settlement",
          "url",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^inv_"
          },
          "object": {
            "type": "string",
            "const": "invoice"
          },
          "livemode": {
            "type": "boolean"
          },
          "number": {
            "type": "string",
            "description": "Sequential per account and mode: `INV-0001`, `INV-0002`, …"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "memo": {
            "type": [
              "string",
              "null"
            ]
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItem"
            }
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Total: the sum of `quantity × unitAmount`, in base units of the settlement token."
          },
          "settlement": {
            "$ref": "#/components/schemas/CheckoutSettlement"
          },
          "dueAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The hosted invoice page, `https://layerhop.com/invoice/{id}`."
          },
          "receiptUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The PDF receipt once `paid`."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Invoice": {
        "type": "object",
        "description": "An invoice as its owner sees it.",
        "required": [
          "id",
          "object",
          "livemode",
          "number",
          "status",
          "lineItems",
          "amount",
          "settlement",
          "url",
          "recipient",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^inv_"
          },
          "object": {
            "type": "string",
            "const": "invoice"
          },
          "livemode": {
            "type": "boolean"
          },
          "number": {
            "type": "string",
            "description": "Sequential per account and mode: `INV-0001`, `INV-0002`, …"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "memo": {
            "type": [
              "string",
              "null"
            ]
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItem"
            }
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Total: the sum of `quantity × unitAmount`, in base units of the settlement token."
          },
          "settlement": {
            "$ref": "#/components/schemas/CheckoutSettlement"
          },
          "dueAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paidAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The hosted invoice page, `https://layerhop.com/invoice/{id}`."
          },
          "receiptUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The PDF receipt once `paid`."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "customerEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address."
          },
          "sessionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The latest checkout session started to pay it."
          },
          "subscriptionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The subscription it bills a period of."
          },
          "sentAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "receiptSentAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "voidedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InvoiceList": {
        "type": "object",
        "required": [
          "invoices",
          "nextCursor"
        ],
        "properties": {
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Invoice"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "InvoicePayResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "url"
        ],
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The hosted checkout page."
          }
        }
      },
      "SubscriptionStatus": {
        "type": "string",
        "description": "`active` (billing each period), `past_due` (an invoice is unpaid past its due date; reminders\nare being sent and renewals wait), `paused` (no invoices or reminders), `canceled` (for good:\nby you, or after 7 days past due).\n",
        "enum": [
          "active",
          "past_due",
          "canceled",
          "paused"
        ]
      },
      "SubscriptionInterval": {
        "type": "string",
        "description": "The billing period unit. Months and years keep the start's day of month (clamped to short months).",
        "enum": [
          "day",
          "week",
          "month",
          "year"
        ]
      },
      "SubscriptionCreateRequest": {
        "type": "object",
        "required": [
          "customerEmail",
          "interval"
        ],
        "properties": {
          "customerEmail": {
            "type": "string",
            "format": "email",
            "maxLength": 254,
            "description": "Where each period's invoice and the reminders are emailed."
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 64,
            "description": "Shown on invoices and in emails (default: the product's)."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The invoice line item, e.g. `Pro plan`; each invoice adds the period's dates. Required without `productId` (default: the product's name)."
          },
          "memo": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000,
            "description": "A note on every invoice."
          },
          "productId": {
            "type": "string",
            "description": "Bill this product's price, settlement token and payout address. Not with `amount`, `settleChain`, `settleToken` or `recipient`."
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Price per period in base units of the settlement token."
          },
          "settleChain": {
            "type": "string",
            "description": "Settlement chain id or slug: ethereum, arbitrum, base, optimism, bsc, polygon or solana."
          },
          "settleToken": {
            "type": "string",
            "description": "`USDC` or `USDT` (or its address) on that chain."
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address on the settlement chain."
          },
          "interval": {
            "$ref": "#/components/schemas/SubscriptionInterval"
          },
          "intervalCount": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 1,
            "description": "Bill every `intervalCount` intervals (e.g. 3 + `month` = quarterly)."
          },
          "daysUntilDue": {
            "type": "integer",
            "minimum": 0,
            "maximum": 60,
            "default": 3,
            "description": "Days after an invoice is issued that it is due."
          },
          "startAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the first period starts and its invoice is issued (default: now; at most 366 days ahead)."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 keys, returned in the API and webhooks."
          }
        }
      },
      "SubscriptionUpdateRequest": {
        "type": "object",
        "description": "All optional; changes apply from the next invoice. `null` clears an optional field.",
        "properties": {
          "customerEmail": {
            "type": "string",
            "format": "email"
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": "string"
          },
          "memo": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$"
          },
          "daysUntilDue": {
            "type": "integer",
            "minimum": 0,
            "maximum": 60
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "cancelAtPeriodEnd": {
            "type": "boolean",
            "description": "`true` schedules a cancel at the end of the current period; `false` undoes it."
          }
        }
      },
      "SubscriptionCancelRequest": {
        "type": "object",
        "properties": {
          "atPeriodEnd": {
            "type": "boolean",
            "default": false,
            "description": "Cancel at the end of the current period instead of now."
          }
        }
      },
      "Subscription": {
        "type": "object",
        "required": [
          "id",
          "object",
          "livemode",
          "status",
          "customerEmail",
          "description",
          "amount",
          "settlement",
          "recipient",
          "interval",
          "intervalCount",
          "daysUntilDue",
          "cancelAtPeriodEnd",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^sub_"
          },
          "object": {
            "type": "string",
            "const": "subscription"
          },
          "livemode": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/SubscriptionStatus"
          },
          "customerEmail": {
            "type": "string"
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "merchantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": "string"
          },
          "memo": {
            "type": [
              "string",
              "null"
            ]
          },
          "productId": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Price per period in base units of the settlement token."
          },
          "settlement": {
            "$ref": "#/components/schemas/CheckoutSettlement"
          },
          "recipient": {
            "type": "string",
            "description": "Your payout address."
          },
          "interval": {
            "$ref": "#/components/schemas/SubscriptionInterval"
          },
          "intervalCount": {
            "type": "integer"
          },
          "daysUntilDue": {
            "type": "integer"
          },
          "currentPeriodStart": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Start of the period last invoiced (null before the first invoice)."
          },
          "currentPeriodEnd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "nextInvoiceAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the next invoice is issued (null when paused or canceled)."
          },
          "cancelAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Scheduled cancel (the end of the current period)."
          },
          "cancelAtPeriodEnd": {
            "type": "boolean"
          },
          "canceledAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cancellationReason": {
            "type": [
              "string",
              "null"
            ],
            "description": "`requested` (you canceled) or `unpaid` (past due for 7 days)."
          },
          "pausedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "latestInvoiceId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The invoice of the current period."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "example": {
          "id": "sub_01k7v0c2c4x8q6r0v3b5n7p9d",
          "object": "subscription",
          "livemode": true,
          "status": "active",
          "customerEmail": "ada@example.com",
          "customerName": "Ada Lovelace",
          "merchantName": "Studio Nine",
          "description": "Pro plan",
          "amount": "49000000",
          "settlement": {
            "chainId": 8453,
            "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
            "symbol": "USDC",
            "decimals": 6
          },
          "recipient": "0x2222222222222222222222222222222222222222",
          "interval": "month",
          "intervalCount": 1,
          "daysUntilDue": 3,
          "currentPeriodStart": "2026-10-18T10:00:00.000Z",
          "currentPeriodEnd": "2026-11-18T10:00:00.000Z",
          "nextInvoiceAt": "2026-11-18T10:00:00.000Z",
          "cancelAtPeriodEnd": false,
          "latestInvoiceId": "inv_01k7v0c2c4x8q6r0v3b5n7p9d",
          "metadata": {
            "plan": "pro"
          },
          "createdAt": "2026-10-18T10:00:00.000Z",
          "updatedAt": "2026-10-18T10:00:00.000Z"
        }
      },
      "SubscriptionList": {
        "type": "object",
        "required": [
          "subscriptions",
          "nextCursor"
        ],
        "properties": {
          "subscriptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Subscription"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SubscriptionInvoiceList": {
        "type": "object",
        "required": [
          "invoices"
        ],
        "properties": {
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Invoice"
            }
          }
        }
      },
      "DepositAddressStatus": {
        "type": "string",
        "description": "`active`: deposits are detected and become orders. `disabled`: no longer tracked.",
        "enum": [
          "active",
          "disabled"
        ]
      },
      "DepositAddressCreateRequest": {
        "type": "object",
        "required": [
          "srcChain",
          "srcToken",
          "dstChain",
          "dstToken",
          "recipient",
          "refundTo"
        ],
        "additionalProperties": false,
        "properties": {
          "srcChain": {
            "type": "string",
            "description": "Chain id or slug your user deposits on."
          },
          "srcToken": {
            "type": "string",
            "description": "The token to deposit: address / mint, curated symbol or native symbol. Other tokens sent to the address may be unrecoverable."
          },
          "dstChain": {
            "type": "string",
            "description": "Chain id or slug to deliver on."
          },
          "dstToken": {
            "type": "string",
            "description": "The token to deliver."
          },
          "recipient": {
            "type": "string",
            "description": "Receives `dstToken` on `dstChain`."
          },
          "refundTo": {
            "type": "string",
            "description": "Your user's address on `srcChain` for refunds. Never an exchange (CEX) deposit address."
          },
          "reusable": {
            "type": "boolean",
            "default": true,
            "description": "true: reusable for this route with any amount (each deposit is a separate order). false: one-time, exactly `amount`."
          },
          "amount": {
            "type": "string",
            "pattern": "^[1-9]\\d*$",
            "description": "Base units of `srcToken`. Required when `reusable` is false; otherwise only sizes the `estimate` (default about $100). At least $1."
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "Your reference (e.g. a user id); filter the list by it."
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string key-value pairs."
          },
          "integrator": {
            "type": "string",
            "maxLength": 64,
            "description": "Partner id whose fee applies, as for `GET /v1/quote`."
          },
          "integratorFeeBps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "description": "Partner fee in bps (capped by the partner's maximum), as for `GET /v1/quote`."
          }
        }
      },
      "DepositAddressFees": {
        "type": "object",
        "required": [
          "ourFeeBps",
          "integratorFeeBps"
        ],
        "properties": {
          "ourFeeBps": {
            "type": "integer",
            "description": "LayerHop's fee (the API channel fee)."
          },
          "integratorFeeBps": {
            "type": "integer",
            "description": "The partner fee."
          },
          "integrator": {
            "type": [
              "string",
              "null"
            ],
            "description": "The partner the fee is paid to."
          }
        }
      },
      "DepositAddress": {
        "type": "object",
        "required": [
          "id",
          "object",
          "livemode",
          "status",
          "provider",
          "address",
          "chainId",
          "token",
          "dstChainId",
          "dstToken",
          "recipient",
          "refundTo",
          "reusable",
          "fees",
          "depositCount",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^da_"
          },
          "object": {
            "type": "string",
            "const": "deposit_address"
          },
          "livemode": {
            "type": "boolean",
            "description": "false for a test-mode address (an `lh_test_` key)."
          },
          "status": {
            "$ref": "#/components/schemas/DepositAddressStatus"
          },
          "provider": {
            "type": "string",
            "enum": [
              "relay",
              "sandbox"
            ],
            "description": "Who owns the address: `relay` (live) or `sandbox` (test mode, a fake address)."
          },
          "address": {
            "type": "string",
            "description": "Where your user sends `token` on `chainId`."
          },
          "chainId": {
            "type": "integer",
            "description": "The source chain."
          },
          "token": {
            "type": "string",
            "description": "The token to deposit (address or mint)."
          },
          "dstChainId": {
            "type": "integer"
          },
          "dstToken": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          },
          "refundTo": {
            "type": "string"
          },
          "reusable": {
            "type": "boolean"
          },
          "amount": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d+$",
            "description": "The exact amount a one-time address expects; null when reusable."
          },
          "fees": {
            "$ref": "#/components/schemas/DepositAddressFees"
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "depositCount": {
            "type": "integer",
            "description": "Deposits detected so far."
          },
          "lastDepositAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DepositEstimate": {
        "type": "object",
        "required": [
          "amount",
          "dstAmount",
          "dstAmountMin",
          "estimatedSeconds"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "The deposit amount the estimate is for."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Expected output in base units of `dstToken`."
          },
          "dstAmountMin": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Minimum output after slippage."
          },
          "estimatedSeconds": {
            "type": "integer"
          }
        }
      },
      "DepositAddressCreated": {
        "description": "`DepositAddress` plus an `estimate` (create only).",
        "allOf": [
          {
            "$ref": "#/components/schemas/DepositAddress"
          }
        ],
        "type": "object",
        "required": [
          "estimate"
        ],
        "properties": {
          "estimate": {
            "$ref": "#/components/schemas/DepositEstimate"
          }
        }
      },
      "DepositAddressWithDeposits": {
        "description": "`DepositAddress` plus its 20 most recent `deposits` (orders whose `quoteId` starts with `dep_`), newest first.",
        "allOf": [
          {
            "$ref": "#/components/schemas/DepositAddress"
          }
        ],
        "type": "object",
        "required": [
          "deposits"
        ],
        "properties": {
          "deposits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountOrder"
            }
          }
        }
      },
      "DepositAddressList": {
        "type": "object",
        "required": [
          "depositAddresses",
          "nextCursor"
        ],
        "properties": {
          "depositAddresses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DepositAddress"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SimulateDepositRequest": {
        "type": "object",
        "required": [
          "amount"
        ],
        "additionalProperties": false,
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^[1-9]\\d*$",
            "description": "Base units of the address's token. Ends in `4001` → refunded, `4002` → failed, anything else fills."
          }
        }
      },
      "LimitOrderStatus": {
        "type": "string",
        "description": "`built` (transaction built, not submitted yet), `open` (live on chain, may be partly filled),\n`filled` (fully filled), `cancelled` (cancelled by the wallet; unfilled input returned),\n`expired` (reached `expiresAt`), `failed` (the order transaction never showed up on chain).\n",
        "enum": [
          "built",
          "open",
          "filled",
          "cancelled",
          "expired",
          "failed"
        ]
      },
      "LimitOrderCreateRequest": {
        "type": "object",
        "required": [
          "wallet",
          "srcToken",
          "dstToken",
          "amount",
          "dstAmount"
        ],
        "additionalProperties": false,
        "properties": {
          "chain": {
            "type": "string",
            "default": "solana",
            "description": "Only `solana` (or `7565164`) for now."
          },
          "wallet": {
            "type": "string",
            "description": "The maker wallet (base58). It signs the order and receives the output."
          },
          "srcToken": {
            "type": "string",
            "description": "Token to sell: mint, curated symbol (`USDC`) or `SOL`."
          },
          "dstToken": {
            "type": "string",
            "description": "Token to buy. The fee applies when it is SOL, USDC or USDT."
          },
          "amount": {
            "type": "string",
            "pattern": "^[1-9]\\d*$",
            "description": "Base units of `srcToken` to sell (worth at least $5)."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^[1-9]\\d*$",
            "description": "Minimum base units of `dstToken` for the whole `amount`; sets the limit price."
          },
          "expiresAt": {
            "type": "integer",
            "description": "Unix seconds, at least 60 s from now. Omit for good-till-cancelled."
          },
          "channel": {
            "$ref": "#/components/schemas/FeeChannel"
          },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Up to 20 string key-value pairs."
          },
          "integrator": {
            "type": "string",
            "maxLength": 64,
            "description": "Partner id whose fee applies, as for `GET /v1/quote`."
          },
          "integratorFeeBps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "description": "Partner fee in bps (capped by the partner's maximum), as for `GET /v1/quote`."
          }
        }
      },
      "LimitOrderFees": {
        "type": "object",
        "required": [
          "ourFeeBps",
          "integratorFeeBps"
        ],
        "properties": {
          "ourFeeBps": {
            "type": "integer",
            "description": "LayerHop's fee written into the order (0 when `dstToken` has no fee account)."
          },
          "integratorFeeBps": {
            "type": "integer",
            "description": "The partner fee written into the order."
          },
          "integrator": {
            "type": [
              "string",
              "null"
            ],
            "description": "The partner the fee is paid to."
          }
        }
      },
      "LimitOrder": {
        "type": "object",
        "required": [
          "id",
          "object",
          "livemode",
          "status",
          "provider",
          "chainId",
          "wallet",
          "srcToken",
          "dstToken",
          "amount",
          "dstAmount",
          "fees",
          "providerOrderId",
          "filledAmount",
          "filledDstAmount",
          "fillCount",
          "channel",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^lo_"
          },
          "object": {
            "type": "string",
            "const": "limit_order"
          },
          "livemode": {
            "type": "boolean",
            "description": "false for a test-mode order (an `lh_test_` key)."
          },
          "status": {
            "$ref": "#/components/schemas/LimitOrderStatus"
          },
          "statusDetail": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": "string",
            "enum": [
              "jupiter",
              "sandbox"
            ]
          },
          "chainId": {
            "type": "integer",
            "description": "Always `7565164` (Solana) for now."
          },
          "wallet": {
            "type": "string",
            "description": "The maker wallet."
          },
          "srcToken": {
            "type": "string",
            "description": "Mint sold."
          },
          "dstToken": {
            "type": "string",
            "description": "Mint bought."
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Input in base units."
          },
          "dstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Minimum output for the whole order in base units."
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "fees": {
            "$ref": "#/components/schemas/LimitOrderFees"
          },
          "providerOrderId": {
            "type": "string",
            "description": "The provider's order id (Jupiter: the order account)."
          },
          "filledAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Input filled so far."
          },
          "filledDstAmount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Output received so far."
          },
          "fillCount": {
            "type": "integer"
          },
          "openTxHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "The transaction that opened the order."
          },
          "cancelTxHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cancel transaction, once submitted (the order turns `cancelled` once confirmed)."
          },
          "channel": {
            "$ref": "#/components/schemas/FeeChannel"
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LimitOrderCreated": {
        "description": "`LimitOrder` plus the unsigned `tx` to sign (create only).",
        "allOf": [
          {
            "$ref": "#/components/schemas/LimitOrder"
          }
        ],
        "type": "object",
        "required": [
          "tx"
        ],
        "properties": {
          "tx": {
            "$ref": "#/components/schemas/SvmTx"
          }
        }
      },
      "LimitOrderWithFills": {
        "description": "`LimitOrder` plus its `fills` (orders whose `quoteId` starts with `lof_`), newest first.",
        "allOf": [
          {
            "$ref": "#/components/schemas/LimitOrder"
          }
        ],
        "type": "object",
        "required": [
          "fills"
        ],
        "properties": {
          "fills": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderSummary"
            }
          }
        }
      },
      "LimitOrderList": {
        "type": "object",
        "required": [
          "limitOrders",
          "nextCursor"
        ],
        "properties": {
          "limitOrders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LimitOrder"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "LimitOrderSubmitRequest": {
        "type": "object",
        "required": [
          "signedTransaction"
        ],
        "additionalProperties": false,
        "properties": {
          "signedTransaction": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "The wallet-signed transaction (base64)."
          }
        }
      },
      "LimitOrderSubmitResponse": {
        "type": "object",
        "required": [
          "limitOrder",
          "txHash"
        ],
        "properties": {
          "limitOrder": {
            "$ref": "#/components/schemas/LimitOrder"
          },
          "txHash": {
            "type": "string",
            "description": "The landed transaction's signature."
          }
        }
      },
      "LimitOrderCancelResponse": {
        "type": "object",
        "required": [
          "limitOrder",
          "tx"
        ],
        "properties": {
          "limitOrder": {
            "$ref": "#/components/schemas/LimitOrder"
          },
          "tx": {
            "description": "The unsigned cancel transaction (`submitViaApi: true`), or null when a `built` order was cancelled directly.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SvmTx"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "LimitOrderSimulateRequest": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "additionalProperties": false,
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "fill",
              "partial_fill",
              "expire"
            ],
            "description": "`fill` the rest · `partial_fill` half of the rest · `expire`."
          }
        }
      },
      "RefundStatus": {
        "type": "string",
        "description": "`pending` (created; waiting for you to sign and report the transaction), `submitted` (reported,\nbeing tracked), `completed` (delivered to the payer; added to the session's `refundedAmount`),\n`failed` (the transfer failed; nothing was refunded).\n",
        "enum": [
          "pending",
          "submitted",
          "completed",
          "failed"
        ]
      },
      "RefundCreateRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Base units of the settlement token. Default: everything not yet refunded."
          },
          "reason": {
            "type": "string",
            "maxLength": 500,
            "description": "For your records; included in the webhook."
          },
          "from": {
            "type": "string",
            "description": "The wallet that sends the refund. Default: the session's payout address."
          },
          "to": {
            "type": "string",
            "enum": [
              "original",
              "settlement"
            ],
            "default": "original",
            "description": "`original`: the payer's original chain and token. `settlement`: the settlement token on the settlement chain (same chain family only)."
          }
        }
      },
      "Refund": {
        "type": "object",
        "required": [
          "id",
          "object",
          "sessionId",
          "livemode",
          "status",
          "amount",
          "to",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^re_"
          },
          "object": {
            "type": "string",
            "const": "refund"
          },
          "sessionId": {
            "type": "string"
          },
          "livemode": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/RefundStatus"
          },
          "statusDetail": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "Base units of the settlement token."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "quoteId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The refund's order: build and report it through `POST /v1/orders`."
          },
          "to": {
            "type": "object",
            "required": [
              "chainId",
              "token",
              "address"
            ],
            "properties": {
              "chainId": {
                "type": "integer"
              },
              "token": {
                "type": "string"
              },
              "address": {
                "type": "string",
                "description": "The payer's address."
              }
            }
          },
          "txHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "The refund transaction once reported."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RefundCreateResponse": {
        "type": "object",
        "required": [
          "refund",
          "quote",
          "next"
        ],
        "properties": {
          "refund": {
            "$ref": "#/components/schemas/Refund"
          },
          "quote": {
            "type": "object",
            "required": [
              "quoteId",
              "provider",
              "srcAmount",
              "dstAmount",
              "dstAmountMin",
              "estimatedSeconds",
              "expiresAt",
              "from"
            ],
            "properties": {
              "quoteId": {
                "type": "string",
                "description": "Pass to `POST /v1/orders`, then `POST /v1/orders/{quoteId}/submitted`."
              },
              "provider": {
                "$ref": "#/components/schemas/ProviderId"
              },
              "srcAmount": {
                "type": "string",
                "pattern": "^\\d+$",
                "description": "What you send (settlement token)."
              },
              "dstAmount": {
                "type": "string",
                "pattern": "^\\d+$",
                "description": "What the payer is quoted to receive."
              },
              "dstAmountMin": {
                "type": "string",
                "pattern": "^\\d+$"
              },
              "estimatedSeconds": {
                "type": "integer"
              },
              "expiresAt": {
                "type": "integer",
                "description": "Unix seconds."
              },
              "from": {
                "type": "string",
                "description": "The wallet that must sign."
              }
            }
          },
          "next": {
            "type": "string",
            "description": "The remaining steps."
          }
        }
      },
      "RefundList": {
        "type": "object",
        "required": [
          "refunds"
        ],
        "properties": {
          "refunds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Refund"
            }
          }
        }
      },
      "CheckoutAnalytics": {
        "type": "object",
        "required": [
          "livemode",
          "from",
          "to",
          "totals",
          "byDay",
          "byPaidWith",
          "bySettlement"
        ],
        "properties": {
          "livemode": {
            "type": "boolean"
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "totals": {
            "type": "object",
            "required": [
              "sessions",
              "payments",
              "grossUsd",
              "refundedUsd",
              "netUsd",
              "averageUsd"
            ],
            "properties": {
              "sessions": {
                "type": "integer",
                "description": "Sessions created in the range."
              },
              "payments": {
                "type": "integer",
                "description": "Of those, `paid`."
              },
              "grossUsd": {
                "type": "number"
              },
              "refundedUsd": {
                "type": "number"
              },
              "netUsd": {
                "type": "number",
                "description": "Gross minus refunded."
              },
              "averageUsd": {
                "type": "number",
                "description": "Average payment."
              },
              "conversionRate": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Percent of sessions paid (one decimal)."
              },
              "medianSecondsToPay": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "From session creation to payment."
              },
              "averageSecondsToPay": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          },
          "byDay": {
            "type": "array",
            "description": "Every UTC day of the range.",
            "items": {
              "type": "object",
              "required": [
                "date",
                "payments",
                "revenueUsd",
                "refundedUsd"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "payments": {
                  "type": "integer"
                },
                "revenueUsd": {
                  "type": "number"
                },
                "refundedUsd": {
                  "type": "number"
                }
              }
            }
          },
          "byPaidWith": {
            "type": "array",
            "description": "What customers paid with, highest revenue first.",
            "items": {
              "type": "object",
              "required": [
                "chainId",
                "chain",
                "token",
                "payments",
                "revenueUsd"
              ],
              "properties": {
                "chainId": {
                  "type": "integer"
                },
                "chain": {
                  "type": "string"
                },
                "token": {
                  "type": "string"
                },
                "payments": {
                  "type": "integer"
                },
                "revenueUsd": {
                  "type": "number"
                }
              }
            }
          },
          "bySettlement": {
            "type": "array",
            "description": "What you received, highest revenue first.",
            "items": {
              "type": "object",
              "required": [
                "chainId",
                "chain",
                "symbol",
                "payments",
                "revenueUsd"
              ],
              "properties": {
                "chainId": {
                  "type": "integer"
                },
                "chain": {
                  "type": "string"
                },
                "symbol": {
                  "type": "string"
                },
                "payments": {
                  "type": "integer"
                },
                "revenueUsd": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "ComponentStatus": {
        "type": "string",
        "description": "`operational`, `degraded` (the latest probe failed) or `down` (an open incident).",
        "enum": [
          "operational",
          "degraded",
          "down"
        ]
      },
      "StatusComponent": {
        "type": "object",
        "required": [
          "id",
          "name",
          "group",
          "status",
          "latencyMs",
          "uptime90d",
          "days"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "`api`, `web`, `worker`, `checkout`, `dashboard`, `docs`, `mcp`, `bot` or `provider:{id}`."
          },
          "name": {
            "type": "string"
          },
          "group": {
            "type": "string",
            "description": "`Core`, `Payments`, `Developer tools` or `Liquidity providers`."
          },
          "status": {
            "$ref": "#/components/schemas/ComponentStatus"
          },
          "latencyMs": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Latest probe (last 15 minutes)."
          },
          "uptime90d": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent of successful probes over 90 days."
          },
          "days": {
            "type": "array",
            "description": "The last 90 UTC days, oldest first.",
            "items": {
              "type": "object",
              "required": [
                "date",
                "uptime"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "uptime": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Percent; null when there is no data."
                }
              }
            }
          }
        }
      },
      "StatusIncident": {
        "type": "object",
        "required": [
          "id",
          "componentId",
          "component",
          "title",
          "startedAt",
          "resolvedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "componentId": {
            "type": "string"
          },
          "component": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "StatusResponse": {
        "type": "object",
        "required": [
          "status",
          "updatedAt",
          "components",
          "incidents",
          "url"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "operational",
              "degraded",
              "outage"
            ]
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "components": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatusComponent"
            }
          },
          "incidents": {
            "type": "array",
            "description": "Incidents started in the last 14 days, newest first.",
            "items": {
              "$ref": "#/components/schemas/StatusIncident"
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The status page."
          }
        }
      }
    }
  }
}
