{"openapi":"3.1.0","info":{"title":"Velum Swap API","version":"3.2.1","summary":"Keyless, non-custodial swap routing across 70+ chains.","description":"Velum Swap's swap engine over HTTP: list chains, find any token, get ranked quotes from every provider, create a swap — the route issues its own one-time deposit address and you send from ANY wallet or exchange — and track status. Deposit-only: nothing is built for a wallet to sign.\n\n**No API key.** Rate limits are per client IP where the deployment can see it (otherwise one shared bucket); see each response's `X-RateLimit-*` headers; a 429 carries `Retry-After`.\n**Non-custodial.** The server never sees a private key, never signs or sends a transaction and never holds funds. Velum adds 0% platform fee; providers, solvers, exchanges and networks charge their own fees, all shown in the quote.\n**Third parties hold funds in flight** (the protocol while a swap fills; Exolix, then ChangeNOW, for a few minutes each in the xmr lane). Velum's own code has been reviewed by AI security agents; no independent firm has audited it yet.\n**Amounts** in requests are decimal strings in human units (`amount`) or integer strings in raw units (`amountRaw`); every `amountOut`-style field in a response is raw units. Quotes expire in about 25 seconds.\n**Payments (exact output):** give `amountOut` (human units of `to`) instead of `amount` to deliver EXACTLY that much — a checkout for \"25 USDC on Solana\" paid from any coin. Routes then carry `amountIn` (what the payer sends); pass it as `maxAmountIn` to /swap, with the route's own `provider`. Routed by exact-output providers only (Relay, NEAR Intents); the route that asks the payer for least is first. A NEAR Intents route includes a small margin (about 0.5%) that is refunded if unused; a Relay route is exact, or refunded. **Private payments:** with `privacy: \"xmr\"` the payment goes through the Monero hop between two exchanges, so nothing on-chain links the payer to the recipient; its legs are floating-rate, so the route says `delivery: \"at_least\"`: `amountIn` carries a 3% cushion (`cushionBps`) and the recipient receives everything that arrives (about `amountOut`), at least the amount asked unless prices move more than the cushion in the 30–60 minutes Monero takes. /swap prices it at exactly your `maxAmountIn` and refuses (409) if that no longer covers the amount plus half the cushion. The exchanges have minimums (about 50 USD). `privacy: \"fast\"` is refused for payments. Velum is not a payment gateway: it never holds the money and adds no fee.\n**Stateless and log-free:** requests and addresses are not stored or logged.\n\nAn MCP server for AI agents is available at `https://velum.exchange/api/mcp` (Streamable HTTP, stateless)."},"servers":[{"url":"https://velum.exchange"}],"tags":[{"name":"Discovery","description":"Chains and tokens."},{"name":"Swap","description":"Quote, create, track."},{"name":"Meta","description":"Health and the API description."},{"name":"Payments","description":"Pay links and x402 funding — exact-output payments, never custody."},{"name":"MCP","description":"Model Context Protocol endpoint for AI agents."}],"paths":{"/api/v1/chains":{"get":{"tags":["Discovery"],"operationId":"listChains","summary":"List chains","description":"Every chain Velum can route to or from, with which way it routes (`canPayFrom`, `canReceiveOn`).","responses":{"200":{"description":"Chains","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChainsResponse"}}}},"429":{"$ref":"#/components/responses/429"}}}},"/api/v1/tokens":{"get":{"tags":["Discovery"],"operationId":"searchTokens","summary":"List or search tokens","description":"Without `q`: the chain's default list. With `q`: search by symbol/name, or paste any contract address / Solana mint — this is how fresh launchpad coins (pump.fun, bonk.fun) are found once a DEX or aggregator lists them. An address nothing lists returns an empty list with a `hint`.","parameters":[{"name":"chain","in":"query","required":true,"description":"Chain key from GET /api/v1/chains.","schema":{"type":"string","minLength":1,"maxLength":32,"pattern":"^[A-Za-z0-9_-]+$","description":"Chain key from GET /api/v1/chains."}},{"name":"q","in":"query","required":false,"description":"Symbol, name, or a token address/mint. Omit for the chain's default list.","schema":{"description":"Symbol, name, or a token address/mint. Omit for the chain's default list.","type":"string","maxLength":128}}],"responses":{"200":{"description":"Tokens","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"400":{"$ref":"#/components/responses/400"},"429":{"$ref":"#/components/responses/429"}}}},"/api/v1/quote":{"post":{"tags":["Swap"],"operationId":"getQuote","summary":"Get ranked quotes","description":"Asks every route that issues a deposit address, in parallel, and returns them best-first. Add `refundTo` + `recipient` to make `depositReady` true (without them the price uses placeholders). `privacy`: standard | private (NEAR Intents confidential) | fast (instant-exchange hop) | xmr (the Monero hop between two exchanges, native coins they list). Total deadline 15 s: the routes that arrived by then are returned with `incomplete: true` (a slower provider may still have one); only when none arrived (and no `prehop` was priced) is it a 504, with `partial`.\n\n**Payments:** give exactly one of `amount`, `amountRaw` or `amountOut`. With `amountOut` (deliver exactly this much of `to`, human units) only exact-output routes (Relay, NEAR Intents) are returned, the one that asks the payer for least first, each with `amountIn`/`amountInFormatted` = what the payer sends (a NEAR Intents route includes a small margin, refunded if unused; a Relay route is exact, or refunded). With `privacy: \"xmr\"` the Monero hop answers instead, `delivery: \"at_least\"` (a 3% cushion the recipient keeps); `privacy: \"fast\"` is a 400.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"examples":{"solToUsdc":{"summary":"SOL → USDC on Solana","value":{"from":{"chain":"sol","token":"native"},"to":{"chain":"sol","token":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"},"amount":"0.1","refundTo":"AKeAJBqmt8nrbEcYtJ8ACAyPeYY81PGW6Zjs4rWwrPbA","recipient":"AKeAJBqmt8nrbEcYtJ8ACAyPeYY81PGW6Zjs4rWwrPbA"}}}}}},"responses":{"200":{"description":"Quotes (possibly with zero routes and per-provider errors)","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"$ref":"#/components/responses/400"},"413":{"$ref":"#/components/responses/413"},"415":{"$ref":"#/components/responses/415"},"429":{"$ref":"#/components/responses/429"},"502":{"$ref":"#/components/responses/502"},"504":{"description":"Deadline reached with no route in: `partial` holds the provider answers that did arrive.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/swap":{"post":{"tags":["Swap"],"operationId":"createSwap","summary":"Create a swap (the route's deposit address)","description":"Re-quotes `provider` fresh, then reserves that route's one-time deposit address (needs `refundTo` and `recipient`, both validated; `mode` is \"deposit\"). Send the exact amount there from any wallet or exchange. The server never signs, sends or holds anything. Tight rate limit (10/min).\n\n**Pass `minAmountOut`** from the route you confirmed in /quote (its after-slippage `minAmountOut`; for a floating-rate route that has none, its `amountOut`). If the fresh re-quote pays less, the call fails with **409 `price_moved`** carrying the fresh route in `error.details.route`, and NO deposit address is reserved. The response repeats the figures as `terms`. **Refunds** differ per provider: read `refundNote` (FixedFloat takes no refund address). The call plans for the route's 30 s limit: if too little time remains it answers 504 `timeout` and reserves nothing.\n\n**Payments:** with `amountOut`, pass `maxAmountIn` = the confirmed route's `amountIn`. If the fresh re-quote needs more, the call fails with 409 `price_moved` and nothing is reserved. The deposit address stays open about 72 hours but the price is held only briefly; a late or out-of-slippage deposit is refunded to `refundTo`. Track with /status?provider=near.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapRequest"}}}},"responses":{"200":{"description":"The deposit swap","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepositSwap"}}}},"400":{"$ref":"#/components/responses/400"},"409":{"description":"`price_moved`: the fresh quote pays less than your `minAmountOut` (or the provider's own slippage guard tripped), or for a payment needs more than your `maxAmountIn`. Nothing was reserved or built; `error.details.route` holds the fresh route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/413"},"415":{"$ref":"#/components/responses/415"},"422":{"description":"The provider cannot route this pair/amount right now, or the amount is under its minimum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/429"},"501":{"$ref":"#/components/responses/501"},"502":{"$ref":"#/components/responses/502"},"504":{"description":"Not enough time left to reserve / build safely, or a registry load hung. Nothing was reserved or built.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/status":{"get":{"tags":["Swap"],"operationId":"getStatus","summary":"Check a swap's status (one quick check)","description":"One-shot status read from the provider's own status endpoint; never a long poll. Poll it yourself about every 15 s and stop only on `success`, `refunded` or `failed`: `pending` is not final, and a pending `detail` can ask you to act (FixedFloat EMERGENCY: open the order on ff.io and choose refund or continue; NEAR short deposit: refunded after the deadline; deBridge cancelled order: refund claimable). Confidential NEAR ids carry an HMAC tag (`<address>:confidential:<tag>`) and must be passed exactly as `POST /api/v1/swap` returned them; unsigned or forged ones are a 400.","parameters":[{"name":"provider","in":"query","required":true,"description":"Provider id returned by POST /api/v1/swap (or by a swap built before deposit-only).","schema":{"type":"string","enum":["relay","near","chainflip","exolix","fixedfloat","xmrsplit","twoleg","jupiter","kyber","velora","zerox","debridge","lifi","across","mayan","symbiosis","thorchain"],"description":"Provider id returned by POST /api/v1/swap (or by a swap built before deposit-only)."}},{"name":"id","in":"query","required":true,"description":"trackingId returned by POST /api/v1/swap.","schema":{"type":"string","minLength":1,"maxLength":640,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:|#=+@/\\-_]*$","description":"trackingId returned by POST /api/v1/swap."}},{"name":"tx","in":"query","required":false,"description":"Origin-chain transaction hash. Required for LI.FI, Across, Symbiosis, Mayan, THORChain and Chainflip vault swaps (trackingId vault:…); for NEAR Intents it is forwarded to speed up deposit detection.","schema":{"description":"Origin-chain transaction hash. Required for LI.FI, Across, Symbiosis, Mayan, THORChain and Chainflip vault swaps (trackingId vault:…); for NEAR Intents it is forwarded to speed up deposit detection.","type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9]+$"}}],"responses":{"200":{"description":"Status","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"400":{"$ref":"#/components/responses/400"},"404":{"$ref":"#/components/responses/404"},"429":{"$ref":"#/components/responses/429"},"501":{"$ref":"#/components/responses/501"},"502":{"$ref":"#/components/responses/502"}}}},"/api/v1/paylink":{"post":{"tags":["Payments"],"operationId":"createPayLink","summary":"Make a pay link","description":"Builds a link anyone can open to pay EXACTLY `amount` of `token` on `chain` to the address `to`, from any coin on any chain (a deposit from any wallet or exchange). Checked the way the payer's page checks it: chain can be paid to, address valid for the chain, amount within the token's decimals. **Nothing is reserved, stored or charged** — the link is the request; each payment is created when someone pays it (POST /api/v1/swap with `amountOut`). Velum never holds the money. A coin NEAR Intents doesn't list is payable only in the same coin (`anyCoin: false`, with a warning); on a chain with no standard transfer link that is a 400.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayLinkRequest"},"examples":{"coffee":{"summary":"25 USDC on Solana","value":{"chain":"sol","token":"USDC","amount":"25","to":"AKeAJBqmt8nrbEcYtJ8ACAyPeYY81PGW6Zjs4rWwrPbA","label":"Coffee shop","note":"Invoice #1042"}}}}}},"responses":{"200":{"description":"The link","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayLinkResponse"}}}},"400":{"$ref":"#/components/responses/400"},"413":{"$ref":"#/components/responses/413"},"415":{"$ref":"#/components/responses/415"},"429":{"$ref":"#/components/responses/429"},"502":{"$ref":"#/components/responses/502"},"504":{"$ref":"#/components/responses/504"}}}},"/api/v1/x402/fund":{"post":{"tags":["Payments"],"operationId":"fundX402","summary":"Price funding an x402 payment from any coin","description":"An HTTP 402 (x402) asks for an exact amount of one asset on one network and you hold something else. Pass what the 402 returned — its JSON body, one `accepts` entry, or the base64 PAYMENT-REQUIRED header; x402 v1 (network names, `maxAmountRequired`) and v2 (CAIP-2, `amount`) are both read — plus YOUR wallet on that network and the coin you pay with. Returns an exact-output quote that delivers exactly that amount into your wallet (below a route's minimum delivery: the minimum +3%, the rest stays yours). Read-only. Then POST /api/v1/swap with `quoteBody`, the route's `provider` and `maxAmountIn`, and once it lands pay the 402 with your own x402 client: an x402 payment is a signature by the paying wallet, which Velum never makes. Testnets are refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402FundRequest"},"examples":{"baseUsdcFromSol":{"summary":"0.10 USDC on Base, paid from SOL","value":{"paymentRequired":{"x402Version":2,"accepts":[{"scheme":"exact","network":"eip155:8453","asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"100000","payTo":"0x…"}]},"wallet":"0x26C4f6247197e7033CEb5eDeeBE02f742f45fA82","from":{"chain":"sol","token":"native"},"refundTo":"AKeAJBqmt8nrbEcYtJ8ACAyPeYY81PGW6Zjs4rWwrPbA"}}}}}},"responses":{"200":{"description":"The funding quote (possibly with zero routes and per-provider errors)","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402FundResponse"}}}},"400":{"$ref":"#/components/responses/400"},"413":{"$ref":"#/components/responses/413"},"415":{"$ref":"#/components/responses/415"},"429":{"$ref":"#/components/responses/429"},"502":{"$ref":"#/components/responses/502"},"504":{"$ref":"#/components/responses/504"}}}},"/api/v1/health":{"get":{"tags":["Meta"],"operationId":"getHealth","summary":"Provider reachability and latency","description":"One cheap request per upstream provider (4 s timeout), cached in memory for 60 s. Latency is measured from this server to the provider. `steps` says whether each privacy step of the swap page (zk: the Solana ZK pool, zec: Zcash, xmr: Monero) can start right now and, when not, why — e.g. Zcash pauses by itself when the chain's consensus branch is one the in-browser Zcash wallet doesn't know.","responses":{"200":{"description":"Health","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"429":{"$ref":"#/components/responses/429"}}}},"/api/v1/payreq":{"post":{"tags":["Payments"],"operationId":"readPaymentRequest","summary":"Read a scanned or pasted payment code","description":"What a payment code asks for: a Velum pay link, BIP21 (bitcoin:, litecoin:, dogecoin:, bitcoincash:, zcash:, dash:), EIP-681 (ethereum:, native or ERC-20), Solana Pay (solana:), TON (ton://transfer) or a plain address. Returns the chain, the token (matched by contract/mint, never by symbol), the amount, the pay link that pays it from any coin, and `quoteBody` for POST /api/v1/quote (add your `from` and `refundTo`). Read-only; nothing is reserved. 400 with the reason for anything it can't read (an unsupported scheme, a Solana Pay transaction request, junk).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"additionalProperties":false,"properties":{"text":{"type":"string","maxLength":2048,"example":"bitcoin:bc1qm34lsc65zpw79lxes69zkqmk6ee3ewf0j77s3h?amount=0.0015"}}}}}},"responses":{"200":{"description":"What the code asks for","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/400"},"429":{"$ref":"#/components/responses/429"}}}},"/api/v1/clock":{"get":{"tags":["Meta"],"operationId":"getClock","summary":"Chains' current block intervals (for live ETAs)","description":"The mean block interval each chain is producing right now (seconds), read from public chain data — last blocks' timestamps on EVM chains, Solana's performance samples, mempool.space for Bitcoin, Monero nodes, daily averages for Litecoin / Dogecoin / Zcash — with the nominal value as a fallback (`source: \"fallback\"`). `lagging`: Relay flags the chain's block production as lagging; `congested`: the latest EVM block was over 90 % full. Cached per chain on the server (30 s; 5 min for daily averages). The app's live ETA sums each route's sub-hops (deposit inclusion + confirmations, fill, payout, the Monero lock) from these.","parameters":[{"name":"chains","in":"query","required":true,"description":"Up to 8 chain keys, comma-separated; \"xmr\" is Monero.","schema":{"type":"string","example":"btc,base,xmr"}}],"responses":{"200":{"description":"Clock per chain","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute for this endpoint."},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"at":{"type":"integer"},"chains":{"type":"object","additionalProperties":{"type":"object","properties":{"interval":{"type":"number"},"nominal":{"type":"number"},"source":{"type":"string","enum":["live","fallback"]},"lagging":{"type":"boolean"},"congested":{"type":"boolean"}}}}}}}}},"400":{"$ref":"#/components/responses/400"},"429":{"$ref":"#/components/responses/429"}}}},"/api/v1/openapi.json":{"get":{"tags":["Meta"],"operationId":"getOpenApi","summary":"This document","responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/mcp":{"post":{"tags":["MCP"],"operationId":"mcpPost","summary":"MCP over Streamable HTTP (stateless)","description":"JSON-RPC 2.0 messages for the Model Context Protocol. Tools: list_chains, search_tokens, get_quote, create_deposit_swap, get_swap_status, get_privacy_options, create_payment_link (a pay link for an exact amount; read-only), read_payment_request (what a scanned / pasted payment code asks for; read-only), fund_x402_payment (prices an exact-output swap into your own wallet to pay an HTTP 402; read-only, Velum never signs the x402 payment). Add `https://velum.exchange/api/mcp` as a remote MCP server in your client. Stateless: no session id; each request is independent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A JSON-RPC 2.0 request, notification or batch."}}}},"responses":{"200":{"description":"JSON-RPC response","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"$ref":"#/components/responses/429"}}},"get":{"tags":["MCP"],"operationId":"mcpInfo","summary":"Discovery document (or 405 for an SSE request)","responses":{"200":{"description":"Server name, tools, instructions"},"405":{"$ref":"#/components/responses/405"}}},"delete":{"tags":["MCP"],"operationId":"mcpDelete","summary":"No-op (stateless: there is no session to end)","responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"TokenSpec":{"type":"object","properties":{"chain":{"type":"string","minLength":1,"maxLength":32,"pattern":"^[A-Za-z0-9_-]+$","description":"Chain key from GET /api/v1/chains, e.g. \"sol\", \"eth\", \"base\", \"btc\" — common names like \"solana\", \"ethereum\", \"arbitrum\" work too."},"token":{"type":"string","minLength":1,"maxLength":128,"description":"Token contract address (EVM) or mint (Solana); \"native\" (or the coin's symbol, e.g. \"SOL\") for the chain's own coin; or a ticker like \"USDC\" when exactly one listed token on the chain has it (several → a 400 listing their addresses)."}},"required":["chain","token"],"additionalProperties":false,"description":"A token on a chain."},"QuoteRequest":{"type":"object","properties":{"from":{"description":"The token you pay with.","$ref":"#/components/schemas/TokenSpec"},"to":{"description":"The token you want to receive.","$ref":"#/components/schemas/TokenSpec"},"amount":{"description":"Amount of `from` in human units as a decimal string, e.g. \"1.5\". Give exactly one of `amount`, `amountRaw` or `amountOut`.","type":"string","pattern":"^\\d{1,40}(\\.\\d{1,40})?$"},"amountRaw":{"description":"Amount of `from` in the token's smallest unit (e.g. lamports, wei) as an integer string. Give exactly one of `amount`, `amountRaw` or `amountOut`.","type":"string","pattern":"^\\d{1,78}$"},"amountOut":{"description":"PAYMENTS: deliver EXACTLY this much of `to` (human units), e.g. \"25\" for a 25 USDC checkout — the quote then tells the payer how much `from` to send (route.amountIn). Give it instead of `amount`/`amountRaw`. Routed by the exact-output providers (Relay, NEAR Intents), the one that asks the payer for least first. With privacy \"xmr\" it is paid through the Monero hop instead and delivers AT LEAST the amount (route.delivery \"at_least\": a 3% cushion, the recipient keeps all of it). privacy \"fast\" is refused.","type":"string","pattern":"^\\d{1,40}(\\.\\d{1,40})?$"},"refundTo":{"description":"Deposit mode: where a failed swap is refunded, on the from-chain. Required to create a deposit swap.","type":"string","minLength":1,"maxLength":512},"recipient":{"description":"Who receives the output, on the to-chain. Required to create a swap; quotes without it are priced with a placeholder.","type":"string","minLength":1,"maxLength":512},"slippageBps":{"default":50,"description":"Max slippage in basis points (1..5000). Default 50 = 0.5%.","type":"integer","minimum":1,"maximum":5000},"hopRefunds":{"description":"Refund addresses for a route's middle steps, when it can't infer one you control: the Monero route (privacy \"xmr\") and the two-step route (provider \"twoleg\"). A quote says which it needs in route.refundsNeeded; /swap refuses (400 refund_needed) until they are given.","type":"object","properties":{"entry":{"description":"Monero route: a refund address YOU control on the coin exchange A takes, when a conversion lands it on another address family (route.refundsNeeded.entry names the chain).","type":"string","minLength":1,"maxLength":512},"exit":{"description":"Monero or two-step route: a refund address YOU control on the chain of the final conversion (route.refundsNeeded.exit names the chain). Never an exchange deposit address.","type":"string","minLength":1,"maxLength":512},"exitToRecipient":{"description":"Monero route: you confirm the receive address is yours (not an exchange's), so the final conversion may refund to it — only when that conversion runs on the destination chain.","type":"boolean"},"xmr":{"description":"Monero route: a Monero mainnet address YOU control (standard 4… or subaddress 8…), given to the second exchange as its refund address — its input is XMR. Without it that exchange has no refund address and a refund there goes through its support with the order id.","type":"string","minLength":1,"maxLength":512}},"additionalProperties":false},"privacy":{"default":"standard","description":"\"standard\" public routes on NEAR Intents or Relay; \"private\" NEAR Intents confidential; \"xmr\" the Monero step (Exolix, then ChangeNOW — the only place exchanges are used), for any coin (a NEAR Intents / Relay conversion leg is added before or after when an exchange does not list it). \"fast\" is retired and refused.","type":"string","enum":["standard","private","fast","xmr"]}},"required":["from","to"],"additionalProperties":false,"description":"Request body for POST /api/v1/quote. Give exactly one of `amount`, `amountRaw` (what you send) or `amountOut` (a PAYMENT: deliver exactly this much of `to`, routed by the exact-output providers, Relay and NEAR Intents, whichever asks the payer for less)."},"SwapRequest":{"type":"object","properties":{"from":{"description":"The token you pay with.","$ref":"#/components/schemas/TokenSpec"},"to":{"description":"The token you want to receive.","$ref":"#/components/schemas/TokenSpec"},"amount":{"description":"Amount of `from` in human units as a decimal string, e.g. \"1.5\". Give exactly one of `amount`, `amountRaw` or `amountOut`.","type":"string","pattern":"^\\d{1,40}(\\.\\d{1,40})?$"},"amountRaw":{"description":"Amount of `from` in the token's smallest unit (e.g. lamports, wei) as an integer string. Give exactly one of `amount`, `amountRaw` or `amountOut`.","type":"string","pattern":"^\\d{1,78}$"},"amountOut":{"description":"PAYMENTS: deliver EXACTLY this much of `to` (human units), e.g. \"25\" for a 25 USDC checkout — the quote then tells the payer how much `from` to send (route.amountIn). Give it instead of `amount`/`amountRaw`. Routed by the exact-output providers (Relay, NEAR Intents), the one that asks the payer for least first. With privacy \"xmr\" it is paid through the Monero hop instead and delivers AT LEAST the amount (route.delivery \"at_least\": a 3% cushion, the recipient keeps all of it). privacy \"fast\" is refused.","type":"string","pattern":"^\\d{1,40}(\\.\\d{1,40})?$"},"refundTo":{"description":"Deposit mode: where a failed swap is refunded, on the from-chain. Required to create a deposit swap.","type":"string","minLength":1,"maxLength":512},"recipient":{"description":"Who receives the output, on the to-chain. Required to create a swap; quotes without it are priced with a placeholder.","type":"string","minLength":1,"maxLength":512},"slippageBps":{"default":50,"description":"Max slippage in basis points (1..5000). Default 50 = 0.5%.","type":"integer","minimum":1,"maximum":5000},"hopRefunds":{"description":"Refund addresses for a route's middle steps, when it can't infer one you control: the Monero route (privacy \"xmr\") and the two-step route (provider \"twoleg\"). A quote says which it needs in route.refundsNeeded; /swap refuses (400 refund_needed) until they are given.","type":"object","properties":{"entry":{"description":"Monero route: a refund address YOU control on the coin exchange A takes, when a conversion lands it on another address family (route.refundsNeeded.entry names the chain).","type":"string","minLength":1,"maxLength":512},"exit":{"description":"Monero or two-step route: a refund address YOU control on the chain of the final conversion (route.refundsNeeded.exit names the chain). Never an exchange deposit address.","type":"string","minLength":1,"maxLength":512},"exitToRecipient":{"description":"Monero route: you confirm the receive address is yours (not an exchange's), so the final conversion may refund to it — only when that conversion runs on the destination chain.","type":"boolean"},"xmr":{"description":"Monero route: a Monero mainnet address YOU control (standard 4… or subaddress 8…), given to the second exchange as its refund address — its input is XMR. Without it that exchange has no refund address and a refund there goes through its support with the order id.","type":"string","minLength":1,"maxLength":512}},"additionalProperties":false},"privacy":{"default":"standard","description":"\"standard\" public routes on NEAR Intents or Relay; \"private\" NEAR Intents confidential; \"xmr\" the Monero step (Exolix, then ChangeNOW — the only place exchanges are used), for any coin (a NEAR Intents / Relay conversion leg is added before or after when an exchange does not list it). \"fast\" is retired and refused.","type":"string","enum":["standard","private","fast","xmr"]},"provider":{"type":"string","enum":["relay","near","chainflip","exolix","fixedfloat","xmrsplit","twoleg"],"description":"Provider id of the route to execute, from a quote's `routes[].provider`."},"minAmountOut":{"type":"string","pattern":"^\\d{1,78}$","description":"Raw-unit floor for the output, an integer string. Pass the chosen route's `minAmountOut` from /quote (for routes that carry none, its `amountOut`). If the fresh re-quote's `amountOut` is lower, the call fails with 409 `price_moved` (the fresh route is in `error.details.route`) and no deposit address is reserved and no transaction is built. It checks the price when the address is RESERVED: floating-rate routes (Exolix, FixedFloat, the Monero hop, the two-step route's second step) settle at the rate when your coins arrive, which this floor cannot bind."},"maxAmountIn":{"type":"string","pattern":"^\\d{1,78}$","description":"Payments (`amountOut`) only: raw-unit ceiling for what the payer sends. Pass the quoted route's `amountIn` (plus any margin you accept). If the fresh re-quote needs more, the call fails with 409 `price_moved` and nothing is reserved or built."},"mode":{"type":"string","enum":["deposit"],"description":"\"deposit\": the route issues a one-time deposit address; send to it from ANY wallet or exchange."}},"required":["from","to","provider","mode"],"additionalProperties":false,"description":"Request body for POST /api/v1/swap: the quote body plus `provider` and `mode`. Pass `minAmountOut` from the confirmed route; for a payment (`amountOut`), pass `maxAmountIn` = the confirmed route's `amountIn`."},"PayLinkRequest":{"type":"object","properties":{"chain":{"type":"string","minLength":1,"maxLength":32,"pattern":"^[A-Za-z0-9_-]+$","description":"Chain the merchant is paid on: a key from GET /api/v1/chains (e.g. \"sol\", \"base\", \"btc\"); \"solana\", \"ethereum\" work too."},"token":{"default":"native","description":"Coin the merchant receives: a mint/contract address, \"native\", or a ticker such as \"USDC\" when exactly one listed token has it. Default \"native\".","type":"string","minLength":1,"maxLength":128},"amount":{"type":"string","pattern":"^\\d{1,30}(\\.\\d{1,18})?$","description":"EXACT amount the merchant receives, in human units, e.g. \"25\"."},"to":{"type":"string","minLength":1,"maxLength":512,"description":"The merchant's address on `chain` — the payment goes straight there."},"label":{"description":"Name shown to the payer, e.g. a shop name.","type":"string","maxLength":60,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"note":{"description":"Note shown to the payer, e.g. \"Invoice #1042\".","type":"string","maxLength":120,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"}},"required":["chain","amount","to"],"additionalProperties":false,"description":"Request body for POST /api/v1/paylink."},"X402FundRequest":{"type":"object","properties":{"paymentRequired":{"anyOf":[{"type":"string","minLength":8,"maxLength":12000},{"type":"object","properties":{},"additionalProperties":{}}],"description":"What the 402 asked for: its JSON body ({ x402Version, accepts: [...] }), one entry of `accepts`, or the base64 PAYMENT-REQUIRED header value. x402 v1 and v2 are both read. At most 10 `accepts` entries (more is a 400: pass the entry you want to pay with)."},"wallet":{"type":"string","minLength":1,"maxLength":512,"description":"YOUR wallet on the network the 402 wants paid on — the asset is delivered here, then your x402 client pays from it."},"from":{"description":"The coin you hold and pay with (any chain).","$ref":"#/components/schemas/TokenSpec"},"refundTo":{"description":"Deposit mode: where a failed swap is refunded, on the from-chain.","type":"string","minLength":1,"maxLength":512},"slippageBps":{"description":"Max slippage in basis points. Default 50.","type":"integer","minimum":1,"maximum":5000}},"required":["paymentRequired","wallet","from"],"additionalProperties":false,"description":"Request body for POST /api/v1/x402/fund."},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable code, e.g. validation_error, rate_limited, no_route."},"message":{"type":"string","description":"Human-readable explanation."},"issues":{"description":"Per-field validation problems (400).","type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}},"details":{"description":"Extra machine-readable context. On 409 `price_moved`: { minAmountOut, amountOut, route } — the fresh route (same shape as a /quote route) so the caller can re-confirm."}},"required":["code","message"],"additionalProperties":false},"partial":{"description":"On 504: the routes that arrived before the deadline."}},"required":["error"],"additionalProperties":false},"Chain":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"vm":{"type":"string","description":"Address type: \"evm\", \"svm\", \"bvm\" (Bitcoin-like) or \"other\"."},"nativeSymbol":{"type":"string"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"icon":{"type":["string","null"]},"explorer":{"type":["string","null"]},"canPayFrom":{"type":"boolean","description":"false when no provider takes a deposit from this chain right now (measured 2026-10-14); quotes FROM it will find no route."},"canReceiveOn":{"type":"boolean","description":"false when no provider routes to this chain at all right now; such chains are hidden in the app."}},"required":["key","name","vm","nativeSymbol","decimals","icon","explorer","canPayFrom","canReceiveOn"],"additionalProperties":false},"ChainsResponse":{"type":"object","properties":{"chains":{"type":"array","items":{"$ref":"#/components/schemas/Chain"}}},"required":["chains"],"additionalProperties":false},"Token":{"type":"object","properties":{"chain":{"type":"string"},"address":{"description":"Contract/mint address; null = the chain's native coin.","type":["string","null"]},"symbol":{"type":"string"},"name":{"type":"string"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"icon":{"type":["string","null"]},"usd":{"description":"Indicative USD price when the source provides a live one.","type":"number"},"verified":{"type":"boolean","description":"true = on a curated list: the chain's native coin, NEAR Intents' token list, or verified by Relay or Jupiter. false = a search hit anyone could have created under this name or symbol (lookalike \"USDC\"s exist): use it only if the user gave you this exact address."},"unverified":{"type":"boolean","description":"true = on NO token list at all, found only by reading the chain (e.g. a pasted contract address): confirm the address with the user before quoting it."},"risks":{"description":"Plain-language red flags when the source reports any (issuer can freeze or mint, thin liquidity, concentrated holders).","type":"array","items":{"type":"string"}}},"required":["chain","address","symbol","name","decimals","icon","verified","unverified"],"additionalProperties":false},"TokensResponse":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}},"hint":{"type":"string"}},"required":["tokens"],"additionalProperties":false},"Route":{"type":"object","properties":{"provider":{"type":"string","enum":["relay","near","chainflip","exolix","fixedfloat","xmrsplit","twoleg"]},"providerName":{"type":"string"},"amountOut":{"type":"string","description":"Output in raw units of the `to` token (integer string)."},"amountOutFormatted":{"type":"string","description":"Output in human units."},"minAmountOut":{"description":"Guaranteed minimum after slippage, raw units.","type":"string"},"amountIn":{"description":"Payments (`amountOut` requests) only: what the payer sends, raw units of `from`. On a NEAR Intents route it includes a small exact-output margin that is refunded if unused; a Relay route is exact, or refunded. Pass it as `maxAmountIn` to /swap.","type":"string"},"amountInFormatted":{"description":"Payments only: `amountIn` in human units.","type":"string"},"maxAmountIn":{"description":"Payments only: pass this to /swap as `maxAmountIn` — `amountIn` plus your slippage, rounded up (the mirror of `minAmountOut`); the Monero hop's `at_least` routes: `amountIn` itself. The payer sends the fresh exact amount, never more than this.","type":"string"},"delivery":{"description":"Payments only. \"exact\": the recipient gets exactly `amountOut` (Relay, NEAR Intents). \"at_least\": privacy \"xmr\" — the Monero hop is floating-rate, so `amountIn` carries `cushionBps` over what the route needs and the recipient receives everything that arrives (`amountOut` here is the expected delivery): at least the amount asked unless prices move more than the cushion while Monero confirms.","type":"string","enum":["exact","at_least"]},"cushionBps":{"description":"Payments with delivery \"at_least\": the cushion over the need, in basis points (300 = 3%).","type":"number"},"refundsNeeded":{"description":"Monero route: refund addresses YOU must still give in hopRefunds before /swap can create it (every refund goes to an address the sender controls). Absent = none needed.","type":"object","properties":{"entry":{"type":"object","properties":{"chain":{"type":"string"},"chainName":{"type":"string"}},"required":["chain","chainName"],"additionalProperties":false},"exit":{"type":"object","properties":{"chain":{"type":"string"},"chainName":{"type":"string"},"recipientFits":{"type":"boolean","description":"The final conversion runs on the destination chain: hopRefunds.exitToRecipient may be used instead of an address."}},"required":["chain","chainName","recipientFits"],"additionalProperties":false}},"additionalProperties":false},"effectiveAmountOut":{"type":"string","description":"amountOut minus any fee paid on top of the input, expressed in output units. Routes are ranked by this."},"etaSeconds":{"type":"number"},"costBps":{"description":"All-in cost against the market price in basis points, when both sides have a price from one source.","type":"number"},"feeNote":{"type":"string"},"extraFee":{"type":"object","properties":{"label":{"type":"string"},"usd":{"type":"number"}},"required":["label"],"additionalProperties":false},"breakdown":{"type":"object","properties":{"fees":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"to":{"type":"string"},"usd":{"type":["number","null"]},"included":{"type":"boolean","description":"true = already taken out of the output; false = paid on top of the input."}},"required":["label","to","usd","included"],"additionalProperties":false}},"steps":{"type":"array","items":{"type":"string"},"description":"The path the money takes, in order."},"networkFeeUsd":{"type":["number","null"]},"networkFeeNote":{"type":"string"}},"required":["fees","steps"],"additionalProperties":false},"route":{"type":"string"},"confidential":{"type":"boolean"},"confidentialLeg":{"description":"A multi-step route (the two-step route) under privacy \"private\": the step that ran confidentially on NEAR Intents, e.g. \"step 1 (NEAR Intents)\". The deposit and the payout aren't publicly linked, but `confidential` stays false: the other step is public.","type":"string"},"depositSupported":{"type":"boolean","description":"POST /api/v1/swap with mode deposit can reserve a deposit address for this route."},"depositReady":{"type":"boolean","description":"This very request already carries a valid refundTo and recipient, so a deposit swap can be created as-is."},"executable":{"type":"boolean","description":"POST /api/v1/swap can create this route. Always true: every route here issues its own deposit address (kept for API stability)."},"quoteExpiresAt":{"type":"string","description":"ISO time after which the quote should be re-requested (~25 s)."},"appUrl":{"type":"string","description":"Open the same swap in the Velum web app."},"notes":{"type":"array","items":{"type":"string"}}},"required":["provider","providerName","amountOut","amountOutFormatted","effectiveAmountOut","feeNote","breakdown","confidential","depositSupported","depositReady","executable","quoteExpiresAt","appUrl"],"additionalProperties":false},"QuoteResponse":{"type":"object","properties":{"request":{"type":"object","properties":{"from":{"type":"object","properties":{"chain":{"type":"string"},"token":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["chain","token","symbol","decimals"],"additionalProperties":false},"to":{"type":"object","properties":{"chain":{"type":"string"},"token":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["chain","token","symbol","decimals"],"additionalProperties":false},"amount":{"description":"A swap: what you send, human units (absent on a payment).","type":"string"},"amountRaw":{"description":"A swap: what you send, raw units (absent on a payment).","type":"string"},"amountOut":{"description":"A payment: exactly what is delivered, human units of `to` (absent on a swap).","type":"string"},"amountOutRaw":{"description":"A payment: exactly what is delivered, raw units (absent on a swap).","type":"string"},"slippageBps":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"privacy":{"type":"string","enum":["standard","private","fast","xmr"]},"mode":{"type":"string","enum":["deposit"]},"refundTo":{"type":"string"},"recipient":{"type":["string","null"]},"depositReady":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["from","to","slippageBps","privacy","mode","recipient","depositReady"],"additionalProperties":false},"routes":{"type":"array","items":{"$ref":"#/components/schemas/Route"},"description":"Best first."},"best":{"description":"Provider id of routes[0], or null when there is no route.","type":["string","null"]},"fastest":{"type":["string","null"]},"errors":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"error":{"type":"string"}},"required":["provider","error"],"additionalProperties":false},"description":"Providers that had no route, with a plain-language reason."},"suggestedMinInput":{"description":"When routes failed only on a minimum: the smallest amount that would work, and what to send.","type":"object","properties":{"amount":{"type":"number","description":"The provider's exact floor."},"symbol":{"type":"string"},"recommended":{"type":"number","description":"The floor + 5%: what to actually send, so a price dip before it lands can't undercut the floor."}},"required":["amount","symbol","recommended"],"additionalProperties":false},"note":{"type":"string"},"incomplete":{"description":"A slower provider hadn't answered by the 15 s deadline: these are the routes that arrived (with none: the priced `prehop` / `posthop`, returned from about 8 s when a temporary wallet is the only way in hand), and `note` names who may still have one. Ask again to include it.","type":"boolean","const":true},"prehop":{"description":"Pay with any coin: when no deposit route takes the coin you send (a memecoin on Solana or an EVM chain), the app runs the swap through a temporary wallet made in your browser — it swaps the coin into a major coin on the same chain, then a deposit route delivers. Priced here, run in the app (appUrl): the API never creates that wallet, because its key must stay with the payer. `deposit` lists what to send it: the coin, and on EVM a little gas.","anyOf":[{"type":"object","properties":{"available":{"type":"boolean","const":true},"runsIn":{"type":"string","const":"app"},"appUrl":{"type":"string"},"why":{"type":"string"},"route":{"type":"string"},"amountOut":{"type":"string"},"amountOutFormatted":{"type":"string"},"etaSeconds":{"type":"number"},"majorCoin":{"type":"object","properties":{"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["symbol","chain"],"additionalProperties":false},"deposit":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"amount":{"type":"string"},"raw":{"type":"string"},"usd":{"type":["number","null"]},"purpose":{"type":"string","enum":["coin","gas"]}},"required":["symbol","amount","raw","purpose"],"additionalProperties":false}},"networkFeeUsd":{"type":["number","null"]},"steps":{"type":"array","items":{"type":"string"}}},"required":["available","runsIn","appUrl","why","route","amountOut","amountOutFormatted","majorCoin","deposit","networkFeeUsd","steps"],"additionalProperties":false},{"type":"object","properties":{"available":{"type":"boolean","const":false},"why":{"type":"string"}},"required":["available","why"],"additionalProperties":false}]},"posthop":{"description":"Receive any coin: when no deposit route delivers the coin you want (a memecoin on Solana or an EVM chain, or one NEAR Intents lists without liquidity), the app has a route deliver the receiving chain's own coin to a temporary wallet made in your browser, which buys your coin on that chain and sends it on. Priced here, run in the app (appUrl) — the API never creates that wallet.","anyOf":[{"type":"object","properties":{"available":{"type":"boolean","const":true},"runsIn":{"type":"string","const":"app"},"appUrl":{"type":"string"},"why":{"type":"string"},"route":{"type":"string"},"amountOut":{"type":"string"},"amountOutFormatted":{"type":"string"},"etaSeconds":{"type":"number"},"majorCoin":{"type":"object","properties":{"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["symbol","chain"],"additionalProperties":false,"description":"The receiving chain's own coin, delivered into the temporary wallet that buys your coin with it."},"inboundVia":{"description":"The route that delivers it into the wallet; null when you send it there yourself (it is the coin you pay).","type":["string","null"]},"buyVia":{"type":"string"},"payThrough":{"description":"Also paying with any coin: the major coin your coin is first swapped into, in a second temporary wallet.","type":"object","properties":{"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["symbol","chain"],"additionalProperties":false},"deposit":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"amount":{"type":"string"},"raw":{"type":"string"},"usd":{"type":["number","null"]},"purpose":{"type":"string","enum":["coin","gas"]}},"required":["symbol","amount","raw","purpose"],"additionalProperties":false}},"keepsForFees":{"type":"object","properties":{"symbol":{"type":"string"},"amount":{"type":"string"},"raw":{"type":"string"},"usd":{"type":["number","null"]}},"required":["symbol","amount","raw","usd"],"additionalProperties":false,"description":"What the wallet keeps of the major coin for its own transactions; what it doesn't spend goes to the recipient too."},"networkFeeUsd":{"type":["number","null"]},"steps":{"type":"array","items":{"type":"string"}}},"required":["available","runsIn","appUrl","why","route","amountOut","amountOutFormatted","majorCoin","inboundVia","buyVia","deposit","keepsForFees","networkFeeUsd","steps"],"additionalProperties":false},{"type":"object","properties":{"available":{"type":"boolean","const":false},"why":{"type":"string"}},"required":["available","why"],"additionalProperties":false}]}},"required":["request","routes","best","fastest","errors"],"additionalProperties":false},"DepositSwap":{"type":"object","properties":{"mode":{"type":"string","const":"deposit"},"provider":{"type":"string"},"terms":{"type":"object","properties":{"amountIn":{"type":"object","properties":{"raw":{"type":"string","description":"Integer string, the token's smallest unit."},"formatted":{"type":"string","description":"Human units."},"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["raw","formatted","symbol","chain"],"additionalProperties":false,"description":"What is sent."},"amountOut":{"type":"object","properties":{"raw":{"type":"string","description":"Integer string, the token's smallest unit."},"formatted":{"type":"string","description":"Human units."},"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["raw","formatted","symbol","chain"],"additionalProperties":false,"description":"What the fresh quote says is received (an estimate for floating-rate exchanges)."},"minAmountOut":{"description":"The provider's after-slippage floor. Absent for floating-rate exchanges (Fast / XMR lanes), which promise no minimum.","type":"object","properties":{"raw":{"type":"string","description":"Integer string, the token's smallest unit."},"formatted":{"type":"string","description":"Human units."},"symbol":{"type":"string"},"chain":{"type":"string"}},"required":["raw","formatted","symbol","chain"],"additionalProperties":false}},"required":["amountIn","amountOut"],"additionalProperties":false,"description":"What the caller is agreeing to, in one place. Show these three figures before anything is sent."},"refundNote":{"type":"string","description":"Where a failed or cancelled swap's money goes, in this provider's own terms. FixedFloat takes NO refund address: refunds are chosen on its order page. Monero routes: a leg-2 refund goes through the exchange's support."},"depositAddress":{"type":"string","description":"One-time address. Send exactly `amountRaw` of the from-token on `chain` here, from any wallet or exchange."},"amountRaw":{"type":"string"},"amountFormatted":{"type":"string"},"symbol":{"type":"string"},"chain":{"type":"string"},"memo":{"description":"Memo / tag some chains require. Include it.","type":"string"},"expiresAt":{"type":"string"},"trackingId":{"type":"string"},"statusUrl":{"type":"string"},"trackingLinks":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"url":{"type":"string"}},"required":["label","url"],"additionalProperties":false}},"recipient":{"type":"string"},"refundTo":{"description":"Present only when the provider actually refunds to it. Absent for FixedFloat (no refund address; see `refundNote`).","type":"string"},"instructions":{"type":"string"},"quote":{"$ref":"#/components/schemas/Route"},"warning":{"type":"string"}},"required":["mode","provider","terms","refundNote","depositAddress","amountRaw","amountFormatted","symbol","chain","trackingId","statusUrl","trackingLinks","recipient","instructions","quote","warning"],"additionalProperties":false},"StatusResponse":{"type":"object","properties":{"provider":{"type":"string"},"id":{"type":"string"},"status":{"type":"string","enum":["pending","success","refunded","failed"]},"detail":{"type":"string"},"links":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"url":{"type":"string"}},"required":["label","url"],"additionalProperties":false}}},"required":["provider","id","status","links"],"additionalProperties":false},"HealthResponse":{"type":"object","properties":{"checkedAt":{"type":"string"},"cacheAgeSeconds":{"type":"number"},"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["up","down","unconfigured"]},"reachable":{"type":"boolean"},"latencyMs":{"type":["number","null"]},"error":{"type":"string"}},"required":["id","name","status","reachable","latencyMs"],"additionalProperties":false}},"steps":{"type":"object","properties":{"zk":{"type":"object","properties":{"ok":{"type":"boolean"},"why":{"type":"string"}},"required":["ok"],"additionalProperties":false},"zec":{"type":"object","properties":{"ok":{"type":"boolean"},"why":{"type":"string"}},"required":["ok"],"additionalProperties":false},"xmr":{"type":"object","properties":{"ok":{"type":"boolean"},"why":{"type":"string"}},"required":["ok"],"additionalProperties":false}},"required":["zk","zec","xmr"],"additionalProperties":false}},"required":["checkedAt","cacheAgeSeconds","providers","steps"],"additionalProperties":false},"PayLinkResponse":{"type":"object","properties":{"url":{"type":"string","description":"The pay link — the same /pay URL the app makes. Share it or show it as a QR code; nothing was stored."},"directUri":{"description":"Solana Pay (`solana:`) or EIP-681 (`ethereum:`) transfer URI for a payer who already holds the coin; null on chains without one.","type":["string","null"]},"anyCoin":{"type":"boolean","description":"True when any coin on any chain can pay it (NEAR Intents lists the coin). False: payable only in the same coin, and `warnings` says so."},"request":{"type":"object","properties":{"chain":{"type":"string"},"chainName":{"type":"string"},"token":{"type":"object","properties":{"symbol":{"type":"string"},"address":{"description":"null = the chain's native coin","type":["string","null"]},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["symbol","address","decimals"],"additionalProperties":false},"amount":{"type":"string","description":"Exact amount the merchant receives, human units."},"amountRaw":{"type":"string","description":"The same, raw units."},"to":{"type":"string"},"label":{"type":"string"},"note":{"type":"string"}},"required":["chain","chainName","token","amount","amountRaw","to"],"additionalProperties":false},"quoteBody":{"type":"object","properties":{"from":{"type":"object","properties":{"chain":{"type":"string"},"token":{"type":"string"}},"required":["chain","token"],"additionalProperties":false},"to":{"type":"object","properties":{"chain":{"type":"string"},"token":{"type":"string"}},"required":["chain","token"],"additionalProperties":false},"amountOut":{"type":"string"},"recipient":{"type":"string"}},"required":["from","to","amountOut","recipient"],"additionalProperties":false,"description":"A payer's POST /api/v1/quote body with `from` left as placeholders: fill in the payer's coin."},"note":{"type":"string"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["url","directUri","anyCoin","request","quoteBody","note","warnings"],"additionalProperties":false},"X402FundResponse":{"type":"object","properties":{"requirement":{"type":"object","properties":{"scheme":{"type":"string"},"network":{"type":"string","description":"As the 402 wrote it (v1 name or v2 CAIP-2)."},"asset":{"type":"string"},"amountRaw":{"type":"string","description":"What the 402 asks, raw units."},"payTo":{"type":"string"},"resource":{"type":"string"},"description":{"type":"string"},"chain":{"type":"string","description":"Velum chain key for the network."},"chainName":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"amount":{"type":"string","description":"What the 402 asks, human units."}},"required":["scheme","network","asset","amountRaw","chain","chainName","symbol","decimals","amount"],"additionalProperties":false,"description":"The payment option chosen (the first one Velum can fund)."},"skipped":{"type":"array","items":{"type":"object","properties":{"network":{"type":"string"},"asset":{"type":"string"},"reason":{"type":"string"}},"required":["network","asset","reason"],"additionalProperties":false},"description":"Options passed over (testnets, unknown networks or assets) and why."},"fundingNeeded":{"type":"boolean","description":"False when the coin you pay with already is the asset on that network: pay the 402 directly."},"quoteBody":{"description":"The POST /api/v1/quote body of the funding swap: exactly the asked amount (or the route's minimum delivery, +3%) into your wallet. Reuse it for POST /api/v1/swap with `provider` and `maxAmountIn`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"quote":{"$ref":"#/components/schemas/QuoteResponse"},"next":{"type":"string","description":"What to do next, in one paragraph."}},"required":["requirement","skipped","fundingNeeded","next"],"additionalProperties":false}},"responses":{"400":{"description":"Validation failed (`error.issues` lists each field), unknown chain/token, or a refund address the route still needs (`refund_needed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Method not allowed (see the `Allow` header).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 16 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Send the body as application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded; see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"This deployment lacks a key the provider needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"A provider or upstream API failed or is unreachable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"Deadline exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}