# MCP Server Source: https://docs.ravn.exchange/ai-agents/mcp-server Connect Claude, Cursor, or any MCP client to RAVN's quote/execute/status loop, free, no API key required. RAVN runs a [Model Context Protocol](https://modelcontextprotocol.io) server that exposes the Integrator API as native tools. Point any MCP-speaking client at it, and your agent can discover and call RAVN without you writing any HTTP glue code. **Endpoint:** `https://app.ravn.exchange/api/mcp` **Transport:** Streamable HTTP **Auth:** None required. Every tool works anonymously; pass your own API key as the optional `apiKey` argument on any tool for a higher rate limit (see [Authentication](/authentication)). **Cost:** Free. These tools call the same free `/v1/*` endpoints as the REST API, not the paid [x402 endpoints](/ai-agents/x402-payments). Sanity-checking the endpoint with `curl` or a browser? A plain `GET` returns `405 Method Not Allowed`, which is expected, not broken. Streamable HTTP MCP servers only speak `POST`; use an MCP client to actually call it. One click, no config file editing. Opens Claude.ai's "Add custom connector" dialog with RAVN's name and endpoint pre-filled, so you just review and confirm. One click from a machine with Cursor installed. Opens Cursor's MCP install dialog with RAVN's name and endpoint pre-filled. No equivalent deep link exists for Codex CLI yet. It only supports `codex mcp add` for local (stdio) servers, and remote HTTP servers like RAVN's have to go in `config.toml` by hand. See the Codex tab below. ## Connect a client ```json Claude Desktop / Claude Code (claude_desktop_config.json / .mcp.json) theme={null} { "mcpServers": { "ravn": { "url": "https://app.ravn.exchange/api/mcp" } } } ``` ```json Cursor (.cursor/mcp.json) theme={null} { "mcpServers": { "ravn": { "url": "https://app.ravn.exchange/api/mcp" } } } ``` ```toml Codex CLI (~/.codex/config.toml) theme={null} [mcp_servers.ravn] url = "https://app.ravn.exchange/api/mcp" auth = "none" ``` Any client that supports remote MCP servers over Streamable HTTP works the same way; there's nothing to install locally. ## Try it: one prompt, one loop With the config above added, prompt your client with something like: > Swap 0.01 ETH on Ethereum to USDC on Base for 0x1234...5678, my wallet address. A capable MCP client resolves that into: 1. `ravn_quote({ inputChainId: 1, outputChainId: 8453, inputToken: "0xEeee...EEeE", outputToken: "", inputAmount: "10000000000000000", userAddress: "0x1234...5678" })` → returns a `quoteToken` plus the priced route. 2. `ravn_execute({ quoteToken })` → returns `{ executionType: "TRANSACTION", transaction: {...} }` for this route (0x Gasless/RFQ-style routes instead return `SIGNATURE`). 3. Your agent signs and sends the returned `transaction` with its own wallet; RAVN never touches it. 4. `ravn_status({ quoteToken, ref: })`, polled until `status` is terminal (`success`, `refunded`, or `failed`). No other setup, no API key, no payment. See [Execution Types](/execution-types) for what `transaction` looks like for each `executionType`, and [Signing: who holds the wallet?](/ai-agents/overview#signing-who-holds-the-wallet) for how an autonomous agent handles step 3 without a human clicking "confirm." ## Tools ### `ravn_quote` Get a swap quote, same-chain or cross-chain, across all 16 supported chains including native Bitcoin and Solana as source or destination. Returns a `quoteToken` to pass to `ravn_execute`, plus an `executable` flag: false means the quote is a preview only, priced against a placeholder address rather than the ones you supplied (or didn't), and `ravn_execute` will reject it with `QUOTE_NOT_EXECUTABLE`. | Argument | Type | Required | Notes | | -------------------- | ------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `inputChainId` | number | yes | See [chain IDs](#chain-ids) below | | `outputChainId` | number | yes | | | `inputToken` | string | yes | Contract address, or `0xEeee…EEeE` for the chain's native coin | | `outputToken` | string | yes | | | `inputAmount` | string | yes | Positive integer, in the input token's smallest unit (no decimals) | | `userAddress` | string | yes | Address the input asset will be sent from | | `destinationAddress` | string | no | Where output should land, if different from `userAddress`. Required here to get an executable quote from Relay (Bitcoin as the source), THORChain (Bitcoin either direction), Across (a Solana-touching route), or Eco (a cross-ecosystem route); omit it there and `executable` comes back false instead of an error | | `refundAddress` | string | no | Required here for a Bitcoin-source Relay or THORChain quote, for the same reason as `destinationAddress` | | `slippageBps` | number | no | 1 to 5000 | | `rankingMode` | `"best_output"` \| `"fastest"` | no | Defaults to `best_output` | | `apiKey` | string | no | Your RAVN API key, if you have one | ### `ravn_execute` Turn a `quoteToken` from `ravn_quote` into an execution payload. | Argument | Type | Required | Notes | | -------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `quoteToken` | string | yes | | | `destinationAddress` | string | no | Late-bound recipient, for a venue that didn't have it yet at quote time. Does not apply to Relay, Across, Eco, or THORChain, which commit it at quote time and ignore a different value here; supply it on `ravn_quote` for those | | `refundAddress` | string | no | Late-bound refund address, same idea as `destinationAddress`. Does not apply to a Bitcoin-source Relay or THORChain quote | | `apiKey` | string | no | | Returns one of three shapes, tagged by `executionType`: * **`TRANSACTION`**: sign and broadcast yourself * **`SIGNATURE`**: sign, RAVN submits on your behalf * **`DEPOSIT`**: send the input asset to a given address (the common case for Bitcoin-source swaps; see `ravn_btc_prepare_send` below) RAVN never takes custody of funds under any of the three; you always sign or send from your own wallet. ### `ravn_status` Poll a swap's status. | Argument | Type | Required | Notes | | ------------ | ------ | -------- | ------------------------------------------------------------------------------------------- | | `quoteToken` | string | yes | | | `ref` | string | yes | Deposit address (`DEPOSIT` venues) or `statusRef` (`SIGNATURE` venues), from `ravn_execute` | | `apiKey` | string | no | | Status is authoritative where the venue exposes it. A few venues (Jupiter, Bebop, 0x Gasless) report `"unknown"` honestly rather than guessing. Check the response's `tracking` field. ### `ravn_health` No arguments. Liveness check across every venue RAVN routes through, useful to call before a swap if you want to know whether a route is degraded ahead of time. ### `ravn_btc_prepare_send` Turns a `DEPOSIT`-type `ravn_execute` result into a ready-to-sign Bitcoin transaction (a PSBT), so your agent doesn't have to implement UTXO selection or fee estimation itself. | Argument | Type | Required | Notes | | ------------------ | -------------------------- | -------- | -------------------------------------------------------------------------------------------------- | | `fromAddress` | string | yes | Your Bitcoin address holding the UTXOs to spend; native SegWit (`bc1q…`) or Taproot (`bc1p…`) only | | `toAddress` | string | yes | The `depositAddress` from `ravn_execute` | | `amountSats` | string | yes | The `depositAmount` from `ravn_execute`, in satoshis | | `feeRateSatsPerVb` | number | no | Omit to use mempool.space's current fee estimate | | `network` | `"mainnet"` \| `"testnet"` | no | Defaults to `mainnet` | UTXOs and the fee rate are fetched from the public [mempool.space](https://mempool.space) API, with no keys and no auth required. RAVN never sees or handles a private key at any point. The response is an unsigned PSBT (`psbtBase64`): sign it with your own wallet's key and broadcast it yourself. Only one signature is ever needed. Every RAVN Bitcoin-source venue (Garden, Chainflip, NEAR Intents) resolves to a plain, single-recipient payment, not a multi-wallet UTXO-co-signing ceremony some other aggregators require for their BTC routes. ## Chain IDs | Chain | ID | | Chain | ID | | ----------- | ---- | - | --------------- | ------ | | Ethereum | 1 | | Robinhood Chain | 4663 | | Optimism | 10 | | **Bitcoin** | **-1** | | BNB Chain | 56 | | **Solana** | **-2** | | Unichain | 130 | | Monad | 143 | | Polygon | 137 | | HyperEVM | 999 | | zkSync | 324 | | Arbitrum | 42161 | | World Chain | 480 | | Linea | 59144 | | Base | 8453 | | Avalanche | 43114 | Bitcoin and Solana use negative sentinel IDs rather than their (non-existent, in Bitcoin's case) EVM chain IDs. Don't assume 0 or a positive placeholder. ## A full loop, end to end 1. `ravn_quote`: get a `quoteToken` 2. `ravn_execute`: get back `TRANSACTION` / `SIGNATURE` / `DEPOSIT` * If `DEPOSIT` and the input asset is Bitcoin: `ravn_btc_prepare_send` → sign the PSBT with your own wallet → broadcast * Otherwise: sign/send with your own wallet per the returned payload 3. `ravn_status`: poll until terminal # AI Agents Source: https://docs.ravn.exchange/ai-agents/overview Three ways for an AI agent to swap through RAVN: a free MCP server, pay-per-call x402 endpoints, or the plain REST API. RAVN quotes and executes swaps across 16 chains, including **native Bitcoin**, not wrapped BTC, as a source or destination asset. Everything below sits on top of the same [Integrator API](/api-reference/overview) (`/api/v1/quote`, `/api/v1/execute`, `/api/v1/status`): same fields, same fees (0% on every route), same DTOs. Pick whichever access pattern fits your agent. ## Three ways in | | No signup | Native tool-calling | Cost | | --------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------- | | **[MCP Server](/ai-agents/mcp-server)** | Yes | Yes: Claude, Cursor, and any MCP client discover it natively | Free | | **[x402 payments](/ai-agents/x402-payments)** | Yes | Depends on your agent's HTTP stack | $0.001 to $0.01/call | | **[REST API](/api-reference/overview)** | Yes (anonymous, rate-limited), or [get a free key](/tools/get-api-key) | You call it yourself | Free | All three hit the same underlying swap logic. There's no "agent tier" with worse pricing or routing than the human-facing app: an agent calling the MCP server for free gets exactly the same quote a retail user gets on ravn.exchange. ## Which one should I use? * **Building on Claude, Cursor, or another MCP-native agent?** Use the [MCP server](/ai-agents/mcp-server): point your client at one URL, and you're done. No API key needed. * **Your agent already speaks x402** (e.g. wraps `fetch` with an x402 client) and would rather pay per call than manage a key? Use [x402 payments](/ai-agents/x402-payments). * **Writing your own HTTP client, or need endpoints x402/MCP don't cover?** Use the [REST API](/api-reference/overview) directly. ## Signing: who holds the wallet? `execute` can return `TRANSACTION` or `SIGNATURE`, and both require a signature RAVN never produces for you (see [Execution Types](/execution-types)). For a human-facing dapp that's a wallet popup; for an autonomous agent, it's a design decision you make once, not per swap: * **Local key in the agent's own environment.** Simplest: the agent process holds a private key (env var, secrets manager) and signs directly with a library like `viem` or `web3.js`. Fine for a sandboxed or self-custodied agent; the key is a standing secret like any server-side key. * **Human-in-the-loop approval.** The agent calls `quote`/`execute`, then hands the returned `transaction` or `typedData` to a human (or a wallet app like MetaMask/Phantom) to review and sign before anything broadcasts. Slower, but nothing moves without a person confirming it. * **TEE or custody-agent signing.** The private key never enters the agent's own process; it lives in a secure enclave or a custody service (e.g. a CDP-managed wallet, Turnkey, Privy) that the agent calls out to for a signature. Keeps the agent stateless with respect to funds. `DEPOSIT`-type results (the common case for Bitcoin-source swaps) sidestep this: there's no typed data to sign, just a plain transfer to an address, and RAVN's own [`ravn_btc_prepare_send`](/ai-agents/mcp-server#ravn_btc_prepare_send) tool builds that transaction for you. ## Receiving real Bitcoin If your agent's swap resolves to a Bitcoin deposit (`executionType: "DEPOSIT"` from `ravn_execute`), it still needs to actually send that payment. See [`ravn_btc_prepare_send`](/ai-agents/mcp-server#ravn_btc_prepare_send), which turns the deposit address and amount into a ready-to-sign transaction, so your agent doesn't need to write its own Bitcoin coin-selection logic. RAVN never sees or holds a private key at any point. # x402 Payments Source: https://docs.ravn.exchange/ai-agents/x402-payments Pay-per-call access to RAVN's quote and execute endpoints, no API key, no signup, priced in USDC. RAVN's quote and execute endpoints are also available over [x402](https://www.x402.org): pay a small amount of USDC per request instead of managing an API key. This is a second, parallel door into the same swap logic as the [free REST API](/api-reference/overview); it doesn't replace the free tier, which still requires no payment at all. If you're building on Claude, Cursor, or another MCP client, the [MCP server](/ai-agents/mcp-server) is free and simpler; there's no reason to pay for the same tool call. x402 is for agents that can't or don't want to hold a long-lived credential at all: * **No key to provision, rotate, or leak.** Nothing to store server-side; a compromised agent process has no standing secret to revoke. * **Spend is capped per call, not per key.** Each payment authorizes exactly one request for exactly the price quoted; there's no API key that, once leaked, keeps working until someone notices and rotates it. * **The payment itself is the audit trail.** Every call settles on-chain (Base or Solana), so usage is independently verifiable without RAVN-side logging or an API dashboard. * **Discoverable by other agents, not just yours.** RAVN's x402 routes are indexed in Coinbase's x402 Bazaar catalog (the search and merchant-lookup API behind [agentic.market](https://agentic.market)) and listed on [x402scan.com](https://x402scan.com), so agents that discover services by querying that catalog directly can find and call RAVN without being told about it in advance. Whether RAVN also appears in agentic.market's own curated marketplace UI is a separate, usage-driven decision on their end, not something indexing alone guarantees. The free REST/MCP doors aren't part of the Bazaar catalog at all. If none of that matters for your use case, the free REST API or MCP server does the same swap logic for nothing. ## Endpoints | Endpoint | Price | Same contract as | | ---------------------------------------------------- | ------- | -------------------------------------------- | | `POST https://app.ravn.exchange/api/v1/x402/quote` | \$0.001 | [`POST /v1/quote`](/api-reference/quote) | | `POST https://app.ravn.exchange/api/v1/x402/execute` | \$0.01 | [`POST /v1/execute`](/api-reference/execute) | Only quote and execute are metered over x402. `status` and `health` aren't priced endpoints and have no `/x402/` counterpart: call [`GET /v1/status`](/api-reference/status) and [`GET /v1/health`](/api-reference/health) directly (free, no key) once you've paid to execute. Request and response bodies are identical to the free endpoints: same fields, same DTOs, same error codes. The `quoteToken` from `/v1/x402/quote` works interchangeably with either `/v1/execute` or `/v1/x402/execute`: you can get a free quote and only pay to execute, if you want. The price is a flat access fee for the API call itself; it is **not** RAVN's swap fee, which stays 0% on every route regardless of which door you come through. ## Accepted payment | Network | Asset | | ---------------- | ----- | | Base (mainnet) | USDC | | Solana (mainnet) | USDC | ## How it works x402 repurposes the HTTP `402 Payment Required` status code: 1. Call the endpoint with no payment attached. 2. RAVN responds `402` with a `payment-required` header describing accepted payment options (network, asset, amount, recipient). 3. Your x402 client signs a payment (an EIP-3009 USDC authorization on Base, or a Solana USDC transfer) and retries the request with a `payment-signature`-style header attached. 4. RAVN verifies and settles the payment via its facilitator, then executes your original request and returns the normal response. Most x402 client libraries handle steps 2 and 3 automatically once wrapped around `fetch`. Debugging step 2 by hand? The `402` response body is an empty `{}`, which is correct, not a bug. The actual payment terms are in the `payment-required` response header (base64-encoded), not the body. Decode that header to see accepted networks, assets, and amounts. ## Example ```javascript theme={null} import { wrapFetchWithPayment, x402Client } from "@x402/fetch"; import { ExactEvmScheme, toClientEvmSigner } from "@x402/evm"; const core = new x402Client(); core.register("eip155:*", new ExactEvmScheme(toClientEvmSigner(yourEvmWalletClient))); const x402Fetch = wrapFetchWithPayment(fetch, core); const res = await x402Fetch("https://app.ravn.exchange/api/v1/x402/quote", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ inputChainId: 1, outputChainId: 8453, inputToken: "0xEeeeeEeeeEeEeeEeEeEeeeEEeeeeEeeeeeeeEEeE", outputToken: "0xEeeeeEeeeEeEeeEeEeEeeeEEeeeeEeeeeeeeEEeE", inputAmount: "1000000000000000000", userAddress: "0xYourAddress", }), }); const { data } = await res.json(); // includes quoteToken ``` Swap in a Solana signer (`@x402/svm`) to pay from a Solana wallet instead. ## Errors Same [error envelope](/errors) as the rest of the Integrator API. One addition: | Code | HTTP status | Meaning | | ---------------- | ----------- | ---------------------------------------------------------------------------------------------------- | | `NOT_CONFIGURED` | 503 | x402 payments aren't currently enabled; use the [free endpoints](/api-reference/overview) instead | | `NOT_FOUND` | 404 | No such route: only `/x402/quote` and `/x402/execute` exist; everything else is REST-only, see above | # GET /tokens/btc-coverage Source: https://docs.ravn.exchange/api-reference/btc-coverage Which tokens on a chain actually route from native Bitcoin. For a swap where native BTC is the **source**, not every token on the destination chain is reachable. This returns which of RAVN's listed tokens on `chainId` a BTC venue can actually route to, and how many venues serve each, so you can build a token list that matches what will really quote instead of discovering it one failed `NO_LIQUIDITY` at a time. BTC-as-source only. Selling a token **into** BTC isn't restricted the same way (nearly any token can be sold into BTC), so this endpoint has nothing useful to say about that direction. ## Request The destination chain to check coverage on. No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s "https://app.ravn.exchange/api/v1/tokens/btc-coverage?chainId=8453" ``` ## Response Echoes the requested chain. False means the upstream venue lists couldn't be reached right now, so `coverage` is empty and the answer is unknown, not "nothing routes." Treat this the same way you'd treat an outage: show your full token list rather than let it look like zero coverage. Lowercased token address to the number of BTC venues (1 to 3) that route to it. Tokens no venue serves are omitted entirely, not listed at 0. ```json theme={null} { "data": { "chainId": 8453, "filtered": true, "coverage": { "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": 2, "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": 2, "0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf": 2 } } } ``` Higher counts are the safer bet: a token two or three venues cover is more likely to keep routing if one venue has an outage. Rank your token list by count, the same way RAVN's own picker does. # POST /execute Source: https://docs.ravn.exchange/api-reference/execute Turn a quote into an actionable execution payload. Takes the opaque `quoteToken` from [`/quote`](/api-reference/quote) and returns one of three shapes tagged by `executionType`. See [Execution Types](/execution-types) for the branch logic. ## Request The opaque token from `/quote`. Late-bound recipient, for a venue that didn't have it yet at quote time. Does **not** apply to Relay, Across, Eco, or THORChain: those commit the recipient at quote time and silently ignore a different value here instead of erroring, so supply it on [`/quote`](/api-reference/quote) for those. Late-bound refund address, same idea as `destinationAddress` above. Does **not** apply to a Bitcoin-source Relay or THORChain quote, both of which commit it at quote time. No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s -X POST https://app.ravn.exchange/api/v1/execute \ -H 'content-type: application/json' \ -d '{ "quoteToken": "" }' ``` ## Response One of three payloads: ```json TRANSACTION theme={null} { "executionType": "TRANSACTION", "approval": { "to": "0x…", "data": "0x095ea7b3…", "value": "0", "chainId": 1 }, "transaction": { "to": "0x…", "data": "0x…", "value": "0", "chainId": 1 } } ``` ```json SIGNATURE theme={null} { "executionType": "SIGNATURE", "approval": { "to": "0x…", "data": "0x095ea7b3…", "value": "0", "chainId": 1 }, "typedData": { }, "approvalData": { }, "submit": { "url": "/api/v1/submit-signature" } } ``` ```json DEPOSIT theme={null} { "executionType": "DEPOSIT", "deposit": { "address": "0x…", "amount": "1000000000000000000", "chainId": 1 }, "statusRef": "0x…" } ``` `approval` appears on `TRANSACTION` and `SIGNATURE` when the input ERC-20 needs an allowance. On `TRANSACTION`, send it and wait for it to be **mined** before `transaction`, or the swap reverts on `transferFrom`. On `SIGNATURE` (CoW, Bebop), land it before submitting or the order is accepted and silently never fills. See [Execution types](/execution-types#the-approval-step). Returns `410 QUOTE_EXPIRED` if the quote has expired, `400 QUOTE_INVALID` if the token is malformed or tampered with, or `400 QUOTE_NOT_EXECUTABLE` if the quote was a preview only (`executable: false` on [`/quote`](/api-reference/quote)). Request a fresh quote and retry in every case. # GET /health Source: https://docs.ravn.exchange/api-reference/health Per-venue liveness. Reports overall status plus each venue's health, so you can surface degraded routing. It always returns `200`, so read the `status` field rather than the HTTP code to gate. This endpoint is public and needs no key. ```bash theme={null} curl -s https://app.ravn.exchange/api/v1/health ``` ## Response Either `ok` or `degraded`. An array of `{ id, name, healthy }`, one per venue. ```json theme={null} { "data": { "status": "ok", "venues": [ { "id": "cow", "name": "CoW Protocol", "healthy": true }, { "id": "near_intents", "name": "NEAR Intents", "healthy": true } ] } } ``` # OpenAPI spec Source: https://docs.ravn.exchange/api-reference/openapi Machine-readable spec for every endpoint above, importable into Postman, Insomnia, or any agent framework's tool loader. The full OpenAPI 3.1 document behind this reference, covering all 8 REST endpoints plus the paid x402 variants. ``` https://app.ravn.exchange/openapi.json ``` Point Postman's or Insomnia's "Import from URL" at it, or hand the URL to any agent framework that loads tools from an OpenAPI spec, so no manual schema-writing is needed on your end. ```bash theme={null} curl -s https://app.ravn.exchange/openapi.json | jq . ``` # Overview Source: https://docs.ravn.exchange/api-reference/overview The RAVN Integrator API surface. Base URL: `https://app.ravn.exchange/api/v1` Prefer to import this into Postman, Insomnia, or an agent framework's tool loader? Full spec at [`/openapi.json`](/api-reference/openapi). Best-priced route + an opaque quoteToken. Turn a quoteToken into an execution payload. Submit a signed order for SIGNATURE venues. Normalized swap status. Resolve any token address to metadata. Which tokens actually route from native BTC. Per-venue liveness. ## Conventions * **Envelope:** `{ data, meta }` on success, `{ error: { code, message, details? }, meta }` on failure. * **Headers:** every response carries `x-request-id` and `ravn-version`. * **Amounts:** strings, in the token's smallest unit. * **Native coin:** the sentinel `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` (Solana native SOL: mint `So1111…1112`). ## Chain IDs | Chain | ID | Chain | ID | | ----------- | --- | ----------- | ------ | | Ethereum | 1 | Base | 8453 | | Optimism | 10 | Arbitrum | 42161 | | BNB Chain | 56 | Linea | 59144 | | Unichain | 130 | Avalanche | 43114 | | Polygon | 137 | Robinhood | 4663 | | zkSync | 324 | Monad | 143 | | World Chain | 480 | **Bitcoin** | **-1** | | HyperEVM | 999 | **Solana** | **-2** | # POST /quote Source: https://docs.ravn.exchange/api-reference/quote Get the best-priced route for a swap. Shops every eligible venue and returns the best price plus an opaque `quoteToken` to pass to [`/execute`](/api-reference/execute). ## Request Origin chain ID. Destination chain ID. Contract address or mint, or the native sentinel. Contract address or mint, or the native sentinel. Positive integer in the token's smallest unit. The sender's address. Recipient on the destination chain. Some venues need this here, at quote time, to return a firm, executable quote at all: notably Relay when Bitcoin is the *source*, THORChain on a Bitcoin route either direction, Across on a Solana-touching route, and Eco on a cross-ecosystem route. Omit it on those and you get back a priced but unexecutable preview instead (see `executable` below), not an error. Most other venues also accept it as a late addition on `/execute`, but Relay, Across, Eco, and THORChain commit the recipient at quote time regardless and ignore a different value supplied later rather than erroring, so supply the real address here whenever you have it. Where the input asset is refunded if the swap fails. A Bitcoin-source Relay or THORChain quote both require this here, at quote time, for the same reason as `destinationAddress` above. Garden and Chainflip accept it as a late addition on `/execute` instead. 1 to 5000. Omit for the venue default. `best_output` (default) or `fastest`. `best_output` is the literal highest net output, full stop. `fastest` picks the quickest-settling quote among quotes within `slippageBps`, even at a real output cost. No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s -X POST https://app.ravn.exchange/api/v1/quote \ -H 'content-type: application/json' -d '{ "inputChainId": -2, "outputChainId": 1, "inputToken": "So11111111111111111111111111111111111111112", "outputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "inputAmount": "100000000000", "userAddress": "SoYourUser", "destinationAddress": "0xYourUser" }' ``` ## Response Opaque handle. Pass it to `/execute` verbatim and do not parse it. It expires. The `id` and `name` of the winning venue. For example, `CROSS_ECOSYSTEM` or `EVM_CROSS_CHAIN`. The input `token` and `amount`. The output `token` and expected `amount`. The applied integrator fee, with `bps`, `amount`, and `token`. False means this is a preview only, priced against a placeholder destination or refund address rather than the ones you supplied (or didn't). Posting `quoteToken` to `/execute` in that state fails with `400 QUOTE_NOT_EXECUTABLE`. Request a fresh quote with the missing address instead of retrying `/execute`. The `bps`, `isFirm`, and `guaranteedMin`, or null. Native gas the user must hold: `native`, `nativeSymbol`, `usd`, and `estimated`. Null on gasless venues. True when the venue didn't report a timing figure for this quote, so `estimatedTimeSeconds` is a generic placeholder rather than a venue-reported number. Epoch milliseconds when the quote expires. ```json theme={null} { "data": { "quoteToken": "...opaque...", "venue": { "id": "near_intents", "name": "NEAR Intents" }, "routeType": "CROSS_ECOSYSTEM", "input": { "token": { }, "amount": "100000000000" }, "output": { "token": { }, "amount": "18985000" }, "fee": { "bps": 0, "amount": "0", "token": { } }, "executable": true, "estimatedTimeSeconds": 42, "estimatedTimeIsGuess": false, "expiresAt": 1750000000000 } } ``` Returns `404 NO_LIQUIDITY` when no venue can serve the pair or amount. # GET /status Source: https://docs.ravn.exchange/api-reference/status Normalized swap status. Poll the progress of a swap. The `ref` is the `statusRef` returned by [`/execute`](/api-reference/execute) for a DEPOSIT, or by [`/submit-signature`](/api-reference/submit-signature) for a SIGNATURE. ## Request The opaque token from `/quote`. The `statusRef` for this swap. No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s "https://app.ravn.exchange/api/v1/status?quoteToken=&ref=" ``` ## Response The normalized lifecycle state. The venue handling the swap. The raw, venue-native status string behind the normalized `status`, for debugging. Present once a venue has been polled. Present as `"unavailable"` only when the venue is not yet wired for tracking (`status` is `unknown`). Absent otherwise. | `status` | Meaning | | ------------ | ------------------------------------------------------------------------------------ | | `pending` | Awaiting the deposit, or not yet observed | | `processing` | Funds received, solver filling | | `success` | Delivered | | `expired` | The fill deadline passed without a fill; a refund is due but has not yet been issued | | `refunded` | Returned to sender | | `failed` | Terminal failure | | `not_found` | The `ref` is unknown to the venue | | `unknown` | The venue is not yet wired for tracking | ```json theme={null} { "data": { "status": "processing", "venue": "near_intents" } } ``` Status tracking is live today for CoW, NEAR Intents, Relay, Across, Mayan, Eco Routes, Garden, Chainflip, and THORChain. Jupiter, Bebop, and 0x Gasless aren't wired yet and return a `status` of `unknown` with `tracking: "unavailable"`. The response shape is stable regardless, so each venue is a drop-in as it's added. **Keep polling on `expired`.** It is **not** a terminal state. It means the deal lapsed and a refund is owed but has not landed yet. On Across, the deposit is returned to the sender on the origin chain roughly 90 minutes later, at which point the status becomes `refunded`. Treat only `success`, `refunded`, and `failed` as terminal; stopping at `expired` will miss the refund. # POST /submit-signature Source: https://docs.ravn.exchange/api-reference/submit-signature Submit a signed order for SIGNATURE venues. Use this for `SIGNATURE`-type venues (0x Gasless, Bebop, CoW, Relay's gasless permit path). Sign the `typedData` from [`/execute`](/api-reference/execute), then post the signature here. RAVN routes it to the correct venue, including any venue-specific quirks in how the signature is submitted, so you never touch per-venue endpoints. ## Request The same opaque token from `/quote`. Your 65-byte hex signature over `typedData`. A signature over `approvalData`, when `/execute` returned it (0x Gasless). No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s -X POST https://app.ravn.exchange/api/v1/submit-signature \ -H 'content-type: application/json' \ -d '{ "quoteToken": "", "signature": "0x..." }' ``` ## Response The handle to poll [`/status`](/api-reference/status) with. The venue the order was submitted to. ```json theme={null} { "data": { "statusRef": "0x...orderUid", "venue": "cow" } } ``` # GET /tokens/resolve Source: https://docs.ravn.exchange/api-reference/tokens Resolve any token address to metadata. Resolve an arbitrary token address to its metadata (symbol, name, decimals) via an on-chain read. Lets you support paste-any-address flows. ## Request The chain to resolve on. The token contract address / mint. No API key required (see [Authentication](/authentication) for the optional higher-limit tiers). ```bash theme={null} curl -s "https://app.ravn.exchange/api/v1/tokens/resolve?chainId=1&address=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ``` ## Response ```json theme={null} { "data": { "token": { "symbol": "USDC", "name": "USD Coin", "address": "0xA0b8…eB48", "decimals": 6, "chainId": 1, "isNative": false } } } ``` Returns `400 UNSUPPORTED_TOKEN` if the address isn't a valid token on that chain. # Authentication Source: https://docs.ravn.exchange/authentication API keys, fees, and rate limits. **[Get a key.](/tools/get-api-key)** Instant, no review, 30 seconds. It 4x's your rate limit (30 → 120 req/min) and puts your project on RAVN's radar, worth having if you want a partnership or a rev-share deal down the line. No key required to start if you just want to poke around: every endpoint works with no `x-api-key` header at all, so you can make your first call right now. `GET /health` is always public regardless of tier. ## Calling from a browser **CORS is enabled on every endpoint**, so a wallet widget, dapp frontend, or any other browser-side integration can call the API directly, with no server-side proxy required. `x-request-id` and `ravn-version` are exposed via `Access-Control-Expose-Headers`, so your client-side code can read them. Quote `x-request-id` if you ever report a bad quote to us; it is how we find your exact request. Because your key travels to the browser in that setup, treat a client-side key as public. It only ever raises a rate limit and carries no spending authority (RAVN never takes custody, and every swap is still signed by the user's own wallet), but rotate it like any other public credential, or keep it server-side and proxy if you would rather not expose it at all. There are three tiers: | Tier | How to get it | Rate limit | Identity | | -------------- | -------------------------------------------------------- | ------------------ | ------------------ | | No key | Nothing, just call the API | 30 req/min, per IP | Anonymous | | Self-serve key | [Get an API key](/tools/get-api-key), instant, no review | 120 req/min | Named, by project | | Enterprise key | Reach out to RAVN directly | Custom | Named, custom deal | To use a self-serve or enterprise key, pass it in the `x-api-key` header: ``` x-api-key: rvn_live_your_key_here ``` A key that doesn't match either store returns `401 UNAUTHORIZED`. Exceeding your tier's limit returns `429 RATE_LIMITED`, with a `retryAfterSec` value in `details`. RAVN charges 0 bps by default, on every route, for every tier, self-serve or enterprise. Full route table, quote `fee` object, and how this differs from optional x402 call fees: see [Pricing](/pricing). ## Enterprise partnerships Building something that needs a custom rate limit or a dedicated fee arrangement, or just want to work closely with the RAVN team? DM [@ravnexchange](https://x.com/ravnexchange) on X or reach out via [ravn.exchange](https://ravn.exchange); include a word on what you're building so we can set your limits. # Errors Source: https://docs.ravn.exchange/errors Predictable, machine-readable error codes. Failures return `{ error: { code, message, details? }, meta }`. Branch on the stable `code`, because the human-readable `message` may change. | Code | HTTP | Meaning | | ---------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `INVALID_REQUEST` | 400 | The body or params failed validation. The `details` field lists the fields. | | `UNSUPPORTED_TOKEN` | 400 | The token is not resolvable on that chain. | | `UNSUPPORTED_CHAIN` | 400 | The chain ID isn't one RAVN supports. | | `NO_LIQUIDITY` | 404 | No venue could quote this pair or amount. | | `QUOTE_EXPIRED` | 410 | The `quoteToken` is past expiry. Request a new quote. | | `QUOTE_INVALID` | 400 | The `quoteToken` is malformed or tampered. | | `QUOTE_NOT_EXECUTABLE` | 400 | The `quoteToken` decodes fine but is a preview only (`executable: false` on the quote). Request a fresh quote with the missing destination or refund address. | | `RATE_LIMITED` | 429 | Your tier's rate limit was exceeded (see [Authentication](/authentication)). | | `UNAUTHORIZED` | 401 | A presented `x-api-key` doesn't match any known key. No key at all is fine, that's the anonymous tier. | | `INTERNAL` | 500 | An unexpected or venue-side error occurred. | ```json theme={null} { "error": { "code": "NO_LIQUIDITY", "message": "No liquidity available for this pair/amount" }, "meta": { "requestId": "6b50...19e", "version": "2024-01" } } ``` Always log the `requestId` from `meta`, which is also in the `x-request-id` header. Include it when you contact support and we can trace the exact request. # Execution Types Source: https://docs.ravn.exchange/execution-types The one field your integration branches on. RAVN spans three execution models. `POST /execute` returns exactly one of them, tagged by `executionType`. Your integration reads that single field and branches. Nothing else about the flow changes. Sign and broadcast the returned transaction.
**Across, Relay, Mayan, Jupiter, Eco Routes, Garden, THORChain, Bebop (self-executed)**
Sign typed data, with no gas and no send. RAVN submits it.
**0x Gasless, Bebop (gasless), CoW, Relay (gasless permit)**
Send the origin asset to an address.
**NEAR Intents, Chainflip, Relay (BTC source), Garden (BTC source)**
A few venues return different types depending on the source chain or execution mode. See the `Execution` column on [Supported Chains & Venues](/supported) for exactly which. ## The payloads ```json TRANSACTION theme={null} { "executionType": "TRANSACTION", "approval": { "to": "0x...", "data": "0x095ea7b3...", "value": "0", "chainId": 1 }, "transaction": { "to": "0x...", "data": "0x...", "value": "0", "chainId": 1 } } ``` ```json SIGNATURE theme={null} { "executionType": "SIGNATURE", "approval": { "to": "0x...", "data": "0x095ea7b3...", "value": "0", "chainId": 1 }, "typedData": { }, "approvalData": { }, "submit": { "url": "/api/v1/submit-signature" } } ``` ```json DEPOSIT theme={null} { "executionType": "DEPOSIT", "deposit": { "address": "0x...", "amount": "1000000000000000000", "chainId": 1 }, "statusRef": "0x..." } ``` ## Branch logic ```js theme={null} switch (res.data.executionType) { case "TRANSACTION": { if (res.data.approval) { const hash = await wallet.sendTransaction(res.data.approval); await wallet.waitForTransactionReceipt({ hash }); // must be mined first } await wallet.sendTransaction(res.data.transaction); break; } case "SIGNATURE": { // Gasless still needs an allowance. Without it the order never fills, silently. if (res.data.approval) { const hash = await wallet.sendTransaction(res.data.approval); await wallet.waitForTransactionReceipt({ hash }); } const sig = await wallet.signTypedData(res.data.typedData); await submitSignature(quoteToken, sig); break; } case "DEPOSIT": await wallet.send(res.data.deposit.address, res.data.deposit.amount); break; } ``` ### The `approval` step Both `TRANSACTION` and `SIGNATURE` payloads can carry an optional `approval`, a ready-to-send ERC-20 `approve()` call. ```json theme={null} "approval": { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // the TOKEN contract "data": "0x095ea7b3…", // encoded approve(spender, amount) "value": "0", "chainId": 8453, "spender": "0x337685fdaB40D39bd02028545a4FfA7D287cC3E2", "amount": "25000000", "unlimitedRecommended": true // optional, see below } ``` | When it appears | When it does not | | -------------------------------------------------------------- | --------------------------------------- | | Selling an ERC-20 that needs an allowance for this venue | Selling a native coin (ETH, BNB, AVAX…) | | Gasless venues too (they still pull tokens via `transferFrom`) | Native BTC or SOL as the input | | | `DEPOSIT` routes | **On `TRANSACTION`:** send `approval`, wait for it to be **mined**, then send `transaction`. The swap moves your tokens with `transferFrom`, so an allowance that is merely broadcast, and not yet in a block, still reverts, and the user pays gas for a failed transaction. **On `SIGNATURE`:** land the allowance before you submit the signed order. Gasless does not mean allowance-free: CoW settles through its vault relayer and Bebop through Permit2. Skip it and the order is accepted and then **silently never fills**, with no error to debug. Read the on-chain allowance for `spender` first and skip the approval when it already covers `amount`. RAVN does not check the chain for you, so `approval` can be present on a token you have already approved. `unlimitedRecommended: true` means the venue would rather you approve once for a large amount than per swap. It is set for CoW, whose relayer needs an on-chain allowance for every token regardless, so an exact approval costs gas on every single swap and cancels out the gasless route. `data` still encodes the exact `amount`; raising it to an unlimited approval is your call. Both work. Do not assume the spender is `transaction.to`, and do not decode the `quoteToken` to find it. The `quoteToken` is opaque and its internals change without notice. If `approval` is absent, no allowance is needed. A `DEPOSIT` can be fulfilled automatically, by building a wallet transfer to the address as an EVM or Solana wallet does, or manually, by showing the address and a QR code as a native-BTC send does. Both are the same execution type, so you choose the UX. # FAQ Source: https://docs.ravn.exchange/faq Common questions about the RAVN Integrator API. No. RAVN routes only through RFQ market makers, intent networks, and solver and relayer networks that settle in the canonical asset. There is never a lock-and-mint bridge, wrapped token, or synthetic. No. The user signs or sends directly to the venue, and RAVN never holds funds. See the [Security Model](/security). No, but get one anyway. Every call works with no `x-api-key` header, rate-limited by IP, but [a free key](/tools/get-api-key) takes 30 seconds, no review, and instantly quadruples your limit, plus it puts your project on RAVN's radar for a future partnership or rev-share deal. See [Authentication](/authentication). RAVN charges 0 bps on every route, for every integrator, by default. The `fee` object still appears on every quote; it just always reports 0. See [Pricing](/pricing) for the route table and how optional x402 call fees differ from the swap fee. An opaque, signed handle returned by `/quote`. Pass it back to `/execute` verbatim, and never parse it. It is tamper-evident and it expires. Branch on the `executionType` field from `/execute`. The values are `TRANSACTION` (sign and broadcast), `SIGNATURE` (sign typed data, then RAVN submits it), and `DEPOSIT` (send the origin asset to an address). That single field is the whole client contract. See [Execution Types](/execution-types). Yes. On RFQ and gasless venues, the user signs an off-chain message and a solver covers gas. They only need the asset they are selling. EVM chains, Solana, and native Bitcoin. See [Supported Chains & Venues](/supported). The `/health` endpoint reports the live venue set. Poll [`GET /status`](/api-reference/status) with the `statusRef` from `/execute` or `/submit-signature`. It returns a normalized lifecycle of `pending`, `processing`, then `success`. Stop only on a terminal state: `success`, `refunded`, or `failed`. A lapsed deal reports `expired` first (a refund is owed but not yet issued), so keep polling until it becomes `refunded`. Every response includes a `requestId`, which is also in the `x-request-id` header. Include it when you reach out via [ravn.exchange](https://ravn.exchange), and we can trace the exact request. # How It Works Source: https://docs.ravn.exchange/how-it-works One quote across every venue, delivered as the canonical asset, with no bridges. RAVN is a **cross-chain execution layer**. You send one request, RAVN finds the best route across every connected venue, and it returns exactly what your user needs to sign or send. The user always receives the **canonical asset** on the destination. There is never a wrapped or synthetic token, and never a lock-and-mint bridge. ## The flow On every quote, RAVN queries all eligible venues in parallel (RFQ market makers, intent networks, and cross-chain solvers) and picks the best real output for the pair, amount, and route. The winning quote comes back in a single shape, with an opaque `quoteToken`. You never deal with per-venue formats. Execution resolves to one of three values of `executionType`: `TRANSACTION`, `SIGNATURE`, or `DEPOSIT`. Your integration branches on that one field. See [Execution Types](/execution-types). The user signs or sends directly to the venue. RAVN never takes custody of funds. Solvers fill and deliver the canonical asset on the destination chain. ## Why there are no bridges Traditional cross-chain routes lock your asset on one chain and mint a wrapped copy on another, which introduces custody, wrapping, and synthetic-asset risk. RAVN routes only through RFQ market makers, intent networks, and solver and relayer networks that settle in the canonical asset. That is what lets RAVN promise no bridges, no wrapping, no synthetics, and no custodians, and it is why "bridge" never appears in a RAVN route. ## What you integrate once EVM, Solana, and native Bitcoin through one API. RFQ, intents, and solvers behind one contract. Three execution types, one branch. Parallel routing picks the best real output. # RAVN Integrator API Source: https://docs.ravn.exchange/introduction One integration to swap any asset across any chain. EVM, Solana, and native Bitcoin. RAVN aggregates RFQ market makers, intent networks, and cross-chain solvers behind a single, uniform interface. You can quote, execute, and track a swap across EVM, Solana, and **native Bitcoin**, without ever touching a bridge, a wrapped asset, or a synthetic. Swap 1 ETH to SOL end to end in four calls. The one field your integration branches on. Every endpoint, request, and response. ## Base URL ``` https://app.ravn.exchange/api/v1 ``` * **Content type:** `application/json` * **Amounts:** always strings, in the token's smallest unit (wei, lamports, satoshis). * **Native coin:** use the sentinel `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For Solana native SOL, use its mint `So1111...1112`. RAVN is in beta. Every call works with no `x-api-key` header at all if you just want to poke around, but [get a free key](/tools/get-api-key) first if you can. It's instant, no review, and quadruples your rate limit. See [Authentication](/authentication) for the full tier breakdown. RAVN charges 0 bps on every route, for every tier, by default. The fee is still shown in every quote, and it is invisible to your end users. ## Why it is different Most swap APIs do one thing, an EVM transaction, so their whole surface assumes it. RAVN spans three genuinely different execution models, and every quote resolves to exactly one `executionType`. Your integration reads that one field and branches. That is the whole contract. | Model | What the user does | Venues | | ------------- | ------------------------------------------- | ------------------------------------------------------------------- | | `TRANSACTION` | Sign and broadcast | Across, Relay, Mayan, Jupiter, Eco Routes, Garden, THORChain, Bebop | | `SIGNATURE` | Sign typed data (no gas), then RAVN submits | 0x Gasless, Bebop, CoW, Relay | | `DEPOSIT` | Send the origin asset to an address | NEAR Intents, Chainflip, Relay (BTC), Garden (BTC) | See [Supported Chains & Venues](/supported) for which type each venue returns and when: a few depend on the source chain or execution mode. ## The response envelope Every response has the same shape. ```json Success theme={null} { "data": { }, "meta": { "requestId": "uuid", "version": "2024-01" } } ``` ```json Failure theme={null} { "error": { "code": "NO_LIQUIDITY", "message": "..." }, "meta": { "requestId": "uuid", "version": "2024-01" } } ``` Every response also carries `x-request-id` and `ravn-version` headers. Log the `requestId` and quote it when you contact support. # Pricing Source: https://docs.ravn.exchange/pricing Route-based fees, fully transparent. 0 bps on every route, every tier. Read the fee object on every quote. RAVN's **swap fee is 0 bps** on every route, for every integrator tier, and for every access door (REST, MCP, x402). Quotes still expose a `fee` object so you can read the applied fee programmatically; today it always reports zero. ## Integrator swap fee by route | Route | RAVN fee | | -------------------------------- | -------- | | EVM same-chain | 0 bps | | Solana to Solana | 0 bps | | EVM cross-chain | 0 bps | | Cross-ecosystem (EVM and Solana) | 0 bps | | Native BTC (either direction) | 0 bps | Direct users on the consumer app also pay **zero RAVN markup**. Venue or network costs that appear in a quote (for example gas on non-gasless routes) are not RAVN fees; they are part of the route economics RAVN ranks for best execution. ## Fee object on every quote Every successful [`POST /quote`](/api-reference/quote) includes: ```json theme={null} "fee": { "bps": 0, "amount": "0", "token": { } } ``` * `bps` is the integrator fee in basis points applied to that quote. * `amount` is that fee in the fee token's smallest unit. * Both are `0` / `"0"` under the default pricing. Do not hard-code the assumption that the fee will stay zero forever if you build billing dashboards off this field: read `fee.bps` and `fee.amount` from the quote. ## Same price on every tier and door | Access path | Swap fee | Access / call cost | | ------------------------------------------------ | ------------------------------ | ---------------------------------------------------- | | Anonymous REST (no key) | 0 bps | Free (rate-limited) | | Self-serve API key | 0 bps | Free ([get a key](/tools/get-api-key)) | | Enterprise key | 0 bps (custom deals available) | Free / custom | | [MCP server](/ai-agents/mcp-server) | 0 bps | Free | | [x402 quote / execute](/ai-agents/x402-payments) | 0 bps | Optional USDC call fee ($0.001 quote, $0.01 execute) | The x402 amounts are **API access fees**, not swap fees. They pay for the HTTP call when you choose the metered door; the swap itself remains 0 bps. See [x402 Payments](/ai-agents/x402-payments). Rate limits and keys live on [Authentication](/authentication). ## Enterprise fee arrangements Need a dedicated fee schedule, rev-share, or custom limits? DM [@ravnexchange](https://x.com/ravnexchange) or reach out via [ravn.exchange](https://ravn.exchange) with a short note on what you are building. # Quickstart Source: https://docs.ravn.exchange/quickstart Swap 1 ETH to SOL end to end. Four calls, always in the same order: quote, execute, complete, then status. Every call below works as-is with no API key. But [get a free key](/tools/get-api-key) first if you can, it takes 30 seconds, quadruples your rate limit, and gets your project on RAVN's radar. Price the swap. You get back the best route across every venue plus an opaque `quoteToken`. ```bash theme={null} curl -s -X POST https://app.ravn.exchange/api/v1/quote \ -H 'content-type: application/json' -d '{ "inputChainId": 1, "outputChainId": -2, "inputToken": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "outputToken": "So11111111111111111111111111111111111111112", "inputAmount": "1000000000000000000", "userAddress": "0xYourUser", "destinationAddress": "SoYourUser" }' ``` Hand the `quoteToken` back. RAVN returns how to complete the swap, tagged by `executionType`. ```bash theme={null} curl -s -X POST https://app.ravn.exchange/api/v1/execute \ -H 'content-type: application/json' \ -d '{ "quoteToken": "" }' # returns { "executionType": "DEPOSIT", "deposit": { "address": "...", "amount": "..." }, "statusRef": "..." } ``` Branch on `executionType`. This is the entire client-side contract. ```js theme={null} switch (res.data.executionType) { case "TRANSACTION": { // Selling an ERC-20? `approval` is present when the token still needs an allowance. // It must be MINED before the swap; broadcasting both together reverts. if (res.data.approval) { const hash = await wallet.sendTransaction(res.data.approval); await wallet.waitForTransactionReceipt({ hash }); } await wallet.sendTransaction(res.data.transaction); break; } case "SIGNATURE": { // Gasless still needs an allowance, or the order never fills, silently. if (res.data.approval) { const hash = await wallet.sendTransaction(res.data.approval); await wallet.waitForTransactionReceipt({ hash }); } const sig = await wallet.signTypedData(res.data.typedData); await submitSignature(quoteToken, sig); break; } case "DEPOSIT": await wallet.send(res.data.deposit.address, res.data.deposit.amount); break; } ``` Skipping the `approval` wait is the most common integration failure. The swap spends your tokens via `transferFrom`, so if the allowance is not yet mined it reverts and the user loses the gas. Wait for the receipt, not just the broadcast. Native-coin sells and already-approved tokens omit `approval` entirely. It appears on `SIGNATURE` too: gasless venues still pull tokens via `transferFrom`, and skipping it there is quieter and worse: the order is accepted and never fills, with no error. See [Execution types](/execution-types#the-approval-step). Poll `status` with the `statusRef` from `execute`, or the `statusRef` from `submit-signature`. ```bash theme={null} curl -s "https://app.ravn.exchange/api/v1/status?quoteToken=&ref=" # returns { "status": "pending" | "processing" | "success" | "expired" | "refunded" | "failed" } # terminal: success, refunded, failed. Keep polling on expired; a refund is still due. ``` Amounts are strings in the token's smallest unit. Native coin uses the sentinel `0xEeee...EEeE`. The `quoteToken` is opaque, so never parse it. It expires, so re-quote if it goes stale. # Security Model Source: https://docs.ravn.exchange/security Non-custodial by design, with no bridges, no wrapping, and no synthetics. RAVN is an **orchestration layer, not a custodian**. It finds routes and normalizes execution. It never holds, wraps, or mints user funds. ## Non-custodial * The user signs or sends directly to the venue. RAVN never takes custody of funds at any point in a swap. * For `DEPOSIT` routes, the user sends the origin asset to a venue-generated address. For `SIGNATURE` and `TRANSACTION` routes, the user signs or broadcasts directly. ## No bridges, no wrapping, no synthetics RAVN routes only through venues that settle in the canonical asset, which are RFQ market makers, intent networks, and solver and relayer networks. There is no lock-and-mint bridge, no wrapped token, and no synthetic anywhere in a RAVN route. ## Quote integrity * Quotes are returned as an opaque, signed `quoteToken`. It is tamper-evident, so any modification of the amount, fee, or route invalidates it, and execution rejects it with `QUOTE_INVALID`. * Quotes expire, and execution re-validates the expiry before building the transaction. ## Venue-enforced settlement Each venue independently validates the economics and signatures of the order it settles. RAVN never asks a user to sign anything the destination venue will not verify on its own. ## Gasless where it counts On RFQ and gasless venues, the user needs zero native gas. They sign an off-chain message and a solver covers execution. The user only ever needs the asset they are selling. Reliability signal: [`GET /health`](/api-reference/health) reports live per-venue status, so integrators can surface degraded routing in real time. # Supported Chains & Venues Source: https://docs.ravn.exchange/supported Every chain RAVN swaps across, and the venues it routes through. ## Chains RAVN spans EVM chains, Solana, and **native Bitcoin**. One integration covers all of them. Use the chain ID in every request. ### EVM | Chain | ID | Chain | ID | | ----------- | ----- | --------- | ------- | | Ethereum | `1` | Base | `8453` | | Optimism | `10` | Arbitrum | `42161` | | BNB Chain | `56` | Linea | `59144` | | Unichain | `130` | Avalanche | `43114` | | Polygon | `137` | Robinhood | `4663` | | zkSync Era | `324` | HyperEVM | `999` | | World Chain | `480` | Monad | `143` | ### Non-EVM | Chain | ID | Notes | | ----------- | ---- | ---------------------------------------------------------------- | | **Solana** | `-2` | SPL and native SOL. Use the mint `So1111...1112` for native SOL. | | **Bitcoin** | `-1` | Native BTC, with no wrapping and no cbBTC intermediary required. | Native coin on any EVM chain uses the sentinel address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. Amounts are always strings in the token's smallest unit (wei, lamports, satoshis). Not every venue serves every chain. The router automatically selects venues that can serve a given route, and it returns `NO_LIQUIDITY` if none can. ## Venues RAVN aggregates twelve venues across four settlement models. On every quote, the eligible venues are queried in parallel and the best real output wins. Most venues return one fixed [execution type](/execution-types); a few return different types depending on the source chain or execution mode, noted per row below. | Venue | Type | Execution | Serves | | ----------------- | ------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | **0x Gasless** | RFQ market maker | `SIGNATURE` | EVM same-chain | | **Bebop** | RFQ market maker | `SIGNATURE` or `TRANSACTION` | EVM same-chain | | **CoW Protocol** | Batch auction and RFQ | `SIGNATURE` | EVM same-chain | | **Jupiter Ultra** | On-chain aggregation | `TRANSACTION` | Solana | | **Across** | Intent and solver network | `TRANSACTION` | EVM cross-chain, cross-ecosystem | | **Relay** | Relayer network | `TRANSACTION`, `SIGNATURE`, or `DEPOSIT` | EVM and Solana, same and cross-chain, plus native BTC as source | | **Mayan** | Intent and auction | `TRANSACTION` | Same-chain, cross-chain, cross-ecosystem | | **NEAR Intents** | Intent network (1Click) | `DEPOSIT` | Any to any, including native BTC | | **Garden** | Atomic swap (HTLC) network | `DEPOSIT` (BTC source) or `TRANSACTION` (EVM/Solana source) | Native BTC ↔ Ethereum, Base, Arbitrum, BNB Chain, HyperEVM, Monad, Robinhood, Solana | | **Eco Routes** | Intent network (ERC-7683 vault) | `TRANSACTION` | Stablecoin-to-stablecoin: Ethereum, Optimism, BNB Chain, Unichain, Polygon, HyperEVM, Base, Arbitrum, and into Solana (destination only) | | **Chainflip** | Validator-vault JIT AMM | `DEPOSIT` | Native BTC ↔ Ethereum, Arbitrum, Solana | | **THORChain** | Validator-vault AMM | `TRANSACTION` | Ethereum, Avalanche → native BTC. BTC as the *source* depends on a THORChain network flag, see below | All venues settle in the **canonical asset**. None of them wrap, mint synthetics, or bridge. RFQ and gasless venues let the user swap with zero native gas, because they sign an off-chain message and a solver covers the gas. **THORChain with BTC as the source** requires THORChain's *memoless* feature, which THORChain can disable network-wide with its `HALTMEMOLESS` flag, and currently has. RAVN checks that flag on every quote and simply leaves THORChain out of the race while it is set, so you never receive a quote that cannot execute. This changes nothing you need to handle: **selling BTC still works**, because Garden, Chainflip, Relay and NEAR Intents all serve it and keep competing. THORChain sending funds *to* native BTC is unaffected either way: that path uses an ordinary memo with no registration. ### Settlement models Professional market makers quote a firm, signed price. The user signs and a solver settles. Zero slippage, zero gas. The user expresses an intent, or deposits the origin asset, and solvers compete to fill and deliver on the destination. Relayers fill on the destination chain and deliver the canonical asset. This gives fast cross-chain execution without bridging. A decentralized, threshold-signed validator network custodies a deposit channel and swaps against its own AMM or vault liquidity. No single custodian ever holds the funds. Coverage grows over time. The [`/health`](/api-reference/health) endpoint always reports the current live venue set. # Get an API key Source: https://docs.ravn.exchange/tools/get-api-key Instant, no review. 4x your rate limit and put your project on the map. Takes 30 seconds. Fill in the form, get your key immediately, no waiting on a human, no approval queue. You go from 30 requests/min to 120, and your project shows up by name in RAVN's usage tracking, which is step one toward a partnership or a rev-share deal down the line. Not ready yet? You can still call the API with zero setup: every endpoint works with no `x-api-key` header at all, capped at 30 requests/min per IP. Come back here whenever you want to scale up. Building something serious and want a custom rate limit or a dedicated fee arrangement? Reach out to the RAVN team directly instead, covered in [Authentication](/authentication#enterprise-partnerships). # Use Cases Source: https://docs.ravn.exchange/use-cases What teams build on RAVN. One integration turns any app into a cross-chain swap surface, including the routes most aggregators cannot do, such as native Bitcoin and cross-ecosystem swaps. Let wallet users swap any asset to any chain in-app across EVM, Solana, and native BTC, without leaving the wallet. Gasless on RFQ routes. Rebalance a multi-chain treasury (for example ETH to BTC, or stables across chains) in one call, non-custodially, with the canonical asset delivered. Add a swap action to a portfolio tracker so users act on positions without leaving the dashboard. Run programmatic cross-chain execution with a normalized quote, execute, and status loop, plus firm RFQ pricing. Move value in and out of native Bitcoin without cbBTC, wrapping, or a bridge. This is a route most aggregators cannot offer at all. Settle a user's asset into the exact token and chain a downstream flow expects, in one hop. Every route is non-custodial and settles in the canonical asset. Your users never touch a bridge, a wrapped token, or a synthetic.