This is the full developer documentation for Chord # Build on Chord > Best-route quotes and unsigned transactions for trading. Swaps on Ethereum, Arbitrum, Base, BNB Chain, Avalanche, Monad, Arc, Robinhood Chain and Solana, rolled up by token, venue and hour. Wallet PnL, liquidity positions and an analyst agent. One REST base URL, no key to read. Trade `GET /v1/quote` finds the best route across every venue on the chain, splitting the order when that improves the output. `POST /v1/swap` turns it into a transaction you sign yourself. Chord never holds funds or keys. Read Swaps on nine chains from Chord’s own index: chain totals, every token traded and wallet PnL on all of them; launches, holders, top wallets, liquidity pools and positions where the chain has them (`GET /v1/chains` says which). Answers carry their own coverage flags. Stream A public WebSocket for live candles, trade tapes and Arc prices, and a server-sent events feed for Robinhood Chain prices. No key, automatic reconnect. Agents The same API as an MCP server and a function-calling manifest, plus the analyst: ask a question in plain language and get a researched answer over the index, with a route card when the question implies a trade. ## Where to start [Section titled “Where to start”](#where-to-start) [Get started](/docs/get-started/)An API key (optional), your first request, and the three-call swap. [Add Chord to your app](/docs/build/)Patterns that hold across every endpoint: chains, amounts, coverage, caching, errors. [Recipes](/docs/recipes/token-page/)A token page, a markets board, a swap, charts, a trader dashboard, an LP dashboard, a launch feed, a bridge. [Networks](/docs/networks/)Ethereum, Arbitrum, Base, BNB Chain, Avalanche, Monad, Arc, Robinhood Chain and Solana: ids, anchors, contracts, venues. [Agents](/docs/agents/)MCP server, function-calling manifest, the Ask agent API and llms.txt. [API reference](/docs/api-reference/)Every endpoint with parameters, response schemas and real examples, generated from the OpenAPI document. ## The base URL [Section titled “The base URL”](#the-base-url) ```plaintext https://api.getchord.xyz/v1 ``` Reads need no key at 60 requests a minute per IP. A key from [getchord.xyz/developer](https://getchord.xyz/developer) raises that to your plan and meters usage per key. The whole contract is one file: [openapi.json](/docs/openapi.json). # Get started > An API key (optional), your first request, and the three calls that take you from nothing to a signed swap on Arc. Chord’s API is REST over HTTPS, JSON in and out. The base URL is `https://api.getchord.xyz` and every path starts with `/v1`. Nothing below needs an account. ## 1. Make a request [Section titled “1. Make a request”](#1-make-a-request) The chain overview is the cheapest useful call: the last 24 hours on Arc, venue share, hourly buckets and daily rows, with the coverage flags every read carries. ```bash curl https://api.getchord.xyz/v1/arc/overview ``` ```json { "chain": 5042, "last24h": { "volUsd": 70377594.23, "swaps": 788926, "tokens": 6288, "sinceHour": 1789808400 }, "venues24h": [ { "dex": "uniswap_v4", "volUsd": 55014882.20, "trades": 683313, "tokens": 4059, "sharePct": 78.17 } ], "hourly24": [ { "hour": 1789808400, "volUsd": 3234644.52, "swaps": 50225 } ], "daily": [ { "day": 1787356800, "swaps": 5712, "volUsd": 609934.64, "tokens": 292, "wallets": 768, "venues": 4 } ], "coverage": { "recentAt": 1789891429, "stale": false, "backfillComplete": true }, "updatedAt": 1789891764243 } ``` Read `coverage` before you trust a quiet number. `stale: true` means the most recent rolled-up hour is older than the lane’s freshness bar; `backfillComplete: false` means long windows undercount. See [Data freshness](/docs/concepts/data-freshness/). ## 2. Get a key (optional) [Section titled “2. Get a key (optional)”](#2-get-a-key-optional) Anonymous reads answer at 60 requests a minute per IP. A key raises that to your plan and meters usage per key; it is required for the [Ask agent API](/docs/agents/ask-api/) and for the `only=` debug lever on quotes. 1. Open [getchord.xyz/developer](https://getchord.xyz/developer) and sign in with Google. 2. Create a key. It is shown once; store it. 3. Send it as a header on every request. ```bash curl -H "X-API-Key: YOUR_KEY" https://api.getchord.xyz/v1/me ``` ```json { "email": "you@example.com", "tier": "free", "limits": { "rpm": 60, "monthly": 100000, "priceUsd": 0, "label": "Free" }, "usage": { "today": 41, "month": 1209 } } ``` Plans are on [getchord.xyz/pricing](https://getchord.xyz/pricing): Free (60 a minute, 300 calls in any 30 days), Build (100 a minute, 16,000 calls) and Grow (150 a minute, 144,000 calls). A plan covers all keys on an account together. See [Rate limits](/docs/concepts/rate-limits/). ## 3. Swap in three calls [Section titled “3. Swap in three calls”](#3-swap-in-three-calls) This buys cirBTC with 5 USDC on Arc. Amounts are strings in the token’s smallest unit: the USDC predeploy has 6 decimals, so 5 USDC is `5000000`. ### Quote [Section titled “Quote”](#quote) ```bash curl "https://api.getchord.xyz/v1/quote?chain=5042\ &inputMint=0x3600000000000000000000000000000000000000\ &outputMint=0x171a4217b86a807a64eb94757db6849fb4bdbaa0\ &amount=5000000&slippageBps=100" ``` The answer is the best route: `outputAmount`, `otherAmountThreshold` (the minimum the transaction enforces), `priceImpactPct`, the `routePlan` with one leg per venue, the protocol `feeBps` on the output token, and a gas estimate. An empty `routePlan` with `outputAmount: "0"` means no route at this size, and `noRouteReason` says why. ### Build [Section titled “Build”](#build) Send the quote body back unmodified with the wallet that signs. ```bash curl -X POST https://api.getchord.xyz/v1/swap \ -H "Content-Type: application/json" \ -d '{ "quoteResponse": , "userPublicKey": "0xYourWallet", "chain": 5042 }' ``` ```json { "transaction": { "to": "0x1b1fee89a381e595fe6536b99ba91f3e16e9601a", "data": "0xdc72a437…", "value": "0", "gasLimit": "1500000", "chainId": 5042 } } ``` For an ERC-20 input, approve `transaction.to` (the Chord router) for at least the input amount first. On Arc the gas token’s ERC-20 face is the USDC predeploy, so even a “native” input is pulled by `transferFrom` and `value` is always `0`. ### Sign and send [Section titled “Sign and send”](#sign-and-send) ```ts const { transaction } = await res.json(); await wallet.sendTransaction({ to: transaction.to, data: transaction.data, value: BigInt(transaction.value), gas: BigInt(transaction.gasLimit), chainId: 5042, }); ``` Before the wallet opens you can `POST /v1/swap/simulate` with the same fields: it `eth_call`s the calldata from your address, decodes a revert if there is one, and estimates gas. The full flow, with approvals and simulation, is in the [Swap recipe](/docs/recipes/swap/). ## Next [Section titled “Next”](#next) * [Add Chord to your app](/docs/build/) — the conventions that hold on every endpoint. * [Clients and codegen](/docs/clients/) — generate a typed client from the OpenAPI document. * [Recipes](/docs/recipes/token-page/) — a token page, a markets board, an LP dashboard, a launch feed. * [API reference](/docs/api-reference/) — every endpoint, with real examples. # Authentication > Reads need no key. A key raises your rate limit, meters usage, and unlocks the Ask agent API. Chord’s API is open to read. Authentication exists to give you a limit of your own and to meter what you use. ## The key [Section titled “The key”](#the-key) Create a key on [getchord.xyz/developer](https://getchord.xyz/developer) after a Google sign-in, or in Ask (sign in at [getchord.xyz/ask](https://getchord.xyz/ask), Settings, API Key). Both pages issue the same kind of key, valid for the data API and for Ask. It is shown once. Send it on every request as a header: ```bash curl -H "X-API-Key: YOUR_KEY" https://api.getchord.xyz/v1/arc/trending ``` A missing or unknown key is **not rejected** on read endpoints: the request simply gets the anonymous per-IP limit. Only two things require a key: * `POST /v1/ask` — the [Ask agent API](/docs/agents/ask-api/) (a Google session bearer also works; that is what the browser uses). * `?only=` on `/v1/quote` — a single-venue debug lever that bypasses the routing safety gates. Check what a key can do with `GET /v1/me`: ```json { "email": "you@example.com", "tier": "build", "limits": { "rpm": 100, "monthly": 16000, "priceUsd": 99, "label": "Build" }, "usage": { "today": 812, "month": 9210 } } ``` ## Keys in browsers [Section titled “Keys in browsers”](#keys-in-browsers) CORS is open, so a browser can send `X-API-Key` directly. A key in a public bundle is a key anyone can copy; if the limit matters to you, call the API from your server or a small proxy and keep the key there. Reads that need no limit can go straight from the browser without a key. ## Sessions [Section titled “Sessions”](#sessions) The Chord app signs users in with Google and mints a short bearer (`nts_…`) for its own surfaces: the developer page, the Ask chat, reports and LP alerts. Agents and integrations do not use sessions; use a key. ## Plans [Section titled “Plans”](#plans) | Plan | Requests a minute | Calls in any 30 days | Price | | ---------- | ----------------- | -------------------- | ------------ | | Free | 60 | 300 | $0 | | Build | 100 | 16,000 | $99 a month | | Grow | 150 | 144,000 | $696 a month | | Enterprise | custom | custom | talk to us | Every key starts on Free. A plan covers all keys on an account together: their calls are counted as one, over the trailing 30 days, and a call past the package answers `429 QUOTA_EXCEEDED` until the window has room again. No endpoint is paywalled; plans change how much you can call. Build and Grow are bought in the app, under Settings, API Key: one transfer of USDC (on Arc, Base, Monad, Avalanche, BNB Chain, Arbitrum or Ethereum) or of USDG (on Robinhood Chain) from your Chord wallet or from any other wallet. A plan runs 30 days, or a year at 20% less, and does not renew by itself. See the [pricing page](https://getchord.xyz/pricing). # Chains, addresses and amounts > How Arc's native USDC, the zero address and decimals work across the API, and what differs on Robinhood Chain. ## Arc (chain 5042) [Section titled “Arc (chain 5042)”](#arc-chain-5042) Arc is Circle’s stablecoin-native chain: **the gas token is USDC**. It has two faces, and the API takes one of them. | Face | Address | Decimals | Where you see it | | -------------- | -------------------------------------------- | -------- | ----------------------------------------------------------------------------------- | | Native USDC | — (balance via `eth_getBalance`) | 18 | wallet balances, `value` on transactions, Uniswap V4 `currency0 = address(0)` pools | | USDC predeploy | `0x3600000000000000000000000000000000000000` | 6 | the ERC-20 interface of the same balance; every V2 / V3 pool; the API | They are one balance: `balanceOf(predeploy) == nativeBalance / 1e12`. There is no wrapped-native contract and nothing to wrap. The API therefore treats the zero address as an **alias for the predeploy** on Arc: send either, get the same route, and the transaction always has `value: "0"` because the router pulls the predeploy by `transferFrom`. Approve the router on the predeploy like any ERC-20. Other anchors: EURC `0xbef5f6d51cb62b58e6a8f77868681825c6fe21c1` (6 decimals, tagged `fx`) and VIRTUAL `0x8c4252c87081c88c6ad57d6dd97e1cafebf842b7` (the quote asset of the Virtuals launcher pools, priced from its own USDC prints). Protocol fee on USDC and EURC is 0 bps. ## Robinhood Chain (chain 4663) [Section titled “Robinhood Chain (chain 4663)”](#robinhood-chain-chain-4663) An ordinary EVM chain: native ETH is the zero address, WETH `0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73` wraps it, and the stable anchor is USDG `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` (6 decimals). Tokenized stocks are 18-decimal tokens tagged `stock` (NVDA `0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC`, AAPL `0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9`, …). WETH, USDG and every stock are 0 bps. ## Monad, Avalanche, Base, BNB Chain, Arbitrum and Ethereum (143, 43114, 8453, 56, 42161, 1) [Section titled “Monad, Avalanche, Base, BNB Chain, Arbitrum and Ethereum (143, 43114, 8453, 56, 42161, 1)”](#monad-avalanche-base-bnb-chain-arbitrum-and-ethereum-143-43114-8453-56-42161-1) Ordinary EVM chains: the zero address is the native coin (MON, AVAX, ETH or BNB), sent as `value`; WMON, WAVAX, WETH and WBNB wrap it, and the router wraps and unwraps for you. The dollar anchors are USDC (and USDT where the chain has it), 6 decimals on Monad, Avalanche, Base, Arbitrum and Ethereum, **18 decimals on BNB Chain**. Ethereum’s USDT refuses a new approval while an old one is left: approve 0 first (`approval.resetFirst` on `/v1/meta`). Anchors and contracts per chain: [Networks](/docs/networks/). ## Amounts [Section titled “Amounts”](#amounts) Every amount the API takes or returns for a token is a **decimal string in the token’s smallest unit**. Never a float, never scientific notation. ```plaintext 5 USDC on Arc → "5000000" (6 decimals) 0.01 ETH on 4663 → "10000000000000000" (18 decimals) 0.005 cirBTC → "500000" (8 decimals) ``` Read decimals from the token list or the token row. Chord never defaults to 18, and neither should you. ```ts const { tokens } = await fetch("https://api.getchord.xyz/v1/tokens?chain=5042").then((r) => r.json()); const usdc = tokens.find((t) => t.symbol === "USDC"); const amount = (5n * 10n ** BigInt(usdc.decimals)).toString(); // "5000000" ``` USD figures in read endpoints (`volume24h`, `priceUsd`, `usd`) are plain numbers. ## Addresses [Section titled “Addresses”](#addresses) Hex, case-insensitive on input; the API returns Arc addresses lower-cased and Robinhood Chain list addresses checksummed. Compare lower-cased. Pool identities are 20-byte addresses for V2 / V3 pools and **32-byte pool ids** for Uniswap V4 — any `pool` parameter accepts both, and any `pool` field may hold either. Treat a pool as an opaque string; only an explorer link needs to know which it is. ## The `chain` parameter [Section titled “The chain parameter”](#the-chain-parameter) | Endpoint family | `chain` | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/quote`, `/swap`, `/swap/calldata`, `/swap/simulate` | `5042`, `4663`, `143`, `43114`, `8453`, `56`, `42161` or `1`. The default is `143`: always pass it. | | `/tokens` | `5042` or `4663`; omitted, the Monad list. | | `/tokens/market` | `4663` or `5042`. Omitted, it answers for Monad. | | `/tokens/board` | `143`. | | `/tokens/search` | `4663`, `5042`, `43114`, `8453`, `56`, `42161` or `1`. Omitted (or `143`), it is Monad off-list discovery. Arc also has `/arc/tokens/search` with full board rows. | | `/candles` | `5042`, `4663`, `143`, `43114`, `8453`, `56`, `42161` or `1`. The default is `143`: always pass it. | | `/chains/{chain}/*` | in the path: `avalanche` or `43114`, `base` or `8453`, `bnb` or `56`, `arbitrum` or `42161`, `ethereum` or `1` (and `solana`). | | `/tokens/chart`, `/tokens/trades`, `/tokens/stats`, `/logo` | none (address-keyed) — `/logo` takes the chain in the path. | | `/smart-money/top`, `/portfolio/*`, `/lp/*` | `5042`, `4663` or `143`. | | `/arc/*` | none; always 5042. | | `/rh/*` | none; always 4663. | | `/points/*`, `/ask/*` | none; always 5042. | # Data freshness and honesty > Rollups versus the tape, coverage flags, attribution, and the flags that mark wash volume, impostors and suspect pools. Every number in a read endpoint comes from Chord’s own index of the chain: every swap event on every venue, decoded and priced at index time, stored as a tape, and rolled up by hour, token and venue. Nothing is fetched from a third-party price API on the request path. ## Tape and rollups [Section titled “Tape and rollups”](#tape-and-rollups) * The **tape** is one row per swap: block, transaction, venue, pool, token, side, size, USD, price and the attributed wallet. Trade tapes, wallet PnL and positions read it. * The **rollups** sum the tape by hour per token and venue, and by day per chain. `/arc/*`, `/rh/*`, boards and overviews read only rollups, so they answer in milliseconds and never scan the tape. * **Live layers** sit on top where seconds matter: Arc prices are pushed from the chain head over WebSocket, and the Arc top-wallets board keeps the last minutes of trades in memory between rebuilds (`live` in the response). ## Coverage flags [Section titled “Coverage flags”](#coverage-flags) Rollup answers carry a `coverage` object. Read it before you trust a quiet number. | Field | Meaning | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `recentAt` | The most recent hour the rollup has processed. | | `stale` | True when `recentAt` is older than the lane’s freshness bar. A quiet chart with `stale: true` is a lane that stopped, not a market that stopped. | | `floorHour` | The oldest hour rolled up so far. Windows reaching further back undercount. | | `genesisHour` | The chain’s first indexed hour. | | `backfillComplete` | True once `floorHour` reached genesis. | Other families expose the same idea in their own words: the holder ledger says `tracked` and `complete`; `/lp/status` shows each lane’s cursor against the chain head; `/arc/status` shows the pool index cursor and whether discovery reached genesis. `updatedAt` on any answer is when the server built it. ## Attribution [Section titled “Attribution”](#attribution) A swap’s wallet is the account that initiated the transaction, resolved through routers, aggregators and account-abstraction executors. On Robinhood Chain, routers and executors were 71 % of transactions in a day before attribution landed; publishing a “top wallets” board of routers would have been a lie. So: `wallets`, `traders`, `providers` count attributed wallets only, and bots are removed from rankings by cadence, nonce rate and behaviour (`botsRemoved` on the board says how many). ## Honesty flags [Section titled “Honesty flags”](#honesty-flags) Chord flags rather than hides, and sorts flagged rows below clean ones. | Flag | Where | Rule | | ------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `flags: ["wash"]` | token rows | ≥ $5k of volume from ≤ 2 wallets, or ≥ $50k from fewer than 5. A fake ARGUS once printed “$9.97M” from ten $500k self-trades in one second. | | `flags: ["impostor"]` | token rows | An unlisted token wearing a listed or trusted symbol. | | `suspect` | pool rows | Turnover no honest pool reaches (24h volume ÷ TVL above 300×, or above 50× with under 25 traders), dust TVL under real volume, or fewer than five wallets printing over $10k. Hidden from `/lp/pools` unless `flagged=1`. | | `token0.impostor` / `token1.impostor` | pool rows | A symbol that copies the chain’s anchor (a “USDC” that is not the predeploy). | | `screened` | `/arc/graduated` | Launches removed by each screen: impostor symbols, launch farms (one creator, many pools), no sells, too few traders, no trades. | | `jit` · `unreconciled` | positions | Opened and closed within seconds (a swap trick); dollars out far above dollars in (the tape missed an add). Shown, never scored. | Forged pools — forks emitting Swap events with no USDC actually moving — are dropped from the tape entirely when detected. ## Prices [Section titled “Prices”](#prices) `priceUsd` on a token row is the last trade on the token’s **dominant venue** for the day, not a blend; a thin fork cannot move it. Market cap is `totalSupply × price` and is fully diluted, because nothing on-chain says what is locked. Candles are built from the tape (`source: "db"`); a token with too few trades for a bucket has no candle rather than a fake one. # Errors and retries > The error body, the codes you will branch on, and which ones to retry. Every non-2xx response is JSON with a stable machine code and a human message: ```json { "error": "INSUFFICIENT_LIQUIDITY", "message": "no route at this size — try a smaller amount" } ``` Branch on `error`, never on `message`. Some older routes add `statusCode`; ignore it. ## Codes [Section titled “Codes”](#codes) | Status | `error` | Where | Meaning and what to do | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------- | | 400 | `INVALID_PARAMS` | everywhere | A parameter is missing or malformed. The message names it. | | 400 | `BAD_ADDRESS` · `BAD_LIMIT` · `BAD_HOURS` · `BAD_DAYS` · `BAD_SORT` · `BAD_QUERY` · `BAD_POOL` | reads | The named check failed. | | 400 | `UNSUPPORTED_CHAIN` · `BAD_CHAIN` | quote, swap, boards | The chain id is not one the API serves. | | 400 | `BAD_SOURCE` | smart money | `source=onchain` is required on 5042 / 4663. | | 400 | `SLIPPAGE_MISMATCH` | swap | The `slippageBps` you sent differs from the quote’s. Re-quote at the slippage you want. | | 400 | `ROUTE_MISMATCH` | swap | The quote body was edited. Send it back unmodified. | | 400 | `ONLY_REQUIRES_KEY` | quote | `?only=` needs an API key. | | 401 | `UNAUTHORIZED` | ask, me | No key or session, or an unknown one. | | 404 | `UNKNOWN_TOKEN` | charts, trades, stats | Not on a curated list and not a side of an indexed pool. | | 404 | `NOT_FOUND` | pool, position, report | Nothing at this identity. | | 404 | `NO_ROUTE` | swap calldata | No route for this pair and size. | | 404 | `NOT_ENOUGH_HISTORY` | LP plan, simulate | Fewer than 24 hourly candles or no anchored pool. | | 409 | `ROUTE_STALE_GRADUATED` | quote | A bonding-curve token graduated mid-route (Monad). Re-quote. | | 409 | `NOT_ATTESTED` · `IN_FLIGHT` | bridge relay | Circle has not attested the burn yet, or a relay is already running. Poll `/bridge2/status`. | | 429 | `RATE_LIMIT_EXCEEDED` | everywhere | Read `X-RateLimit-Reset` and back off. | | 429 | `RATE_LIMITED` | ask | Over 8 questions a minute. | | 502 | `ENGINE_ERROR` · `ROUTE_ERROR` | quote, swap | The routing engine did not answer. Retry once after a second. | | 503 | `NOT_READY` | arc, rh, launchers | The rollup or index has not run on this deployment yet. | | 503 | `CHAIN_NOT_ENABLED` | quote, smart money | The chain’s routing or board is not published here. | | 503 | `HOLDERS_PENDING` | holders | The token was just pinned for tracking. Retry in a few minutes. | | 503 | `NOT_ENABLED` | points | The points program is off on the deployment. | | 503 | `ARC_DATA_UNAVAILABLE` · `RH_DATA_UNAVAILABLE` · `SIMULATION_UNAVAILABLE` · `IRIS_UNAVAILABLE` · `SESSION_STORE_UNAVAILABLE` · `DISABLED` | various | A dependency did not answer. Retry with backoff. | ## Empty is not an error [Section titled “Empty is not an error”](#empty-is-not-an-error) Some answers are honest empties, not failures: * A quote with `routePlan: []` and `outputAmount: "0"` — no route at this size. Read `noRouteReason` (`INSUFFICIENT_LIQUIDITY` or `NO_POOLS`). * A token on `/arc/token/{address}` that comes back as `{ address, listed: false }` — no trades in the last 24 hours. * Portfolio routes answer an empty 200 shape (`tokens: []`) when the tape read fails, never a 5xx. Treat it as “nothing yet” and retry later. * A holder ledger with `complete: false` — the backfill has not reached the token’s creation block; balances are partial and say so. ## Retrying [Section titled “Retrying”](#retrying) Retry `502` and `503` with exponential backoff starting at one second, at most three times. Do not retry `400`, `401`, `404` or `409` — the request will not become valid on its own (a `409 NOT_ATTESTED` is a poll, not a retry). Retry `429` after `X-RateLimit-Reset`. Quotes are live and expire: a `502` on `/swap` after a successful quote usually means the route changed. Quote again rather than resubmitting the old body. # Liquidity and positions > What the liquidity family indexes — events, pools, positions, the health score, range planning — and how the numbers are made. The `/v1/lp/*` family is Chord’s LP agent: the data a liquidity provider needs before, during and after a position, on Arc, Robinhood Chain and Monad. ## What is indexed [Section titled “What is indexed”](#what-is-indexed) * **Events** — every `Mint` / `Burn` / `Collect` on V2 pairs, V3 pools and V4 pools (`ModifyLiquidity`), with the sender resolved through position managers to the wallet, and the dollars that entered or left the pool where the pool has an anchor side (USDC, EURC on Arc; WETH, USDG on 4663). V4 amounts are computed from `liquidityDelta` and the pool’s price at that block, because the log does not carry them. * **Pools** — hourly volume, trades and price per pool from the swap tape, TVL from the chain (or a market-data fallback, named in `tvlSrc`), and the pool’s fee tier. Fees are `volume × fee tier`; `feeTvlPct` is fees ÷ TVL for the window; `aprPct` is the 24-hour figure × 365, a full-range yardstick and not a promise. * **Positions** — every position NFT from the Uniswap V3 position manager and the V4 PositionManager on each chain: dollars in and out, fees collected, and for open positions the live value, uncollected fees (V3), whether it is in range, the distance to the nearest edge, and PnL on the liquidity leg. * **Providers** — the leaderboard: win rate on closed positions, fees, expected value per position, average age, invested and monthly profit, and the last seven days. ## The health score [Section titled “The health score”](#the-health-score) Every pool has a 0–100 score from six parts: traders (real wallets, not printing), TVL, yield sanity (fee/TVL a pool can honestly sustain), LP flow (net adds versus removes), age, and penalties. `reasons` names what cost points — “the launcher holds 100 % of the liquidity added”, “fee/TVL over 10 %/day: volume is being printed”. `/lp/token/{address}/pools` ranks a token’s pools by it. ## Suspect pools [Section titled “Suspect pools”](#suspect-pools) A pool is `suspect` when its numbers cannot be honest: 24-hour turnover above 300× TVL, above 50× with fewer than 25 traders, dust TVL under six-figure volume, fewer than five wallets printing over $10k, or a hooked V4 pool with dust TVL (a launchpad curve where the hook holds the real reserves). Suspect pools are hidden from `/lp/pools` unless `flagged=1`, and never chosen as “best yield”. The rule was measured against a launch fleet printing $100k a day through $2.5k pools with three wallets, and against a real market-maker pool turning 48× a day with thousands of traders — turnover alone cannot split them; traders can. ## Launch facts [Section titled “Launch facts”](#launch-facts) On Arc most tokens are born through a launcher. `/lp/pools/{pool}` and `/lp/token/{address}/pools` say who launched the pool, how much of the liquidity ever added the launcher supplied (`launcherSharePct`), and when it last pulled and how much. A pool whose launcher holds all the liquidity and has started removing it is a different risk from one with fifty providers. ## Planning a range [Section titled “Planning a range”](#planning-a-range) `/lp/plan` derives three ranges from the token’s own hourly and daily volatility (tight, balanced, wide), reports the share of the last seven days the price stayed inside each, and backtests each on Chord’s candles against holding: fees at the pool’s real tier and the position’s share of liquidity, impermanent loss, how many times the price left the range, and the net versus hold. `/lp/simulate` runs one explicit range. Under two days of candles the answer says `young: true` — the bands are a launch’s noise, not a distribution. ## Minting [Section titled “Minting”](#minting) `/lp/pools/{pool}` returns `mint`: the position manager to call, the pool key (tokens, fee, tick spacing, hooks), Permit2, and whether `currency0` is native. It is what the Chord app uses to add liquidity from the browser (V3 through the NPM, V4 through PositionManager + Permit2). Chord does not build the mint calldata for you; the pool key is the input to the Uniswap SDK. ## Alerts [Section titled “Alerts”](#alerts) `POST /lp/watch` turns on alerts for a wallet’s positions — out of range, fees past a bar, a watched pool draining — in the app and, through a one-hour Telegram deep link, in a chat. `GET /lp/watch` is the inbox. # Meta aggregator > One quote and one unsigned transaction on any Chord chain. Chord's own router answers first; a third-party aggregator only when it fails, and the answer says who quoted it. `GET /v1/meta/quote` and `POST /v1/meta/swap` are the swap endpoints built for agents: one call on any of the eight EVM chains that ends in a route you can sign, or an honest “no route anywhere”. Chord’s own router always answers first. A third-party aggregator answers only when Chord fails, and every answer names the provider and the reason. | Chain | First | Fallbacks, in order | | ---------------------- | ------------ | -------------------------- | | Monad `143` | Chord router | KyberSwap, Monorail, Relay | | Robinhood Chain `4663` | Chord router | KyberSwap, LI.FI, Relay | | Arc `5042` | Chord router | KyberSwap, LI.FI, Relay | | Avalanche `43114` | Chord router | KyberSwap, LI.FI, Relay | | Base `8453` | Chord router | KyberSwap, LI.FI, Relay | | BNB Chain `56` | Chord router | KyberSwap, LI.FI, Relay | | Arbitrum One `42161` | Chord router | KyberSwap, LI.FI, Relay | | Ethereum `1` | Chord router | KyberSwap, LI.FI, Relay | The live order and each provider’s breaker state: `GET /v1/meta/providers`. ## When a fallback is used [Section titled “When a fallback is used”](#when-a-fallback-is-used) Only on a Chord failure: * the routing engine timed out, returned an error, or is down (a cold start, a deploy); * Chord has no route for the pair or the size; * Chord refuses the route itself: the [value guard](/docs/concepts/quotes-and-routing/), a taxed token, a stale bonding-curve route; * the Chord router is not live on that chain; * the transaction Chord built fails simulation. Never because another aggregator shows a better price. Never on a user error: an address that is not a token, a bad amount or an unknown chain is answered with HTTP 400 and no other provider is asked. ## What you get back [Section titled “What you get back”](#what-you-get-back) The same shape whichever provider answered. | Field | Meaning | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `provider` | `chord`, `kyberswap`, `monorail`, `lifi`, `relay`. `null` = no provider has a route. | | `fallbackReason` | `null` when Chord answered, otherwise why it did not (`no_route`, `engine_timeout`, `value_guard`, `simulation_failed`, …). | | `attempts` | Every provider asked, in order, with `status`, `ms` and a short `error`. | | `amountOut` | What the taker receives after every fee, smallest unit. | | `minAmountOut` | The minimum the transaction enforces, from the slippage you asked for. | | `priceImpactPct` · `valueLossPct` | Impact when the provider states one; value lost at Chord’s own prices (`null` when a side has no reliable price). | | `feeBps` · `feeRecipient` | Chord path: Chord’s protocol fee. Fallback: the integrator fee Chord added (0 today); the provider’s own fees are inside `amountOut`. | | `route.venues` | Venue names. | | `tx` | `{to, data, value, gas, chainId}`, unsigned. `null` without `taker`. | | `approval` | `{token, spender, amount}` to send first, or `null`. | | `simulation` | The transaction run as the taker: `{ok, amountOut, gasUsed}`. | | `safety` | A security scan of the unknown token, when the value check could not run. | | `warnings` | `INSUFFICIENT_BALANCE`, `UNPRICED`, `OUTPUT_WRAPPED`, `NO_ROUTE`. | | `quoteId` · `expiresAt` | Rebuild with `POST /v1/meta/swap {quoteId, taker}` within 2 minutes; quote again after `expiresAt`. | Note the one difference from `/v1/quote`: its `outputAmount` is before Chord’s fee, `amountOut` here is after every fee, so answers from different providers compare directly. ## The checks on a fallback answer [Section titled “The checks on a fallback answer”](#the-checks-on-a-fallback-answer) A third-party answer is untrusted data until it passes all of these. One failure and the next provider is asked. 1. **Allowlist.** The transaction target and the approval spender must be that provider’s known router on that chain, and have code there. Anything else is refused, never returned. 2. **Calldata.** For KyberSwap the calldata is decoded: receiver, tokens and amount must be what you asked. 3. **Minimum.** `minAmountOut` comes from your slippage. A provider minimum below it is refused. 4. **Value guard.** An output worth 30 % less than the input at Chord’s own prices is refused, exactly as on `/v1/swap`. When Chord has no price for a side, the token is scanned (`safety`) and a honeypot is refused. 5. **Simulation.** With a `taker`, the transaction is run as that wallet and must deliver at least `minAmountOut` to it. A fallback transaction that cannot be simulated is never returned. The simulation runs the swap from the taker’s own address and measures the taker’s balance of the output token before and after, so it means the same thing for every aggregator. When the taker does not hold the input yet, the input is supplied for the simulation and the answer carries `INSUFFICIENT_BALANCE`. ## Quote, then sign [Section titled “Quote, then sign”](#quote-then-sign) ```bash # 1. Price (read-only) curl -s "https://api.getchord.xyz/v1/meta/quote?chain=base&tokenIn=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&tokenOut=0x4200000000000000000000000000000000000006&amount=10000000&slippageBps=50" # 2. The unsigned transaction for a wallet (simulated as that wallet) curl -s -X POST https://api.getchord.xyz/v1/meta/swap -H 'Content-Type: application/json' \ -d '{"chain":"base","tokenIn":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","tokenOut":"0x4200000000000000000000000000000000000006","amount":"10000000","slippageBps":50,"taker":"0xYourWallet"}' ``` Then, in your own wallet: 1. If `approval` is not `null`, send `token.approve(spender, amount)` and wait for it. 2. Sign and send `tx` on `tx.chainId`. Chord never signs and never holds funds. ## Reading the status codes [Section titled “Reading the status codes”](#reading-the-status-codes) | Answer | Meaning | | ----------------------- | ---------------------------------------------------------------------------------------------------------- | | `200`, `provider` set | A route. Read `provider` and `fallbackReason` first. | | `200`, `provider: null` | Every provider looked and none has a route. | | `400` | Your request: `INVALID_PARAMS`, `UNSUPPORTED_CHAIN`, `UNKNOWN_TOKEN`. | | `404` on `/meta/swap` | `NO_ROUTE`, with `attempts`. | | `410` on `/meta/swap` | `QUOTE_EXPIRED`: send the full params. | | `503 UNAVAILABLE` | Nobody could answer right now (timeouts, an open breaker). Retry in a few seconds; this is not “no route”. | ## For agents [Section titled “For agents”](#for-agents) * MCP and function calling: `chord_quote` and `chord_swap_tx` call this endpoint on every EVM chain ([MCP server](/docs/agents/mcp/), [tools manifest](/docs/agents/function-calling/)). * The [Agent Skill](/docs/agents/skill/) quotes through the meta aggregator first and checks the router of every answer against its own pinned list. * Solana is not on this endpoint: Solana swaps are `/v1/sol/trade/*`, where every quote builds Chord’s own Solana route and Jupiter’s for the wallet and keeps the better one. See [Solana](/docs/networks/solana/#swaps). # Quotes and routing > What a quote is, how the route is found, what the numbers mean, fees, slippage, the fast frame, and the honest no-route answer. `GET /v1/quote` is a live read of every venue on the chain for one pair and size. It is not a price feed: the answer is what you would get right now, on the route the engine would execute. ## How a route is found [Section titled “How a route is found”](#how-a-route-is-found) 1. **Every single-hop venue is quoted in parallel** — Uniswap V3 and V4 pools (including hooked launchpad pools on Arc), V2 pairs, and the forks the engine knows. 2. **Splits.** Within a hop the order can be split across venues (say 90 % in one pool and 10 % in another) when that improves the output beyond a small threshold, and only across distinct pools. 3. **Composed hops.** When no direct pool wins, the engine composes the best `A → anchor` leg with the best `anchor → B` leg through the chain’s anchors (USDC and EURC on Arc; WETH and USDG on Robinhood Chain). 4. **Safety gates.** Routes over 50 % impact are dropped, hooks the engine has not verified are not routed, and a paused venue is muted. The winner is returned with one `routePlan` entry per leg, each carrying the venue id, the pool, the amounts, and the adapter and calldata the router will use. Do not construct venue logic from these fields — pass the whole body to `/swap`. ## Reading the numbers [Section titled “Reading the numbers”](#reading-the-numbers) | Field | Meaning | | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `outputAmount` | What the route returns before the protocol fee, smallest unit. | | `feeBps` · `feeAmount` · `feeTier` | The protocol fee on the **output** token, per token, from the on-chain fee collector: 5 bps by default on every chain, 0 on USDC / EURC (Arc) and WETH / USDG / stocks (4663), capped at 100. `feeAmount` is deducted on-chain from `outputAmount`. | | `otherAmountThreshold` | The minimum output after fee and slippage — **the number the transaction enforces**. Positive slippage goes to the user. | | `priceImpactPct` | Percent, against the spot rate of the same route. Display only. | | `gasEstimate` | From the venue quoter or an RPC estimate. | | `blockNumber` | The block the venues were read at. | A quote is good for about 30 seconds. If the user waited longer, quote again before building. ## No route [Section titled “No route”](#no-route) An empty `routePlan` with `outputAmount: "0"` is a real answer: nothing on the chain fills this size. `noRouteReason` says `INSUFFICIENT_LIQUIDITY` (the pair routes at a smaller size — try one) or `NO_POOLS` (no venue holds the pair). The engine never fabricates a price. ## Slippage [Section titled “Slippage”](#slippage) `slippageBps` on the quote sets `otherAmountThreshold`. On `/swap` it is a consistency check only: the signed minimum is the quote’s threshold, which already folds in venue-specific widening the swap builder cannot re-derive. Sending a different value returns `400 SLIPPAGE_MISMATCH`. Want tighter or looser? Quote again. ## The fast frame [Section titled “The fast frame”](#the-fast-frame) `fast=1` returns a single-hop quote in about 400 ms with `preliminary: true`. Use it to paint a first number, run the full quote alongside, and replace. Never build a transaction from a preliminary quote. ## Debug: one venue [Section titled “Debug: one venue”](#debug-one-venue) `only=` restricts routing to one venue and returns its raw quote **before** the safety gates. It needs an API key, because a shared link with `?only=` would hand a user exactly the route the gate refuses. ## Simulate before you sign [Section titled “Simulate before you sign”](#simulate-before-you-sign) `POST /v1/swap/simulate` with the built transaction runs `eth_call` from the user’s address and estimates gas. A revert comes back decoded (`NotRouter`, a paused market, allowance or balance) so the wallet never opens on a doomed transaction. An allowance revert is advisory: approve, then swap. ## Where fees go [Section titled “Where fees go”](#where-fees-go) The fee is read per output token from the on-chain fee collector: 5 bps by default on every chain since 2026-10-02, 0 on the stablecoins and majors each chain exempts, capped at 100. It does not change with a token’s age. A referrer passed as `feeAccount` on `POST /v1/swap` earns 50 % of the fee on that swap; `/v1/meta/*` and the MCP tools take no referrer. Quotes and API usage are free. # Rate limits > Per-minute buckets, what shares them, the headers to read, and how to stay under. Limits are per minute and enforced in Redis. Every response carries three headers: ```plaintext X-RateLimit-Limit: 60 X-RateLimit-Remaining: 42 X-RateLimit-Reset: 1789891900 ``` Over the limit you get `429` with `{ "error": "RATE_LIMIT_EXCEEDED" }`. Wait for `X-RateLimit-Reset` (Unix seconds), then continue. The limiter fails open if the store is unreachable: a store outage never turns into a client outage. ## Buckets [Section titled “Buckets”](#buckets) Anonymous traffic is keyed by IP. A key is keyed by the key and gets the plan’s limit. Some families are read-heavy by nature and have their own, larger per-IP buckets, so a page that fans out on load cannot starve a swap from the same address. | Bucket | Applies to | Anonymous limit | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | | Default | `/quote`, `/swap`, `/arc/*`, `/rh/*`, `/lp/*`, `/smart-money/*`, `/points/*`, `/ask/*`, `/bridge2/*` and everything not below | 60 a minute per IP, or your plan with a key | | Data reads | `GET /tokens*`, `/portfolio/*`, `/market*`, `/stream/*` | 300 a minute per IP | | Logos | `GET /logo/*` | 3,000 a minute per IP | | Bridge polling | `GET /crosschain/status` | 240 a minute per IP | | Exempt | `/ws/live` upgrades | own connection and channel caps | The Ask agent adds its own guard: 8 questions a minute per caller, and a daily token budget for the deployment (`GET /v1/ask/status` shows it). ## Staying under [Section titled “Staying under”](#staying-under) * Poll boards at 10–30 s and token pages at 5–10 s; the answers are memoised server-side, and polling faster returns the same bytes. * Use `/v1/ws/live` for candles, trades and Arc prices instead of polling `/tokens/chart` and `/tokens/trades`. * One `/arc/tokens?limit=500` beats 500 token calls; one `/tokens/stats/{address}` beats four windowed calls. * Cache `/tokens?chain=` (the curated list) for an hour. * Quotes are the expensive call. Quote on user intent, not on every keystroke; the `fast=1` frame exists for the first paint. ## Capacity, not rate [Section titled “Capacity, not rate”](#capacity-not-rate) Two endpoints cap concurrency instead: `/v1/stream/market` at 500 clients and `/v1/ws/live` at 500 connections with 8 channels each. Both answer `503` when full. Reconnect with backoff. # Streaming > The public WebSocket (candles, trades, and the board-wide feed for Arc and Robinhood Chain — prices, 24h counters, first-time tokens) and the server-sent events feed, with the full protocol. Two push channels replace polling. Neither needs a key. | Channel | URL | Carries | Use it for | | ------------------ | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | WebSocket | `wss://api.getchord.xyz/v1/ws/live` | live candles per token and timeframe, trade tapes per token, and the board-wide feed per chain (every print, 24h volume and trade counts, tokens trading for the first time) | token pages, charts, boards and tickers on Arc and Robinhood Chain | | Server-sent events | `https://api.getchord.xyz/v1/stream/market` | Robinhood Chain prices every \~8 s (`rh-ticker`) | a fallback where WebSockets are blocked | ## WebSocket: `/v1/ws/live` [Section titled “WebSocket: /v1/ws/live”](#websocket-v1wslive) Open a socket, send JSON frames to subscribe, receive JSON frames. Up to **8 channels per connection**, 500 connections in total. The server pings every 25 seconds; reply is not required, but a proxy that idles at 100 s will not cut you. ### Subscribe [Section titled “Subscribe”](#subscribe) ```json { "op": "sub", "channel": "candles", "token": "0x171a4217b86a807a64eb94757db6849fb4bdbaa0", "tf": "1m" } { "op": "sub", "channel": "trades", "token": "0x171a4217b86a807a64eb94757db6849fb4bdbaa0" } { "op": "sub", "channel": "prices", "chain": 5042 } { "op": "sub", "channel": "prices", "chain": 4663 } ``` `tf` is one of `1m` · `1h` · `4h` · `1d` · `1w` (candles only). `prices` is keyed by chain, not token: `5042` (Arc), `4663` (Robinhood Chain) or `143` (Monad, prices only). A re-subscribe of a held channel re-acknowledges and re-sends the snapshot without counting twice. ### Frames from the server [Section titled “Frames from the server”](#frames-from-the-server) ```json { "op": "subbed", "channel": "candles", "token": "0x171a…", "tf": "1m" } { "op": "candle", "token": "0x171a…", "tf": "1m", "candle": { "t": 1789891800, "o": 80410.1, "h": 80425.0, "l": 80398.7, "c": 80418.3, "v": 1412.5 }, "closed": false } { "op": "trades", "token": "0x171a…", "items": [ { "tx": "0x…", "logIndex": 41, "dex": "uniswap_v3", "side": "buy", "tokenAmt": 0.0058, "usd": 472.37, "priceUsd": 80418.25, "ts": 1789891817, "wallet": "0x0e17…" } ] } { "op": "prices", "chain": 5042, "snapshot": true, "at": 1789891400120, "items": [ { "address": "0xece5…", "priceUsd": 0.01923, "ts": 1789891399, "block": 21808201, "side": "buy", "usd": 212.4, "volume24h": 48210.5, "buyVolume24h": 26011.2, "sellVolume24h": 22199.3, "trades24h": 1180, "buys24h": 640, "sells24h": 540 } ] } { "op": "new", "chain": 5042, "items": [ { "address": "0x9f2c…", "symbol": "TKN", "name": "Token", "decimals": 18, "logoURI": "https://api.getchord.xyz/v1/logo/5042/0x9f2c…", "totalSupply": 1000000000, "firstTs": 1789891402, "priceUsd": 0.0000412 } ] } { "op": "ping", "t": 1789891855000 } { "op": "error", "code": "bad_tf", "message": "tf must be one of 1m|1h|4h|1d|1w" } ``` * `candle` frames repeat the open candle as it updates; `closed: true` marks the last frame for a bucket. Seed the chart from `/v1/tokens/chart` first, then apply frames by `t`. * `trades` items have the same shape as `/v1/tokens/trades`. * `prices` sends a snapshot of recent prints on subscribe (the last 15 minutes), then one frame every \~400 ms carrying only the tokens that traded. Apply by `address`; later `block` wins. * On Arc and Robinhood Chain each item also carries the token’s 24h counters **as the board should show them now**: the hourly rollup plus every trade since. Robinhood Chain has no buy/sell split, so only `volume24h` and `trades24h` appear there. `at` is the server time of the frame in milliseconds — REST boards carry `updatedAt` on the same clock, and the later of the two is the current number (the API adds the same not-yet-rolled trades to both, so switching between them never double counts). * `new` (Arc and Robinhood Chain) announces a token trading for the first time — neither the 24h board nor the feed had seen it — with its on-chain name and `totalSupply` in whole tokens (market cap = `totalSupply × priceUsd`). A snapshot of up to 100 recent ones follows the `prices` snapshot when there are any; a `prices` snapshot means start the list over. Unscreened: for the screened list use `GET /v1/arc/graduated`. * Error codes: `bad_op` · `bad_token` · `bad_tf` · `bad_chain` · `channel_cap`. ### Unsubscribe [Section titled “Unsubscribe”](#unsubscribe) ```json { "op": "unsub", "channel": "candles", "token": "0x171a…", "tf": "1m" } { "op": "unsub", "channel": "prices", "chain": 5042 } ``` ### Browser example [Section titled “Browser example”](#browser-example) ```ts const ws = new WebSocket("wss://api.getchord.xyz/v1/ws/live"); ws.onopen = () => { ws.send(JSON.stringify({ op: "sub", channel: "prices", chain: 5042 })); ws.send(JSON.stringify({ op: "sub", channel: "candles", token, tf: "1m" })); }; ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.op === "prices") for (const it of m.items) prices.set(it.address, it); // price + 24h counters if (m.op === "new") for (const t of m.items) newest.unshift(t); if (m.op === "candle") chart.update(m.candle, m.closed); }; ws.onclose = () => setTimeout(reconnect, 1000 + Math.random() * 2000); ``` Reconnect with jittered backoff and re-subscribe; the server keeps no state for a closed socket. ## Server-sent events: `/v1/stream/market` [Section titled “Server-sent events: /v1/stream/market”](#server-sent-events-v1streammarket) An `EventSource` feed with automatic reconnect built into the browser. Exactly these events: | `event:` | Cadence | Data | | ---------------------------- | ----------------------------------------- | ------------------------------------------------------------------------ | | `rh-ticker` | about every 10 s, only when a price moved | `{ "items": [ { "address", "priceUsd", "change24h" } ] }` for chain 4663 | | `ticker` · `whales` · `defi` | 15–60 s | Monad boards — ignore on Chord | | `ping` | 5 s | a timestamp | ```ts const es = new EventSource("https://api.getchord.xyz/v1/stream/market"); es.addEventListener("rh-ticker", (e) => { for (const it of JSON.parse(e.data).items) prices.set(it.address, it.priceUsd); }); ``` Capacity is 500 concurrent clients; `503` beyond that. A closed feed reconnects on its own. ## Which to use [Section titled “Which to use”](#which-to-use) * The whole Arc or Robinhood Chain board — prices, volume, trade counts, new tokens: WebSocket `prices`. * Where WebSockets are blocked: SSE `rh-ticker` (Robinhood Chain prices only). * One token’s chart or tape, either chain: WebSocket `candles` / `trades`. * Anything else: poll the REST endpoint at the cadence in [Rate limits](/docs/concepts/rate-limits/). # Wallet PnL and Smart Score > How portfolio PnL is computed from the tape, what is excluded, and how the top-wallets board ranks. ## Average-cost PnL [Section titled “Average-cost PnL”](#average-cost-pnl) `/v1/portfolio/{wallet}/pnl` replays the wallet’s swaps from the tape, in order, with an average-cost basis per token: * A **buy** adds to the position and raises or lowers the average cost. * A **sell** realizes `(price − average cost) × amount` against that average and reduces the position. * What is still held is marked at the current price (`priceUsd` on the token’s dominant venue) as **unrealized**. `realized`, `unrealized` and `total` are the sums; per token you also get `avgCost`, `curAmount`, `curValue`, `costRemaining` and `roiPct`. The calendar (`/pnl-calendar`) sums the same realized events by UTC day, so it reconciles with `realized` by construction. ### What is excluded [Section titled “What is excluded”](#what-is-excluded) * **Transfers.** A balance that arrived by transfer has no cost basis. It is reported as `untrackedAmount` / `untrackedValue` and left out of PnL. Airdrops, bridged funds and CEX withdrawals fall here. * **Liquidity.** Adding to or removing from a pool is not a swap. LP results live in `/v1/lp/positions`. * **Gas.** Not deducted. ### Freshness [Section titled “Freshness”](#freshness) The compute walks the wallet’s whole tape and is cached with stale-while-revalidate: a fresh answer for a minute, a stale one served for up to a day while a refresh runs behind it. An empty result is never cached over a real one. If the tape read fails you get an empty 200 shape, not a 5xx. ## Smart Score [Section titled “Smart Score”](#smart-score) `/v1/smart-money/top` ranks wallets on the tape by a **Smart Score**, not raw profit: * **Realized-weighted.** Money taken off the table counts more than paper gains. * **Luck-corrected.** Win rate is shrunk toward the mean for wallets with few trades (`winRateAdj`), so one lucky launch does not top the board. * **Recency-decayed.** Recent skill counts more than old. Before ranking, routers, executors and bots are removed — by cadence (hundreds of transactions a day from a wallet’s first trade), by nonce rate and deny lists, and by behaviour (bursts, sub-minute round trips, sniping dozens of launches). `botsRemoved` counts each pass; `totalWallets` is what qualified. Each row carries its archetype (`degen`, `allrounder`, …), meme share, and top token. The board is rebuilt per window (15 minutes for 24h, hourly for 7d and 30d, three hours for all) and served from cache between rebuilds. On Arc a live delta of the last minutes’ trades sits on top, so the board moves between polls; `live` in the response shows its state. # Agents on Chord > The same API as tools for models — an MCP server, a function-calling manifest, the Ask agent API, and llms.txt for retrieval. Chord is built for agents first: every number the app shows is one GET away, amounts are strings, errors are stable codes, and nothing needs a browser. The ways in: | Path | What it is | Best for | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | [Docs MCP](/docs/agents/docs-mcp/) | this documentation as tools — search, read a page, look up an endpoint with a real example; hosted at `getchord.xyz/docs/mcp` | any agent writing code against the API; no key, no install | | [Agent skill](/docs/agents/skill/) | `SKILL.md`, references and a dependency-free Python client in the Agent Skills format; one `curl` loop installs it, no repository access | Claude Code, Codex, OpenClaw, Hermes: read prices and boards on every chain, quote, prepare an unsigned swap | | [MCP server](/docs/agents/mcp/) | hosted at `api.getchord.xyz/v1/mcp`: 17 tools, every chain as a parameter, one URL per chain with `?chain=` | Claude Code, Claude Desktop, Cursor, any MCP client; no install, key optional | | [Function calling](/docs/agents/function-calling/) | the same tools as OpenAI-style JSON Schema, public at `api.getchord.xyz/v1/mcp/tools.json` | OpenAI, LangChain, anything that takes a manifest | | [Ask agent API](/docs/agents/ask-api/) | `POST /v1/ask` — Chord’s own analyst over the index, 40+ tools, one JSON answer | judgement questions: is this launch real, where is support, who is buying | | [llms.txt](/docs/agents/llms-txt/) | this documentation as plain text, every page as Markdown, the OpenAPI document, and the discovery files (`/.well-known/api-catalog`, `ai-catalog.json`, `agent-skills/index.json`) | retrieval, system prompts, codegen by a model, finding Chord’s tools from the domain alone | ## Prepare, then sign [Section titled “Prepare, then sign”](#prepare-then-sign) The API is non-custodial. A tool that trades returns an **unsigned transaction**; the agent’s own wallet signs it and broadcasts it to the chain it names. Chord never sees a private key, never holds funds, never broadcasts. Read `otherAmountThreshold` before signing — it is the minimum the transaction enforces — and simulate with `POST /v1/swap/simulate` when the wallet cannot. ## Which tool for which question [Section titled “Which tool for which question”](#which-tool-for-which-question) * Raw numbers — prices, a token’s tape, who launched what, a wallet’s PnL: the data tools (MCP / manifest) or the REST endpoints directly. Fast, deterministic, free. * Judgement — “is ARGUS still being bought by real wallets”, “give me an entry ladder”, “compare these three launches”: the Ask agent. 5–40 s, metered, needs a key. * Trading: `chord_quote` then `chord_swap_tx`, or the REST pair `/quote` → `/swap`, on any EVM chain Chord routes; Solana swaps go through `/v1/sol/trade/*`. ## Keys [Section titled “Keys”](#keys) Read tools work without a key at the anonymous limit. Set `CHORD_API_KEY` (MCP) or send `X-API-Key` (manifest, REST) to run at your plan’s limit; the Ask agent requires one. Keys come from [getchord.xyz/developer](https://getchord.xyz/developer). # Ask agent API > POST /v1/ask — Chord's analyst over the Arc index and the router, as an API for other agents. One JSON answer, sources, a route card, tables. Ask is the analyst behind the chat on getchord.xyz. It has 40+ tools over the Arc index and the router — trending, a token’s flow, holders and risk, support and resistance, top traders on a token, a wallet’s PnL and trades, largest prints, launches and launchers, depth, a bridge quote, read-only SQL over the index — and answers in plain language with the sources it read. The same agent is available to your agent. ## Call it [Section titled “Call it”](#call-it) ```bash curl -X POST https://api.getchord.xyz/v1/ask \ -H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \ -d '{ "question": "Is ARGUS still being bought by real wallets, and where is support?", "stream": false }' ``` * **Auth**: an API key (`X-API-Key`). The browser uses a Google session instead; agents use a key. * **`stream: false`** returns one JSON answer in 5–40 s. Without it the response is `text/event-stream` (below). * **`history`**: up to 12 prior turns `{ role, content }` for a conversation. * **`wallet`**: the agent’s wallet, so “my PnL” and “my positions” resolve. * **`mode`**: `"quick"` or `"deep"`, the chat’s answer switch. Quick returns the shortest form of the answer (the verdict, its claim, at most three rows of evidence, 120 words at most) and runs faster. Deep returns a judgement or an explanation as a full research note (`shape: "report"`), and any other answer with a longer `details`. Leave it out for the length the question calls for; any other value is ignored. * **Limits**: 8 questions a minute per key, metered per key per day against the deployment’s token budget (`GET /v1/ask/status`). ## The answer [Section titled “The answer”](#the-answer) ```json { "text": "**ARGUS is still being bought by real wallets: 59.8% of the last hour's buying is not bots or routers.** Confidence: medium (…)\n\n| Level | Price | vs now % | Why |\n| --- | --- | --- | --- |\n| Support | 0.0181 | … | … |\n\n**Against:** …\n\n*… UTC. Chord's Arc index.*", "shape": "brief", "parts": [ { "t": "md", "text": "**ARGUS is still being bought by real wallets: 59.8% of the last hour's buying is not bots or routers.** Confidence: medium (…)" }, { "t": "viz", "i": 0 }, { "t": "md", "text": "**Against:** …\n\n*… UTC. Chord's Arc index.*" } ], "details": null, "viz": [ { "kind": "table", "title": "ARGUS · key levels on the tape", "columns": [ "Level", "Price", "vs now %", "Why" ], "rows": [ … ] } ], "followUps": [ "Who are the top buyers of $ARGUS this hour?", "…", "Alert me if ARGUS closes below 0.0176" ], "followUpKinds": [ "deeper", "ask", "alert" ], "assets": [ { "symbol": "ARGUS", "label": "…", "price": …, "change24hPct": 12.7 } ], "focus": 0, "citations": [ { "label": "ARGUS on Arc", "href": "/arc/token/0xece5…" } ], "quote": null, "artifact": { "kind": "token", "token": { "address": "0xece5…", "symbol": "ARGUS" }, "stats": { … }, "analysis": { … }, "report": null }, "toolsUsed": ["arc_token", "arc_price_analysis", "arc_token_traders"], "tokens": 9120 } ``` | Field | Meaning | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `text` | The answer, Markdown, complete on its own. A table the answer placed is written out here as a Markdown table (its first 8 rows and 6 columns), so a client that reads only `text` shows the whole answer. | | `shape` | The kind of answer the question got: `fact` · `explain` · `brief` (a call with its evidence) · `board` (a ranked list) · `why` · `overview` · `compare` · `post` (something to paste or a chart) · `do` (steps on Chord) · `report` · `auto`. | | `parts` | The same answer in order, for a client that draws blocks: `{ "t": "md", "text" }` is text, `{ "t": "viz", "i" }` is the table or chart `viz[i]` placed at that point. | | `details` | `{ text, parts }` or `null`: further depth (a per-venue breakdown, a longer history) that the chat folds under “Show full analysis”. It is not repeated in `text`. | | `viz` | Tables and charts from real numbers (`kind`: `table` · `bar` · `line` · `donut`), at most 6. The ones `parts` and `details` place come first, in that order; the rest were not placed in the text. A client that draws `text` and then `viz` should skip the tables `parts` points at: `text` already holds them. | | `followUps` · `followUpKinds` | Up to three next questions, and for each whether it is `deeper` (into this answer), an `alert` to set, or another `ask`. | | `assets` · `focus` | Price chips for the assets the answer names; `focus` is the index of the one asset the answer is about, or `null`. | | `citations` | Where to check the numbers: `{ label, href }` per source. `href` is a Chord page as a path under `https://getchord.xyz` (`/arc/token/0x…`), or the source’s own URL. | | `quote` | A route card when the question implied a trade: the two tokens, the amounts in whole tokens, the venues, price impact, fee and a link to the trade on Chord. It is a preview, not a `/v1/quote` response: `/v1/swap` needs a fresh `/v1/quote`. | | `artifact` | The token the answer is about: its stats, where volume traded (support, resistance, VWAP) and a report link when one was built. No entry ladder, stop or targets: levels are a reading of the tape, not orders. | | `toolsUsed` · `tokens` | What ran and what it cost. | `shape`, `parts`, `details`, `followUpKinds` and `focus` are optional: an answer that asks you something back leaves `shape`, `parts` and `followUpKinds` out, with `details` and `focus` at `null`. Ignore all five and `text` plus `viz` is still the whole answer, without the folded `details`. Errors: `401 UNAUTHORIZED` (no key), `429 RATE_LIMITED`, `503 DISABLED` (the analyst is off), `503 EMPTY` (no answer produced — ask again, more specifically). ## Streaming [Section titled “Streaming”](#streaming) Without `stream: false`, the response is server-sent events: `status` frames name the tool running (`{ "tool": "arc_price_analysis", "label": "Reading the tape" }`), one `answer` frame carries the object above, `error` carries `{ code, message }`, and `done` closes. Use it for a UI that shows progress; agents want the JSON. ## Picks and reports [Section titled “Picks and reports”](#picks-and-reports) * `GET /v1/ask/picks` — the analyst’s current board (rebuilt every four hours over tokens with real activity): side, score, confidence, reasons for and against, and the seven-day track record (picks graded, the share that moved their way, average move). No targets or stops. Public. * `POST /v1/ask/report { token }` — a three-page research note for a token (HTML for print-to-PDF, and Markdown), links good for seven days. Session-gated today. ## What to ask [Section titled “What to ask”](#what-to-ask) It answers like a trader’s analyst: from the index first, and from outside market data, news headlines and posts on X where the question needs them. Good questions: “what is moving on Arc and why”, “launch forensics on 0x…”, “top PnL wallets on Minara and how they traded it”, “is TOLLY a buy here, and what would change that”, “which pools pay real fees on USDC pairs”. It takes a position and shows the evidence for it, and it says when the data is thin. A plan (zones, tranches, an exit, the level where the idea is wrong) is written only when you ask for one, as illustrative scenarios with their assumptions stated, never as advice. # Docs MCP > Give your agent the Chord documentation as tools — search, read a page, look up an endpoint with its real example — hosted at getchord.xyz/docs/mcp or run locally over stdio. The Chord Docs MCP is this documentation as a Model Context Protocol server: an agent searches the docs, reads a page, or pulls an endpoint’s exact parameters, response shape and a real example — instead of guessing from training data. It is read-only and never calls the Chord API; when the agent also needs live numbers, pair it with the hosted [MCP server](/docs/agents/mcp/), the [Agent skill](/docs/agents/skill/) or direct API calls. ## Hosted [Section titled “Hosted”](#hosted) One URL, no install, Streamable HTTP: ```plaintext https://getchord.xyz/docs/mcp ``` **Claude Code** ```bash claude mcp add --transport http chord-docs https://getchord.xyz/docs/mcp ``` **Claude Desktop, Cursor, Windsurf, any client with an `mcpServers` config** ```json { "mcpServers": { "chord-docs": { "type": "http", "url": "https://getchord.xyz/docs/mcp" } } } ``` **Codex, OpenAI Agents SDK and other clients that take a URL**: point them at the same address. The server is stateless (no session ids), answers JSON to a `POST`, and allows any origin. Its server card ([MCP SEP-2127](https://modelcontextprotocol.io/seps/2127-mcp-server-cards)) is at [`https://getchord.xyz/docs/mcp/server-card`](https://getchord.xyz/docs/mcp/server-card), and the site’s AI catalog ([`/.well-known/ai-catalog.json`](https://getchord.xyz/.well-known/ai-catalog.json)) lists it. ## Local (stdio) [Section titled “Local (stdio)”](#local-stdio) The same server also runs over stdio, for an offline client or one that only speaks stdio, but only from a checkout of the Chord repository (`packages/docs-mcp`), which is not public yet. Outside it, use the hosted URL above: same server, same index. ```bash # from a checkout of the Chord repository pnpm install --filter @nullterminal/docs-mcp claude mcp add chord-docs -- node $PWD/packages/docs-mcp/stdio.mjs ``` It fetches the docs index from getchord.xyz on start and refreshes it every 30 minutes. `DOCS_INDEX_URL` points it elsewhere; `DOCS_INDEX_FILE` uses a local build of the docs. ## Tools [Section titled “Tools”](#tools) | Tool | What it does | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `search_chord_docs` | Full-text search over every page and every endpoint; returns matching sections and operations with a snippet and URL. `kind` narrows to pages or operations. | | `read_chord_docs_page` | The full Markdown of one page (or one section with `#anchor`) by path, e.g. `/docs/concepts/streaming/`. | | `chord_api_reference` | An endpoint’s method, path, every parameter with type / enum / default, the request body, the response shape and a real example captured from the live API. Look up by operationId (`getQuote`), path (`/v1/arc/tokens`) or words. | | `list_chord_docs_pages` | Every page with its description, grouped by section, plus the API tags — for orientation. | The server also sends `instructions` on connect (base URL, the amounts rule, the Arc USDC alias), so a model that only calls one tool still gets the facts it most often gets wrong. ## What the index is [Section titled “What the index is”](#what-the-index-is) A JSON built with the site — every page’s Markdown split into sections, every OpenAPI operation with its parameters, response outline and example — published at [`/docs/docs-index.json`](/docs/docs-index.json) and rebuilt on every deploy. Search is a small in-memory scorer; a query answers in a few milliseconds. ## Tested with Claude [Section titled “Tested with Claude”](#tested-with-claude) Both transports were verified with Claude Code in headless mode: the model was told to answer only from the MCP, and it called `search_chord_docs` then `read_chord_docs_page` / `chord_api_reference` and returned the exact WebSocket subscribe frame and the holders endpoint with the doc URLs. Run the same check yourself: ```bash claude -p "Using only the chord-docs MCP, how do I subscribe to live Arc prices over WebSocket?" \ --allowedTools "mcp__chord-docs__*" ``` # Function calling > The Chord agent tools as an OpenAI-style JSON Schema manifest, always current, for any framework that takes a tool list. `https://api.getchord.xyz/v1/mcp/tools.json` is the tool set as JSON Schema: a `tools` array in the OpenAI function format, the `base_url`, the MCP endpoint and the `auth` header. It is public, needs no install, and is printed from the same list the [hosted MCP server](/docs/agents/mcp/) serves, so it never lags behind it. A copy also lives at `https://getchord.xyz/agent/tools.json`. ```bash curl -s https://api.getchord.xyz/v1/mcp/tools.json | jq '{base_url, mcp, auth, tools: [.tools[].function.name]}' ``` ```json { "base_url": "https://api.getchord.xyz", "mcp": "https://api.getchord.xyz/v1/mcp", "auth": { "header": "X-API-Key", "required": false }, "tools": ["chord_chains", "chord_status", "chord_overview", "chord_tokens", "chord_search", "chord_token", "chord_trades", "chord_candles", "chord_wallet", "chord_wallet_trades", "chord_smart_money", "chord_holders", "chord_lp_pools", "chord_lp_positions", "chord_quote", "chord_swap_tx", "chord_ask"] } ``` ## A minimal loop [Section titled “A minimal loop”](#a-minimal-loop) Hand `tools` to the model. When it returns a tool call, send that call to the MCP endpoint as one JSON-RPC message and give the text back to the model. No MCP library is needed: it is one POST. ```ts const manifest = await fetch("https://api.getchord.xyz/v1/mcp/tools.json").then((r) => r.json()); const tools = manifest.tools; // OpenAI format: { type: "function", function: { name, description, parameters } } async function runChordTool(name: string, args: object) { const res = await fetch(manifest.mcp, { method: "POST", headers: { "content-type": "application/json", ...(process.env.CHORD_API_KEY ? { "X-API-Key": process.env.CHORD_API_KEY } : {}) }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name, arguments: args } }), }).then((r) => r.json()); return res.result.content[0].text; // JSON text: { chain, route, data }; res.result.isError marks a tool-level error } // 1. ask the model with the tools attached // 2. for each tool_call the model returns: for (const call of message.tool_calls) { const result = await runChordTool(call.function.name, JSON.parse(call.function.arguments)); messages.push({ role: "tool", tool_call_id: call.id, content: result }); } // 3. ask the model again with the tool results ``` Every data tool takes a `chain` (`monad`, `robinhood`, `arc`, `avalanche`, `base`, `bnb`, `arbitrum`, `ethereum`, `solana`). To default one, POST to `https://api.getchord.xyz/v1/mcp?chain=arc` instead. Tools take addresses and integer amounts in the token’s smallest unit; `chord_search` turns a symbol into an address, and the token’s `decimals` come back with it. Each answer names the REST `route` that produced it. If you would rather call REST yourself, [`GET /v1/chains`](/docs/api-reference/) lists the route of every capability on every chain. ## The trading pair [Section titled “The trading pair”](#the-trading-pair) `chord_quote` returns the route, the expected output and a `quoteId`; `chord_swap_tx` returns the unsigned transaction for that `quoteId` and a taker, with the approval it needs and a simulation. Both work on the eight EVM chains; Solana swaps are REST only (`/v1/sol/trade/*`). The model proposes; your code signs, or shows the user what would be signed. Never let a model hold a key. ## Direct REST as tools [Section titled “Direct REST as tools”](#direct-rest-as-tools) For a framework that generates tools from an OpenAPI document (LangChain’s OpenAPI toolkit, an OpenAI Actions schema, a Gemini extension), point it at [openapi.json](/docs/openapi.json). Every operation has an `operationId`, a summary a model can read, and examples. # llms.txt, Markdown and discovery files > This documentation as plain text and as Markdown pages for retrieval and system prompts, the machine-readable API contract, and the files that let an agent find Chord's tools from the domain alone. | File | What | Size | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | [`/llms.txt`](/llms.txt) (also [`/docs/llms.txt`](/docs/llms.txt)) | What Chord is, then every page of this documentation with a one-line description, the API, the agent integrations and the app ([llmstxt.org](https://llmstxt.org) format) | small | | `/docs/.md` | Any page as Markdown: add `.md` to the page’s path (`/docs/agents/mcp/` → [`/docs/agents/mcp.md`](/docs/agents/mcp.md)), or ask for the page with `Accept: text/markdown`. API operations too ([`/docs/api-reference.md`](/docs/api-reference.md) lists them) | per page | | [`/llms-full.txt`](/llms-full.txt) (also `/docs/llms-full.txt`) | Every page of this documentation, concatenated | large | | [`/docs/llms-small.txt`](/docs/llms-small.txt) | The same, minified — for a context window that needs the whole thing | medium | | [`/openapi.json`](/openapi.json) (also `/docs/openapi.json`) | The OpenAPI 3.1 contract: every endpoint, parameter, schema and example | large | ## Discovery files [Section titled “Discovery files”](#discovery-files) An agent that only knows `getchord.xyz` finds everything else from these: | File | Standard | Points to | | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | [`/.well-known/api-catalog`](/.well-known/api-catalog) | RFC 9727 (linkset) | the REST API with its OpenAPI document, docs and status; both MCP servers; the skill index | | [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json) | AI Catalog ([MCP SEP-2127](https://modelcontextprotocol.io/seps/2127-mcp-server-cards)) | the server cards of the [MCP server](/docs/agents/mcp/) and the [Docs MCP](/docs/agents/docs-mcp/) | | [`/.well-known/agent-skills/index.json`](/.well-known/agent-skills/index.json) | [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) | the [Chord skill](/docs/agents/skill/) archive and its SHA-256 digest | | [`/robots.txt`](/robots.txt) | robots + Content Signals | crawlers, assistants and agents allowed (`search`, `ai-input`, `ai-train` = yes); both sitemaps | `api.getchord.xyz` answers `/.well-known/api-catalog`, `/.well-known/ai-catalog.json` and `/robots.txt` too, and `GET https://api.getchord.xyz/` returns the same links as JSON. ## In a system prompt [Section titled “In a system prompt”](#in-a-system-prompt) Paste `llms.txt` and let the model fetch the `.md` pages it needs, or paste `llms-small.txt` when the model must answer without fetching. Add the two facts models get wrong most: ```plaintext Chord API base: https://api.getchord.xyz/v1. Amounts are decimal strings in the token's smallest unit. On Arc (chain 5042) USDC is the gas token; send the ERC-20 predeploy 0x3600000000000000000000000000000000000000 (6 decimals); the zero address is an alias for it and transactions always have value 0. ``` ## For codegen by a model [Section titled “For codegen by a model”](#for-codegen-by-a-model) Give it `openapi.json`. Every operation has an `operationId`, constraints on parameters (enums, ranges, patterns), a response schema, and a real example captured from the live API. ## For a retrieval index [Section titled “For a retrieval index”](#for-a-retrieval-index) Fetch `llms-full.txt` and split on the page separators; each page starts with its title and URL. Refresh daily — the file is rebuilt with every deploy of the docs. # MCP server > The hosted Chord MCP server. One URL, 17 tools, every chain Chord serves as a tool parameter. Market data, quotes and unsigned swap transactions for any MCP client, no install. Chord runs an MCP server at `https://api.getchord.xyz/v1/mcp`. Add the URL to an MCP client and 17 tools appear: boards, tokens, trades, candles, wallets, smart money, holders and liquidity pools on Ethereum, Arbitrum One, Base, BNB Chain, Avalanche, Monad, Arc, Robinhood Chain and Solana, plus quotes and unsigned swap transactions on the eight EVM chains. Every data tool takes a `chain`. Nothing signs or sends: `chord_swap_tx` returns a transaction for the taker’s own wallet. ## Add it [Section titled “Add it”](#add-it) **Claude Code** ```bash claude mcp add --transport http chord https://api.getchord.xyz/v1/mcp ``` **Any client that takes a config** ```json { "mcpServers": { "chord": { "type": "http", "url": "https://api.getchord.xyz/v1/mcp", "headers": { "X-API-Key": "optional: raises the rate limit; chord_ask needs it" } } } } ``` The server is stateless Streamable HTTP with JSON answers. It needs no session and no OAuth: the handshake and the tool list work without credentials. ## One URL per chain [Section titled “One URL per chain”](#one-url-per-chain) Add `?chain=` and the endpoint defaults to that chain. `chain` stops being a required argument and the server names itself after the chain. ```plaintext https://api.getchord.xyz/v1/mcp?chain=arc https://api.getchord.xyz/v1/mcp?chain=monad https://api.getchord.xyz/v1/mcp?chain=solana ``` Keys: `monad`, `robinhood`, `arc`, `avalanche`, `base`, `bnb`, `arbitrum`, `ethereum`, `solana`. A call may still pass another `chain`. ## Discovery [Section titled “Discovery”](#discovery) Clients and registries can find the server without being given the URL: * **Server card** ([MCP SEP-2127](https://modelcontextprotocol.io/seps/2127-mcp-server-cards)): [`https://api.getchord.xyz/v1/mcp/server-card`](https://api.getchord.xyz/v1/mcp/server-card) gives the name, version, transport, protocol versions and the optional key header. It has no tool list: read that live with `tools/list`. * **AI catalog**: [`https://getchord.xyz/.well-known/ai-catalog.json`](https://getchord.xyz/.well-known/ai-catalog.json) lists this server and the [Docs MCP](/docs/agents/docs-mcp/), each with its card. * **API catalog** (RFC 9727): [`https://getchord.xyz/.well-known/api-catalog`](https://getchord.xyz/.well-known/api-catalog) links the REST API, both MCP servers, their docs and status. * **MCP Registry**: `io.github.getchordlabs/chord`. ## Keys and limits [Section titled “Keys and limits”](#keys-and-limits) A tool call is an ordinary API request made as you. Without a key it runs at the anonymous limit of the address you call from. With `X-API-Key` (or `Authorization: Bearer `, or `?apiKey=` for connectors that cannot set a header) it is metered and limited as that key. The handshake and the tool list are free. Keys come from the [developer page](https://getchord.xyz/developer). ## Tools [Section titled “Tools”](#tools) | Tool | Arguments | Returns | | --------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `chord_chains` | none | every chain with its native asset, anchors, and which capabilities it has | | `chord_status` | none | per chain: routing engine state and how far the newest indexed trade is behind the chain | | `chord_overview` | `chain` | last 24 hours: volume, swaps, venue share, hourly buckets | | `chord_tokens` | `chain`, `sort`, `limit` | the 24h token board | | `chord_search` | `chain`, `query` | tokens matching a symbol, name or address | | `chord_token` | `chain`, `address` | one token: price, volume, trades, pools or venues | | `chord_trades` | `chain`, `address`, `limit` | the newest swaps of a token | | `chord_candles` | `chain`, `address`, `tf`, `limit` | OHLCV candles from Chord’s index | | `chord_wallet` | `chain`, `wallet` | realised and open PnL per token | | `chord_wallet_trades` | `chain`, `wallet` | a wallet’s recent swaps | | `chord_smart_money` | `chain`, `days`, `limit` | wallets ranked by profit, bots removed | | `chord_holders` | `chain`, `address`, `limit` | balances by address | | `chord_lp_pools` | `chain`, `limit` | pools ranked for a liquidity provider | | `chord_lp_positions` | `chain`, `wallet` | a wallet’s liquidity positions | | `chord_quote` | `chain`, `tokenIn`, `tokenOut`, `amount`, `slippageBps`, `taker` | the best quote; Chord’s router first, another aggregator only when Chord cannot route | | `chord_swap_tx` | `quoteId` or the pair and amount, `taker` | the unsigned transaction, its approval and a simulation | | `chord_ask` | `question`, `wallet` | the analyst’s researched answer (needs a key) | Amounts are integer strings in the token’s smallest unit. The zero address is the native asset on EVM chains. Solana addresses are base58 and case-sensitive. ## Not every chain has everything [Section titled “Not every chain has everything”](#not-every-chain-has-everything) `chord_chains` returns the live list. A tool called for a chain that lacks the capability answers with the chains that have it, for example: `base has no holders data. Chains with it: robinhood, arc.` | Capability | Monad | Robinhood | Arc | Avalanche | Base | BNB | Arbitrum | Ethereum | Solana | | -------------------------------------------------------- | ----- | --------- | --- | --------- | ---- | --- | -------- | -------- | ------ | | Overview, tokens, search, token, trades, candles, wallet | yes | yes | yes | yes | yes | yes | yes | yes | yes | | Wallet trades | yes | yes | yes | yes | yes | yes | yes | yes | yes | | Smart money | yes | yes | yes | no | no | no | no | no | yes | | Holders | no | yes | yes | no | no | no | no | no | no | | LP pools and positions | yes | yes | yes | no | no | no | no | no | yes | | Quote and swap transaction | yes | yes | yes | yes | yes | yes | yes | yes | no | Solana swaps are open on REST, not yet in the MCP tools: [`GET /v1/sol/trade/quote`](/docs/networks/solana/) answers with the unsigned transaction, the wallet signs it unchanged and `POST /v1/sol/trade/send` relays it. `chord_quote` called for Solana answers with those steps, and `chord_chains` lists Solana’s `quote` and `swap` as those two routes. The same table as data: [`GET /v1/chains`](/docs/api-reference/). ## What an answer looks like [Section titled “What an answer looks like”](#what-an-answer-looks-like) Each tool returns one JSON text block: the chain, the REST route that produced it, and that route’s body. ```json { "chain": "arc", "route": "GET /v1/arc/overview", "data": { "chain": 5042, "last24h": { "volUsd": 15625106.36, "swaps": 133764 } } } ``` The `route` is the endpoint to call if you want the same data without MCP. Large answers are shortened by dropping rows from the end of long lists, with a count of what was dropped; the JSON is always valid. ## Clients that only speak stdio [Section titled “Clients that only speak stdio”](#clients-that-only-speak-stdio) `chord-agent` in the Chord repository is a stdio bridge to the same hosted server: it lists and calls the tools above over HTTP, so it never goes out of date. It is not on npm yet. From a checkout: ```bash cd packages/agent && pnpm install && pnpm build claude mcp add chord -- node /absolute/path/to/packages/agent/dist/mcp.js ``` Environment: `CHORD_API_KEY` (optional), `CHORD_CHAIN` (optional default chain), `CHORD_API_URL` (default `https://api.getchord.xyz`). ## Related [Section titled “Related”](#related) * [Function calling](/docs/agents/function-calling/): the same tools as an OpenAI-style manifest. * [Docs MCP](/docs/agents/docs-mcp/): a second hosted server that answers questions about this documentation. * [Status](https://getchord.xyz/status): uptime of the API on every chain, measured every minute from outside Chord’s servers. # Agent skill > The Chord Agent Skill (SKILL.md + references + a small client) for Claude Code, Codex, OpenClaw, Hermes and any agent that reads the Agent Skills format. The Chord skill teaches an agent to use Chord the way a careful trader’s assistant would: read prices, boards, candles, holders and wallet PnL on all eight EVM chains, quote a swap across every venue, and prepare an unsigned transaction, without ever signing anything itself. It follows the open [Agent Skills](https://agentskills.io) format, so Claude Code, Codex, OpenClaw, Hermes and other agents load it the same way. ## Install [Section titled “Install”](#install) One command, no repository access needed. It unpacks the whole skill (SKILL.md, references, the client) into the folder your agent reads: ```bash mkdir -p ~/.claude/skills/chord && curl -fsSL https://getchord.xyz/.well-known/agent-skills/chord.tar.gz | tar -xz -C ~/.claude/skills/chord ``` Or with the [`skills`](https://www.npmjs.com/package/skills) CLI, which reads the site’s discovery index (`-a` picks the agent; `-g` installs for your user instead of the project): ```bash npx skills add https://getchord.xyz -s chord -a claude-code ``` Tools that follow [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) find it from the domain alone: [`https://getchord.xyz/.well-known/agent-skills/index.json`](https://getchord.xyz/.well-known/agent-skills/index.json) lists the archive with its SHA-256 digest, so a client can check the bytes before loading them. `SKILL.md` by itself is at [`https://getchord.xyz/skill.md`](https://getchord.xyz/skill.md), and every file is also under `/docs/skills/chord/` (table below). Then, from that folder, `bash scripts/install.sh` copies it to `~/.agents/skills/chord` as well and prints the paths for OpenClaw (`~/.openclaw/skills/chord`) and Hermes (`~/.hermes/skills/chord`). For one project only: `bash scripts/install.sh --project /path/to/project` (writes `.claude/skills/chord` there). The installer is idempotent and only replaces a folder that already holds this skill. Optional: `export CHORD_API_KEY=...` raises the rate limit and unlocks [Chord Ask](/docs/agents/ask-api/). Data calls work without a key at 60 requests a minute. Create a key at [getchord.xyz/developer](https://getchord.xyz/developer), or in Ask at [getchord.xyz/ask](https://getchord.xyz/ask) (sign in, Settings, API Key). Both are the same kind of key and work for data and Ask. ## What it covers [Section titled “What it covers”](#what-it-covers) | Ask your agent | What the skill does | | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | “Price of NVDA’s stock token and its gap to the real stock” | reads the Robinhood Chain stock screener: last on-chain price, reference price and its source, gap, off-hours share | | “Quote 50 USDC to AERO on Base” | resolves both tokens on the chain, converts the amount exactly, quotes every venue, shows fee, minimum received, impact and route | | “Which tokens on Arc traded the most in the last 24h?” | reads the chain board, flags wash and impostor rows and look-alike tickers | | “What’s moving on pump.fun? Who bought this Solana token?” | reads Chord’s Solana tape (read-only): board, token stats, traders, wallet PnL, with base58 mints kept exactly as given and the tape’s gaps (no prop AMMs or order books) stated | | “Who is buying ARGUS, where is support?” | asks Chord Ask (needs a key) and relays the answer with its sources | | “Swap it” | shows a full confirmation summary, waits for an explicit yes in a new message, then builds the unsigned transaction for the user’s own wallet | Chains: Ethereum (1), Arbitrum One (42161), Base (8453), BNB Chain (56), Avalanche (43114), Monad (143), Robinhood Chain (4663), Arc (5042), plus Solana: data, and swaps through `/v1/sol/trade/*` (the user’s wallet signs). ## The safety model [Section titled “The safety model”](#the-safety-model) * **Read and prepare, never sign.** The skill never signs, broadcasts or asks for a private key. The swap transaction is unsigned and goes to the user’s own wallet. * **Two-step confirmation.** The quote and summary come in one message; the transaction is built only after the user says yes in the next one. Any change to amount, token, chain, slippage or wallet voids the confirmation. The bundled client refuses to build without an explicit `--user-confirmed` flag and refuses quotes older than 60 seconds. * **Numbers only from the API**, with the chain, the source and the time named in every answer. * **Token safety.** Canonical addresses from the curated list (and CoinGecko on Avalanche, Base, BNB Chain, Arbitrum and Ethereum), bridged versus native tokens (USDC vs USDC.e or USDbC), look-alike tickers, airdrop and approval scams, address poisoning, stock token versus share. * **Analysis is not advice**: no buy calls, no promised returns, no stop-loss or take-profit recommendations. ## Files [Section titled “Files”](#files) | File | Contents | | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | [`SKILL.md`](/docs/skills/chord/SKILL.md) | when to use it, chain table, intent routing, confirmation flow, answer and safety rules, errors | | [`references/data.md`](/docs/skills/chord/references/data.md) | market-data endpoints by chain | | [`references/quote-and-swap.md`](/docs/skills/chord/references/quote-and-swap.md) | quotes, the unsigned transaction, approvals, simulation | | [`references/stocks.md`](/docs/skills/chord/references/stocks.md) | Robinhood Chain stock tokens | | [`references/solana.md`](/docs/skills/chord/references/solana.md) | Solana: data and swaps | | [`references/ask.md`](/docs/skills/chord/references/ask.md) | Chord Ask over the API | | [`references/safety.md`](/docs/skills/chord/references/safety.md) | token and address safety | | [`references/examples.md`](/docs/skills/chord/references/examples.md) | real responses from the live API | | [`scripts/chord.py`](/docs/skills/chord/scripts/chord.py) | a dependency-free Python client (`token`, `price`, `board` — these three also on Solana — `stock`, `quote`, `swap-tx`, `simulate`, `ask`) | | [`scripts/install.sh`](/docs/skills/chord/scripts/install.sh) | the installer | ## Other ways in [Section titled “Other ways in”](#other-ways-in) The skill sits on the same public API as the [MCP server](/docs/agents/mcp/), the [function-calling manifest](/docs/agents/function-calling/) and the [Docs MCP](/docs/agents/docs-mcp/). If your agent already has the `chord_*` tools, the skill’s rules apply to them too: `chord_swap_tx` is the signing boundary. # Add Chord to your app > The conventions that hold on every endpoint — chains, addresses, amounts, timestamps, coverage flags, caching and errors — so you read them once. Everything Chord shows is served by this API, and the app follows the same rules you will. Read this page once; nothing below is repeated per endpoint. ## Chains [Section titled “Chains”](#chains) Chord routes on eight EVM chains and indexes them, plus Solana (data and swaps). Pass the chain id where an endpoint takes one; the `/v1/arc/*`, `/v1/rh/*` and `/v1/chains/{chain}/*` families are chain-bound. | Chain | id | Gas | Stable anchor | Data family | Notes | | --------------- | ------- | -------------------------- | ----------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------- | | Arc | `5042` | USDC (native, 18 decimals) | USDC predeploy `0x3600…0000` (6 decimals) | `/v1/arc/*` | Chord’s home chain. Trading, markets, portfolio, points and Ask read Arc. | | Robinhood Chain | `4663` | ETH | USDG (6 decimals) | `/v1/rh/*` | Tokenized stocks and ETFs; the stocks page. | | Monad | `143` | MON | USDC (6 decimals) | `/v1/tokens/*`, `/v1/markets/monad/hourly` | The default when `chain` is omitted. | | Avalanche | `43114` | AVAX | USDC, USDt (6 decimals) | `/v1/chains/avalanche/*` | | | Base | `8453` | ETH | USDC, USDT (6 decimals) | `/v1/chains/base/*` | | | BNB Chain | `56` | BNB | USDT, USDC (**18 decimals**) | `/v1/chains/bnb/*` | Swaps under $100 are not indexed. | | Arbitrum | `42161` | ETH | USDC, USDT0 (6 decimals) | `/v1/chains/arbitrum/*` | | | Ethereum | `1` | ETH | USDC, USDT (6 decimals), DAI (18) | `/v1/chains/ethereum/*` | USDT: approve 0 first when an old allowance is left | | Solana | none | SOL | USDC | `/v1/chains/solana/*`, `/v1/sol/trade/*` | Swaps through Chord’s own router and Jupiter, best of both. | `chain` is required in practice on `/quote`, `/swap`, `/tokens`, `/smart-money/top`, `/portfolio/*` and every `/lp/*` call: omitting it selects Monad. `GET /v1/chains` lists which route serves each capability on each chain. Details per chain, with contracts and venues, are under [Networks](/docs/networks/). ## Addresses and amounts [Section titled “Addresses and amounts”](#addresses-and-amounts) * Addresses are hex, case-insensitive. The zero address `0x0000…0000` is the chain’s native unit wherever a token is accepted. On Arc it is an alias for the USDC predeploy: there is nothing to wrap, so a “native” leg is an ERC-20 leg. * Amounts are **strings in the token’s smallest unit**, never floats. USDC and USDG have 6 decimals, most tokens 18, cirBTC 8. Read `decimals` from `/v1/tokens?chain=` or from the token row; never assume. * USD figures in read endpoints are numbers, already scaled. ## Timestamps [Section titled “Timestamps”](#timestamps) Unix seconds, UTC. Hourly buckets are named `hour`, daily ones `day`, and both are the bucket’s start. The one exception is `updatedAt`, which is milliseconds and says when the server built the answer. ## Coverage, not the clock [Section titled “Coverage, not the clock”](#coverage-not-the-clock) Read endpoints say how fresh and how deep they are. The rollup families carry a `coverage` object (`recentAt`, `stale`, `floorHour`, `genesisHour`, `backfillComplete`); the holder ledger carries `tracked` and `complete`; the pools and positions families expose their cursors on `/v1/lp/status`. A quiet number with `stale: true` is a lane that stopped, not a market that stopped. See [Data freshness](/docs/concepts/data-freshness/). ## Honesty flags [Section titled “Honesty flags”](#honesty-flags) Chord flags rather than hides. Token rows carry `flags: ["wash"]` when a day’s volume came from one or two wallets and `["impostor"]` when an unlisted token wears a listed symbol; the boards sort those below clean rows. Pools carry `suspect` (wash or launch-farm printing) and `token0.impostor` / `token1.impostor`; the pool list hides suspect pools unless you ask with `flagged=1`. Trader counts are attributed wallets only: routers, executors and bots are not wallets. Build the same distinctions into your UI, or your users will see a $10M pool with three traders. ## Caching [Section titled “Caching”](#caching) Rolled-up reads are cheap and memoised server-side (30–60 s on the liquidity family, per-window on the boards). Poll the boards at 10–30 s, the token page at 5–10 s, and use the [streams](/docs/concepts/streaming/) for prices and candles instead of polling. Quotes are live venue reads: do not cache them beyond about 30 seconds. Responses that are safe to cache say so with `Cache-Control: public, max-age=…`; the rest send none. ## Errors [Section titled “Errors”](#errors) Every non-2xx body is `{ "error": "CODE", "message": "for humans" }`. Codes are stable strings; branch on them, not on the message. A `503` is a lane that has not run or is not enabled on the deployment — retry later, never render it as “no data”. The table is in [Errors and retries](/docs/concepts/errors/). ## Rate limit headers [Section titled “Rate limit headers”](#rate-limit-headers) Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. Back off on a `429`. Reads without a key share a per-IP bucket; a key gives you your own. See [Rate limits](/docs/concepts/rate-limits/). ## CORS [Section titled “CORS”](#cors) Open to any origin on `/v1`, no credentials. A browser can call the API directly, including with `X-API-Key` — but a key in a public bundle is a key anyone can use, so proxy it from your server if the limit matters to you. ## Logos [Section titled “Logos”](#logos) Every Arc token row’s `logoURI` points at Chord’s logo proxy, `/v1/logo/5042/{address}`: a 128 px WebP cached on disk, a placeholder when there is none, never a 404. Use it as-is in an ``. `logoUriRaw` is the upstream URL if you want the original. # Clients and codegen > Generate a typed client from the OpenAPI document, or call the API with fetch. There is no SDK to install. The whole API is one OpenAPI 3.1 document, kept in step with the routes: ```plaintext https://getchord.xyz/docs/openapi.json ``` It has every endpoint in this reference, with parameter constraints, response schemas and the same real examples. Feed it to a generator or to a model. ## TypeScript with openapi-typescript [Section titled “TypeScript with openapi-typescript”](#typescript-with-openapi-typescript) ```bash npx openapi-typescript https://getchord.xyz/docs/openapi.json -o chord.d.ts ``` ```ts import type { paths } from "./chord"; import createClient from "openapi-fetch"; const chord = createClient({ baseUrl: "https://api.getchord.xyz/v1", headers: { "X-API-Key": process.env.CHORD_API_KEY ?? "" } }); const { data } = await chord.GET("/arc/tokens", { params: { query: { limit: 20, sort: "volume" } } }); for (const t of data?.tokens ?? []) console.log(t.symbol, t.priceUsd, t.volume24h, t.flags ?? []); ``` ## Plain fetch [Section titled “Plain fetch”](#plain-fetch) Nothing in the API needs more than `fetch`. Amounts are strings, so use `BigInt` for arithmetic. ```ts const A = "https://api.getchord.xyz/v1"; const quote = await fetch(`${A}/quote?chain=5042&inputMint=0x3600000000000000000000000000000000000000&outputMint=0x171a4217b86a807a64eb94757db6849fb4bdbaa0&amount=5000000&slippageBps=100`).then((r) => r.json()); if (quote.routePlan.length === 0) throw new Error(quote.noRouteReason); const { transaction } = await fetch(`${A}/swap`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ quoteResponse: quote, userPublicKey: wallet, chain: 5042 }) }).then((r) => r.json()); ``` ## Python [Section titled “Python”](#python) ```python import requests A = "https://api.getchord.xyz/v1" r = requests.get(f"{A}/arc/trending", params={"limit": 10}, headers={"X-API-Key": KEY}, timeout=20) r.raise_for_status() for t in r.json()["tokens"]: print(t["symbol"], t["score"], t["change1hPct"]) ``` ## Other generators [Section titled “Other generators”](#other-generators) Any OpenAPI 3.1 generator works: `openapi-generator-cli` for Go, Java, Rust or Swift, `orval` or `oazapfts` for TypeScript, `datamodel-codegen` for Pydantic models. The document uses `oneOf`, `allOf` and nullable type arrays (`["number", "null"]`), so pick a generator that understands 3.1. ## Agents [Section titled “Agents”](#agents) If the caller is a model, hand it the document or [llms.txt](/docs/agents/llms-txt/), or use the [MCP server](/docs/agents/mcp/) and the [function-calling manifest](/docs/agents/function-calling/), which wrap the API as tools. # Supported launchpads > The launcher contracts Chord names on Arc, what they create, and how to follow their launches through the API. Most tokens on Arc are created through a launcher contract that deploys the token and initialises its first pool — a Uniswap V4 pool with a hook that runs a bonding curve, or a V3 / V2 pool with seeded liquidity. Chord’s launch radar watches every pool creation on the chain, attributes it to the contract that made it, and names the ones it knows. `GET /v1/arc/launchers` returns the live activity of every launcher, named or not, with the addresses. | Launcher | Site | Pools it creates | | ------------------------------- | ----------------------- | ------------------------------ | | Uniswap Liquidity Launcher | github.com/Uniswap/sdks | V4 | | Uniswap V4 PoolManager (direct) | app.uniswap.org | V4 | | Pools.trade | pools.trade | V4 (fee 2500, tick spacing 25) | | aka.fun | aka.fun | V4 | | Argus | argus.world | V4 | | Minara.fun | minara.fun | V4 | | Rapid Launch | rapidlaunch.io | V4 | | Sharc.fun | sharc.fun | V4 | | Bozo | bozo.fun | V4 | | o1 Launchpad | launch.o1.exchange | V4 | | Enso | enso.trade | V4 | | Triplfun | tripl.fun | V4 | | BullCheese | bullcheese.fun | V4 | | par.family | par.family | V4 | | lift.fun | lift.fun | V3, V4 | | Long.supply | long.supply | V3, V4 | | Synthra | synthra.org | V3 | | TOLLY | tollylabs.com | V3 | | circlearc.fun | circlearc.fun | V3 | | ArcPad | arcpad.meme | V3 | | Curving | curving.fun | V3 | | DEPLOY | deploydollars.com | V3 | | ARClove | arclove.fun | V3 | | ARK | ark-ai.xyz | V3 | | PEGD | pegd.fun | V3 | | BigShort | bigshort.xyz | V2 | | Niorfun | niorfun.com | V2 | | Tollan | tollan.io | V2 | ## Routing hooked pools [Section titled “Routing hooked pools”](#routing-hooked-pools) A V4 launchpad pool carries a hook, and a hook can do anything to a swap — including quoting one amount and delivering another. Chord routes a hook only after a real swap has been verified in both directions on it; an unverified hook is not routed, and its tokens show `routable: false` until it is. The engine has verified the launchpad hooks in the table above plus two per-token hook templates; a token on a hook it has not seen quotes `NO_POOLS`. ## Following launches [Section titled “Following launches”](#following-launches) * Feed: `GET /v1/arc/graduated?hours=48` — screened launches, newest first, with `launcher` and `launcherName`. * Activity per launcher: `GET /v1/arc/launchers?hours=24` — pool shapes, pools per hour, creators, 24-hour swaps and volume over its pools. * Forensics per token: holders, pools with launch facts, windowed stats — the [Launch lifecycle](/docs/recipes/launchpad-lifecycle/) recipe. * Token art: launchers publish metadata off-chain in different places; Chord resolves logos from the token contract, the launcher’s events, and public sources, and serves them at `/v1/logo/5042/{address}` with a placeholder until found. A launcher you use that is missing here: the address still appears in `/v1/arc/launchers` and on every launch row; naming it is a one-line registry change on Chord’s side. # Supported networks > The chains Chord indexes and routes on, with ids, gas, anchors and the data families that serve them. | Network | Chain id | Gas | Stable anchor | Trading | Data | Streams | | -------------------------------------------------- | --------------------------- | ------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------- | | [Arc](/docs/networks/arc/) | `5042` | USDC (native) | USDC predeploy `0x3600…0000`, EURC | Uniswap V3 / V4 / V2, launchpad hooks, the forks | `/v1/arc/*`, `/v1/lp/*`, portfolio, top wallets, holders, points, Ask | WebSocket `prices`, `candles`, `trades` | | [Robinhood Chain](/docs/networks/robinhood-chain/) | `4663` | ETH | USDG | Uniswap V3 / V4, GIGA, SwapHood, PancakeSwap, up, Metric OMM | `/v1/rh/*`, `/v1/lp/*`, portfolio, top wallets, holders | SSE `rh-ticker`, WebSocket `prices`, `candles`, `trades` | | [Monad](/docs/networks/monad/) | `143` | MON | USDC | Uniswap V3 / V4, PancakeSwap, Capricorn, Atlantis, LFJ, Kuru, Hanji, Metric, WOOFi, Balancer, Curve, Mento, nad.fun | `/v1/tokens/*`, `/v1/markets/monad/hourly`, `/v1/lp/*`, portfolio, top wallets | WebSocket `prices` | | [Avalanche](/docs/networks/avalanche/) | `43114` | AVAX | USDC, USDt | Uniswap V3 / V4, Pharaoh, LFJ, Pangolin, Blackhole, Metric, WOOFi | `/v1/chains/avalanche/*`, candles, search | none | | [Base](/docs/networks/base/) | `8453` | ETH | USDC, USDT | Uniswap V2 / V3 / V4, PancakeSwap, Aerodrome, Hydrex, QuickSwap, Metric | `/v1/chains/base/*`, candles, search | none | | [BNB Chain](/docs/networks/bnb-chain/) | `56` | BNB | USDT, USDC (18 decimals) | PancakeSwap V2 / V3 / Infinity, Uniswap V3 / V4, Topaz, THENA | `/v1/chains/bnb/*` (swaps ≥ $100), candles, search | none | | [Arbitrum](/docs/networks/arbitrum/) | `42161` | ETH | USDC, USDT0 | Uniswap V2 / V3 / V4, PancakeSwap, SushiSwap, Camelot, Metric, WOOFi | `/v1/chains/arbitrum/*`, candles, search | none | | [Ethereum](/docs/networks/ethereum/) | `1` | ETH | USDC, USDT, DAI | Uniswap V2 / V3 / V4, PancakeSwap, SushiSwap | `/v1/chains/ethereum/*`, candles, search | none | | [Solana](/docs/networks/solana/) | none (`solana` in the path) | SOL | USDC, USDT, wSOL | swaps (`/v1/sol/trade/*`): Chord’s own router on Raydium, Orca, Meteora, pump.fun and PumpSwap, against Jupiter, best of both | `/v1/chains/solana/*` (11 venues) | none | Every EVM chain above shares the router, fee and registry contracts at the same addresses, and one API: `/v1/quote` and `/v1/swap` take any of the eight chain ids. Pass `chain=` where an endpoint takes it; the `/arc/*`, `/rh/*` and `/chains/{chain}/*` families are bound to their chain. `GET /v1/chains` lists the chains with the route that serves each capability, and is the place to check before calling a route on a chain. The data on Arc, Robinhood Chain and Monad is the deepest (top wallets, wallet PnL, liquidity positions); on Avalanche, Base, BNB Chain, Arbitrum and Ethereum it is the tape, token and wallet routes of `/v1/chains/{chain}/*`. Robinhood Chain data (tokenized stocks and ETFs, 24/7) is on the stocks page of the Chord app. Solana has its own API: swaps under `/v1/sol/trade/*`, where every quote builds Chord’s own route and Jupiter’s for your wallet and keeps whichever leaves it with more, and data from Chord’s own tape of the swap events of 11 Solana venues (pump.fun, PumpSwap, Meteora, Raydium, Orca), with base58, case-sensitive addresses. It does not read prop AMMs or order books, so major pairs are understated. See [Solana](/docs/networks/solana/). # Arbitrum > Arbitrum One (42161). Ids, anchors, contracts, venues and the /v1/chains/arbitrum/* data family. | | | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chain id | `42161` (key `arbitrum` in `/v1/chains/{chain}/*`) | | Gas | ETH (zero address in the API; WETH `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`) | | Blocks | \~250 ms | | Stable anchors | USDC `0xaf88d065e77c8cC2239327C5EDb3A432268e5831` and USDT0 `0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9` (6 decimals); the bridged USDC.e counts as a dollar too | | Explorer | [arbiscan.io](https://arbiscan.io) | | Chord index since | 2026-10-06 20:00 UTC | ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on the dollar stables and WETH. ## Venues [Section titled “Venues”](#venues) Routing covers Uniswap V2, V3 and V4, PancakeSwap V3, SushiSwap V2 and V3, Camelot V3, Metric and WOOFi. The data index covers every venue on the chain; `GET /v1/chains/arbitrum/venues` is the live list with share. Common ids: `uniswap_v3` · `uniswap_v4` · `pancake_v3` · `camelot_v3` · `sushi_v3` · `sushi_v2` · `camelot_v2` · `uniswap_v2` · `ramses_v2` · `pancake_v2`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | -------------------------------------------------- | ------------------------------------------------------------------------------------------ | | Freshness and coverage | `GET /v1/chains/arbitrum/status` | | Chain totals, venue share, hourly and daily | `GET /v1/chains/arbitrum/overview` | | Every token traded in 24h | `GET /v1/chains/arbitrum/tokens` | | One token’s hourly tape and venue split, its swaps | `GET /v1/chains/arbitrum/token/{address}`, `…/token/{address}/trades` | | Search | `GET /v1/tokens/search?q=&chain=42161` | | Candles | `GET /v1/candles?chain=42161&token=` | | A wallet’s swaps and PnL | `GET /v1/chains/arbitrum/wallet/{address}`, `…/wallet/{address}/trades` | | Quote and swap | `GET /v1/quote?chain=42161…`, `POST /v1/swap { chain: 42161 }`, native ETH goes in `value` | There are no top-wallet, holder or liquidity boards for Arbitrum yet. # Arc > Chain 5042 — Circle's USDC-native L1. Ids, RPC, the two faces of USDC, contracts, venues and launchers as Chord indexes them. | | | | ----------------- | -------------------------------------------------------------------------------------------------------------------------- | | Chain id | `5042` | | Gas | USDC — native (18 decimals) with an ERC-20 face at the predeploy `0x3600000000000000000000000000000000000000` (6 decimals) | | Finality | sub-second | | Explorer | [explorer.arc.io](https://explorer.arc.io) | | Public RPC | `https://rpc.mainnet.arc.io` (rate-limited; Chord lists alternatives at [getchord.xyz/rpc](https://getchord.xyz/rpc)) | | Chord index since | genesis (rollups reach `genesisHour`; pool discovery reached genesis) | ## USDC, twice [Section titled “USDC, twice”](#usdc-twice) Native USDC pays gas and appears as `currency0 = address(0)` in Uniswap V4 pools with 18 decimals; the predeploy is the same balance seen as an ERC-20 with 6 decimals (`balanceOf == native / 1e12`). There is no wrapped-native contract. The API takes the predeploy, treats the zero address as its alias, and always builds transactions with `value: "0"`. Details in [Chains, addresses and amounts](/docs/concepts/chains-and-amounts/). Other anchors: EURC `0xbef5f6d51cb62b58e6a8f77868681825c6fe21c1` (6 decimals, tagged `fx`), VIRTUAL `0x8c4252c87081c88c6ad57d6dd97e1cafebf842b7` (Virtuals launcher quote asset, priced from its USDC prints). Beware tokens named USDC that are not the predeploy — the API flags them `impostor`. ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) | Contract | Address | | ----------------------------------------------------------------------------- | -------------------------------------------- | | Router (UUPS proxy) — `transaction.to` in every `/swap` answer | `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a` | | Fee collector (UUPS proxy) — `feeBpsFor(token)` is the on-chain fee authority | `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834` | | Adapter registry (UUPS proxy) — the approved venue adapters | `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f` | Adapters (one per venue family: Uniswap V3 and forks, Uniswap V4 with native currency, V2 with tax detection) are returned inside every quote’s `routePlan`; never hardcode them. The fee schedule: USDC and EURC 0 bps, every other token 5 bps. ## Protocol contracts Chord reads [Section titled “Protocol contracts Chord reads”](#protocol-contracts-chord-reads) | | Address | | ------------------------------------- | -------------------------------------------- | | Uniswap V3 factory | `0xf0db7b58379503491d857db50ac9ece64c653918` | | Uniswap V3 QuoterV2 | `0x7dfd4f31be6814d2906bde155c3e1b146eac1468` | | Uniswap V3 NonfungiblePositionManager | `0x39654a85a4c05127f5fd6ed22caec077a0fb1377` | | Uniswap V2 factory | `0x89e5db8b5aa49aa85ac63f691524311aeb649eba` | | Uniswap V4 PoolManager | `0x8366a39cc670b4001a1121b8f6a443a643e40951` | | Uniswap V4 PositionManager | `0x6049c9a0e26405c0985f9e3685c87d0ae917f82b` | | Uniswap V4 StateView | `0xf3334192d15450cdd385c8b70e03f9a6bd9e673b` | | Uniswap V4 Quoter | `0x8dc178efb8111bb0973dd9d722ebeff267c98f94` | | SwapRouter02 | `0x53bf6b0684ec7ef91e1387da3d1a1769bc5a6f77` | | Permit2 | `0x000000000022d473030f116ddee9f6b43ac78ba3` | | Multicall3 | `0xca11bde05977b3631167028862be2a173976ca11` | ## Venues [Section titled “Venues”](#venues) Every pool from every factory and the V4 PoolManager is indexed for data; routing covers the Uniswap trio plus verified launchpad hooks and the named forks. Venue ids as they appear in `dex` fields: | id | Venue | | --------------------------------- | -------------------------------------------------------------------------- | | `uniswap_v4` | Uniswap V4 (most launches live here; hooked pools are per-launcher curves) | | `uniswap_v3` · `uniswap_v2` | Uniswap V3 / V2 | | `pools_trade` | Pools.trade — V4 pools (fee 2500, tick spacing 25) through its launcher | | `synthra_v3` | Synthra | | `sushi_v2` · `sushi_v3` | SushiSwap V2 / V3 | | `dyorswap` | DYORSwap | | `slipstream_fork` | an Aerodrome Slipstream fork (“Aero”) | | `v3fork_<8hex>` · `v2fork_<8hex>` | unnamed forks, keyed by the first 8 hex of the factory | `GET /v1/arc/venues` is the live list with volume and share. Names for display are in [Venue ids](/docs/resources/venue-ids/). ## Launchers [Section titled “Launchers”](#launchers) Arc’s tokens are mostly born through launcher contracts. Chord names 27 of them and indexes the rest by address; the [Launchpads](/docs/launchpads/) page lists them and `GET /v1/arc/launchers` reports their activity. ## Data lanes [Section titled “Data lanes”](#data-lanes) | Lane | Freshness | Endpoint to check | | ------------------------------------------------ | -------------------------------------------------------------------- | -------------------------------------------------- | | Trade tape (every swap, priced) | seconds behind the head (WebSocket head trigger + a forward crawler) | `/v1/arc/status` → `recentAt`, `staleSec` | | Hourly / daily rollups | rolled every few minutes | `/v1/arc/status` → `coverage` | | Pool index (V2 / V3 / V4 discovery) | minutes | `/v1/arc/status` → `index` | | Holder ledger (Transfer logs for tracked tokens) | forward lane near the head; backfill per token | `/v1/arc/status` → `holders`; per token `complete` | | Liquidity events, pools, positions | minutes | `/v1/lp/status` | | Live prices | per print, over WebSocket | subscribe `prices` | # Avalanche > Avalanche C-Chain (43114). Ids, anchors, contracts, venues and the /v1/chains/avalanche/* data family. | | | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Chain id | `43114` (key `avalanche` in `/v1/chains/{chain}/*`) | | Gas | AVAX (zero address in the API; WAVAX `0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7`) | | Blocks | \~1.3 s | | Stable anchors | USDC `0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E` and USDt `0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7` (6 decimals); the bridged USDC.e and USDT.e count as dollars too | | Explorer | [snowtrace.io](https://snowtrace.io) | | Chord index since | 2026-09-23 16:00 UTC | ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on the dollar stables and WAVAX. ## Venues [Section titled “Venues”](#venues) Routing covers Uniswap V3 and V4, Pharaoh (V3 and DLMM), LFJ (V1 and Liquidity Book), Pangolin V2 and V3, Blackhole (V2 and CL), Metric and WOOFi. The data index covers every venue on the chain; `GET /v1/chains/avalanche/venues` is the live list with share. Common ids: `pharaoh_v3` · `pharaoh_dlmm` · `uniswap_v3` · `blackhole_v3` · `lfj_lb_v22` · `lfj_lb_v21` · `uniswap_v4` · `lfj_v1` · `pangolin_v2` · `pangolin_v3` · `blackhole_v2`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | -------------------------------------------------- | ------------------------------------------------------------------------------------------- | | Freshness and coverage | `GET /v1/chains/avalanche/status` | | Chain totals, venue share, hourly and daily | `GET /v1/chains/avalanche/overview` | | Every token traded in 24h | `GET /v1/chains/avalanche/tokens` | | One token’s hourly tape and venue split, its swaps | `GET /v1/chains/avalanche/token/{address}`, `…/token/{address}/trades` | | Search | `GET /v1/tokens/search?q=&chain=43114` | | Candles | `GET /v1/candles?chain=43114&token=` | | A wallet’s swaps and PnL | `GET /v1/chains/avalanche/wallet/{address}`, `…/wallet/{address}/trades` | | Quote and swap | `GET /v1/quote?chain=43114…`, `POST /v1/swap { chain: 43114 }`, native AVAX goes in `value` | The database keeps the raw tape for about 7 days on this chain; a wallet’s older days come from Chord’s data lake, and the answer’s `window` and `history` say which. There are no top-wallet, holder or liquidity boards for Avalanche yet. # Base > Base (8453). Ids, anchors, contracts, venues and the /v1/chains/base/* data family. | | | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chain id | `8453` (key `base` in `/v1/chains/{chain}/*`) | | Gas | ETH (zero address in the API; WETH `0x4200000000000000000000000000000000000006`) | | Blocks | \~2 s | | Stable anchors | USDC `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` and USDT `0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2` (6 decimals); the bridged USDbC counts as a dollar too | | Explorer | [basescan.org](https://basescan.org) | | Chord index since | 2026-09-23 15:00 UTC | ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on the dollar stables and WETH. ## Venues [Section titled “Venues”](#venues) Routing covers Uniswap V2, V3 and V4, PancakeSwap V3, Aerodrome (Slipstream and V2), Hydrex, QuickSwap V4 and Metric. The data index covers every venue on the chain; `GET /v1/chains/base/venues` is the live list with share. Common ids: `aerodrome_slipstream_3` · `uniswap_v3` · `aerodrome_slipstream` · `pancake_v3` · `uniswap_v4` · `aerodrome_v2` · `aerodrome_slipstream_2` · `uniswap_v2` · `hydrex_integral` · `quickswap_v4` · `sushi_v3`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | -------------------------------------------------- | ---------------------------------------------------------------------------------------- | | Freshness and coverage | `GET /v1/chains/base/status` | | Chain totals, venue share, hourly and daily | `GET /v1/chains/base/overview` | | Every token traded in 24h | `GET /v1/chains/base/tokens` | | One token’s hourly tape and venue split, its swaps | `GET /v1/chains/base/token/{address}`, `…/token/{address}/trades` | | Search | `GET /v1/tokens/search?q=&chain=8453` | | Candles | `GET /v1/candles?chain=8453&token=` | | A wallet’s swaps and PnL | `GET /v1/chains/base/wallet/{address}`, `…/wallet/{address}/trades` | | Quote and swap | `GET /v1/quote?chain=8453…`, `POST /v1/swap { chain: 8453 }`, native ETH goes in `value` | The database keeps the raw tape for about 3 days on this chain; a wallet’s older days come from Chord’s data lake, and the answer’s `window` and `history` say which. There are no top-wallet, holder or liquidity boards for Base yet. # BNB Chain > BNB Chain (56). Ids, anchors with 18 decimals, contracts, venues, the $100 ingest floor and the /v1/chains/bnb/* data family. | | | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | Chain id | `56` (key `bnb` in `/v1/chains/{chain}/*`) | | Gas | BNB (zero address in the API; WBNB `0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c`) | | Blocks | \~450 ms | | Stable anchors | USDT `0x55d398326f99059fF775485246999027B3197955`, USDC `0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d`, USD1, FDUSD, BUSD: all **18 decimals** | | Explorer | [bscscan.com](https://bscscan.com) | | Chord index since | 2026-09-30 17:00 UTC | The dollar stables on BNB Chain have 18 decimals, not 6: 10 USDT is `"10000000000000000000"`. Read decimals from the token row, as everywhere. ## Swaps under $100 are not indexed [Section titled “Swaps under $100 are not indexed”](#swaps-under-100-are-not-indexed) The tape records swaps of $100 or more only (since it started). Every `/v1/chains/bnb/*` and `/v1/candles?chain=56` answer carries `ingestFloor` (`minTradeUsd: 100`). Token volumes, trade counts and wallet histories on this chain leave out the small swaps; say so when you show them. Quotes and swaps are not affected. ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on the dollar stables and WBNB. ## Venues [Section titled “Venues”](#venues) Routing covers PancakeSwap (V2, V3 and Infinity CL), Uniswap V3 and V4, Topaz and THENA V3. The data index covers every venue on the chain; `GET /v1/chains/bnb/venues` is the live list with share. Common ids: `pancake_v3` · `pancake_infinity_cl` · `pancake_v2` · `uniswap_v4` · `uniswap_v3` · `topaz` · `flap` · `thena_v3` · `fstswap`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | -------------------------------------------------- | ------------------------------------------------------------------------------------ | | Freshness, coverage and the ingest floor | `GET /v1/chains/bnb/status` | | Chain totals, venue share, hourly and daily | `GET /v1/chains/bnb/overview` | | Every token traded in 24h | `GET /v1/chains/bnb/tokens` | | One token’s hourly tape and venue split, its swaps | `GET /v1/chains/bnb/token/{address}`, `…/token/{address}/trades` | | Search | `GET /v1/tokens/search?q=&chain=56` | | Candles | `GET /v1/candles?chain=56&token=` | | A wallet’s swaps and PnL | `GET /v1/chains/bnb/wallet/{address}`, `…/wallet/{address}/trades` | | Quote and swap | `GET /v1/quote?chain=56…`, `POST /v1/swap { chain: 56 }`, native BNB goes in `value` | The database keeps the raw tape for about 3 days on this chain; a wallet’s older days come from Chord’s data lake, and the answer’s `window` and `history` say which. There are no top-wallet, holder or liquidity boards for BNB Chain yet. # Ethereum > Ethereum mainnet (1). Ids, anchors, contracts, venues and the /v1/chains/ethereum/* data family. | | | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Chain id | `1` (key `ethereum` in `/v1/chains/{chain}/*`) | | Gas | ETH (zero address in the API; WETH `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`) | | Blocks | \~12 s | | Stable anchors | USDC `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` and USDT `0xdAC17F958D2ee523a2206206994597C13D831ec7` (6 decimals); DAI `0x6B175474E89094C44Da98b954EedeAC495271d0F` (18 decimals) | | Explorer | [etherscan.io](https://etherscan.io) | | Chord index since | 2026-10-08 17:00 UTC | ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on USDC, USDT, DAI, WETH and WBTC. ## USDT approvals [Section titled “USDT approvals”](#usdt-approvals) USDT on Ethereum refuses a new `approve` while the spender still holds a non-zero allowance. Approve exactly the input amount (the swap uses all of it, so the allowance returns to 0). When an older allowance is left over, send `approve(spender, 0)` first: `/v1/meta/quote` and `/v1/meta/swap` say so with `approval.resetFirst: true`. ## Venues [Section titled “Venues”](#venues) Routing covers Uniswap V2, V3 and V4, PancakeSwap V3, SushiSwap V2 and V3. Curve, Fluid, Balancer and Ekubo are not routed yet; the data index reads the venues that emit Uniswap-shaped swap events (about 93 % of the chain’s swaps). `GET /v1/chains/ethereum/venues` is the live list with share. Common ids: `uniswap_v3` · `uniswap_v4` · `uniswap_v2` · `pancake_v3` · `sushi_v3` · `sushi_v2` · `ring_v2` · `supernova_cl` · `shibaswap` · `fraxswap`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | -------------------------------------------------- | ---------------------------------------------------------------------------------- | | Freshness and coverage | `GET /v1/chains/ethereum/status` | | Chain totals, venue share, hourly and daily | `GET /v1/chains/ethereum/overview` | | Every token traded in 24h | `GET /v1/chains/ethereum/tokens` | | One token’s hourly tape and venue split, its swaps | `GET /v1/chains/ethereum/token/{address}`, `…/token/{address}/trades` | | Search | `GET /v1/tokens/search?q=&chain=1` | | Candles | `GET /v1/candles?chain=1&token=` | | A wallet’s swaps and PnL | `GET /v1/chains/ethereum/wallet/{address}`, `…/wallet/{address}/trades` | | Quote and swap | `GET /v1/quote?chain=1…`, `POST /v1/swap { chain: 1 }`, native ETH goes in `value` | ```bash curl -s "https://api.getchord.xyz/v1/quote?chain=1&inputMint=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&outputMint=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&amount=1000000000000000000" ``` 1 WETH to USDC on 2026-10-15: `outputAmount` 2452700960 (2,452.70 USDC), split 96 % Uniswap V3 and 4 % PancakeSwap V3. There are no top-wallet, holder or liquidity boards for Ethereum yet. # Monad > Chain 143, where Chord's routing engine started. Ids, anchors, contracts, the venues routing covers and where the chain's data is read. | | | | ------------- | ---------------------------------------------------------------------------------------------------- | | Chain id | `143`, also the default of `/quote`, `/swap` and `/candles` when `chain` is omitted. Pass it anyway. | | Gas | MON (zero address in the API; WMON `0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A`) | | Blocks | \~300 ms | | Stable anchor | USDC `0x754704Bc059F8C67012fEd69BC8A327a5aafb603` (6 decimals) | | Explorer | [monadscan.com](https://monadscan.com) | ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as every EVM chain Chord routes on: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. Protocol fee: 5 bps by default, 0 on dollar stables, MON / WMON and the majors. Monad is the only chain where `POST /v1/swap` takes `batch: "7702"`: one signature for approve and swap through an EIP-7702 delegate. ## Venues [Section titled “Venues”](#venues) Routing covers the AMMs (Uniswap V3 and V4, PancakeSwap V3, Capricorn V3, Atlantis, LFJ Liquidity Book), the order books Kuru and Hanji, the oracle-priced pools Metric, LFJ POE and WOOFi, Balancer V3, Curve StableSwap-NG, Mento FX, nad.fun (bonding curve before graduation and its DEX after), and buy-only deposits into the aprMON, shMON and gMON vaults. Composed hops go through WMON, shMON, AUSD and USDT0. The quote’s `routePlan` names the venue of each leg. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | --------------------------------------------- | -------------------------------------------------------------------------------------- | | Hourly swaps and USD, last 24 hours | `GET /v1/markets/monad/hourly` | | Token board by volume or change | `GET /v1/tokens/board?chain=143&sort=volume` | | One token: windows, markets, tape | `GET /v1/tokens/stats/{address}`, `GET /v1/tokens/trades/{address}` | | Search beyond the list | `GET /v1/tokens/search?q=&chain=143` | | Candles | `GET /v1/candles?chain=143&token=` | | Quote and swap | `GET /v1/quote?chain=143…`, `POST /v1/swap { chain: 143 }`, native MON goes in `value` | | Wallet PnL and trades, top wallets, liquidity | `chain=143` on `/v1/portfolio/*`, `/v1/smart-money/top?source=onchain`, `/v1/lp/*` | | Live prices | WebSocket `/v1/ws/live`, channel `prices`, chain `143` | There is no holder ledger for Monad tokens. # Robinhood Chain > Chain 4663 — tokenized stocks and ETFs on-chain, 24/7. Ids, anchors, venues and the /v1/rh/* data family. | | | | ----------------- | -------------------------------------------------------------------------------- | | Chain id | `4663` | | Gas | ETH (zero address in the API; WETH `0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73`) | | Blocks | \~100 ms | | Stable anchor | USDG `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` (6 decimals) | | Explorer | [robin.etherscan.io](https://robin.etherscan.io) | | Public RPC | `https://rpc.mainnet.chain.robinhood.com` | | Chord index since | the chain’s first swap (`genesisHour` on `/v1/rh/status`) | ## Tokenized stocks [Section titled “Tokenized stocks”](#tokenized-stocks) Equities and ETFs are 18-decimal tokens tagged `stock` on the curated list (NVDA `0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC`, AAPL `0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9`, SPCX, …). They trade around the clock; `GET /v1/rh/stocks` reports each one’s 24-hour tape, the issuer’s NAV where published (`navUsd`, `basisPct`) and the share of the last seven days that traded outside the NYSE session (`offHours7d`). Protocol fee on WETH, USDG and every stock is 0 bps. ## Chord contracts [Section titled “Chord contracts”](#chord-contracts) The same proxies as Arc: router `0x1b1fee89a381e595fe6536b99ba91f3e16e9601a`, fee collector `0x6c66229675fd9ceda9a9b2ea2bd983b3d8255834`, adapter registry `0x6cf25d2af1a58d7094b0ac253ae616a8e1f2ea3f`. Adapters come with every quote. ## Venues [Section titled “Venues”](#venues) Routing covers Uniswap V3 and V4, GIGA V3, SwapHood V3, PancakeSwap V3, up v3 and the Metric OMM, plus composed hops through WETH and USDG. The data index covers every venue on the chain, including the ones routing does not use; `GET /v1/rh/venues` is the live list with ids and share. Common ids: `uniswap_v3` · `uniswap_v4` · `uniswap_v2` · `giga_v3` · `swaphood_v3` · `pancake_v3` · `up_v3` · `metric` · `nadfun_dex` · `pons_v2_curve`. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | ------------------------------------------------ | ----------------------------------------------------------------------------------------- | | Chain totals, venue share, hourly and daily | `GET /v1/rh/overview` | | Every token traded in 24h | `GET /v1/rh/tokens?sort=volume` | | One token’s hourly tape and venue split | `GET /v1/rh/token/{address}` | | Every stock with NAV basis and after-hours share | `GET /v1/rh/stocks` | | Price map for the curated list | `GET /v1/tokens/market?chain=4663` | | Curated list, search | `GET /v1/tokens?chain=4663`, `GET /v1/tokens/search?q=&chain=4663` | | Candles, tape, stats | \`GET /v1/tokens/chart | | Quote and swap | `GET /v1/quote?chain=4663…`, `POST /v1/swap { chain: 4663 }` — native ETH goes in `value` | | Top wallets, portfolio, liquidity | `chain=4663` on `/v1/smart-money/top`, `/v1/portfolio/*`, `/v1/lp/*` | | Live prices | SSE `/v1/stream/market` event `rh-ticker` | Freshness: `GET /v1/rh/status`. # Solana > Solana on Chord — swaps through Chord's own router and Jupiter, best of both, open to everyone, and data from Chord's own tape of 11 venues; base58 addresses, units, the /v1/sol/trade/* and /v1/chains/solana/* families. | | | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chain id | none — the path segment is the literal `solana` (`/v1/chains/solana/*`) | | Addresses | base58, **case-sensitive** (mints, wallets, pools); signatures base58 | | Gas | SOL | | Quote anchors | USDC `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` > USDT `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` > wSOL `So11111111111111111111111111111111111111112` (in a SOL/USDC pool, SOL is the token) | | Trading | **open to everyone** since 2026-10-15: SOL ↔ any token through Chord’s own router and Jupiter, whichever leaves the wallet with more (`/v1/sol/trade/*`, [below](#swaps)) | | Chord tape since | live from 2026-10-03 12:01 UTC, plus a backfill of the days before: read `coverageSince` on `GET /v1/chains/solana/overview` | ## Swaps [Section titled “Swaps”](#swaps) A Solana swap quoted by Chord is SOL against one token, bought or sold. For every quote Chord builds, at the same moment, the transaction of each route below **for your wallet**, simulates it on the chain, and reads what your wallet would end up with: tokens for a buy, SOL for a sell, after every fee. You get the route that leaves you with the most. | `route` | What it is | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `direct` | **Chord’s own router.** It builds the swap itself, from the pool accounts, on Raydium AMM v4, CPMM and CLMM, Orca Whirlpool, Meteora DLMM and DAMM v2, and the launch curves Meteora DBC, Raydium LaunchLab, pump.fun and PumpSwap. Pools come from Chord’s tape; a large order can be split over two pools (`hops`). No third party in the path. | | `jupiter` | Jupiter’s swap API (Metis), without Jupiter’s fee. | | `jupiter_meta` | Jupiter’s order: Metis, Jupiter’s RFQ market makers, DFlow and OKX bid for it. Jupiter’s fee is inside the amount; on RFQ and gasless orders Jupiter or the market maker pays the network fee (`gasless: true`). | So a swap through Chord gets Jupiter’s price whenever Jupiter is better (majors, where most of the liquidity sits in prop AMMs and market makers only Jupiter reaches), and Chord’s own route when it is as good (ties go to `direct`, then `jupiter`), when Jupiter has no route yet for a new token, or when Jupiter is down or rate-limited. `compared` in the answer shows what every route offered. A route that would hand back less than half of the input’s market value is refused. **Status.** Open to everyone since 2026-10-15 21:25 UTC, no key needed (an `X-API-Key` raises the rate limit, as everywhere else). `GET /v1/sol/trade/config` says, for the caller, whether the lane is `enabled`, `open` to everyone, and `allowed` for you. Chord takes no fee on Solana today (`feeBps: 0`); Jupiter’s own fee applies on `jupiter_meta` quotes and is already inside the amount. **One swap, step by step.** Amounts are base units as decimal strings: lamports for SOL, the token’s smallest unit otherwise. 1. `GET /v1/sol/trade/quote?mint=&side=buy|sell&amount=&wallet=&slippageBps=100` — `amount` is lamports for a buy, tokens (smallest unit) for a sell. The answer’s `quote.tx` is an unsigned v0 transaction, base64, exactly the one simulated; `outAmount` is what the simulation delivered, `minOut` the least the transaction accepts. 2. Sign `quote.tx` **unchanged** with the wallet. On `jupiter_meta` the wallet can be the second signer, not the fee payer. 3. `POST /v1/sol/trade/send` with `{ "tx": "" }`. Chord relays only a transaction it quoted in the last three minutes, signed by the wallet it quoted; `jupiter_meta` orders go through Jupiter’s execute endpoint. 4. Poll `GET /v1/sol/trade/tx/{signature}`: `pending`, then `confirmed` / `finalized` (with `receivedOut`, read from the chain with the same measure as the quote), `failed` or `expired`. An RFQ quote carries `expireAt` (Unix seconds) and lives a few seconds: ask again when fewer than ten seconds are left. `GET /v1/sol/trade/balances?wallet=&mint=` and `/holdings?wallet=` give the wallet’s SOL and token balances for a swap form. **Not covered.** Token ↔ token (SOL is always one side). Chord’s own route does not go through a second pool (token → USDC → SOL) or reach prop AMMs and RFQ makers: for those tokens and sizes the Jupiter routes win and are what you get. ## What the tape reads [Section titled “What the tape reads”](#what-the-tape-reads) Chord decodes the swap **events** of 11 venues straight from Solana blocks, and checks every swap against the pool vaults’ balance changes in the same transaction: PumpSwap · pump.fun bonding curve · Meteora DBC · Meteora DAMM v2 · Meteora DLMM · Meteora pools (dynamic AMM v1) · Raydium CLMM · Raydium CPMM · Raydium AMM v4 · Raydium LaunchLab · Orca Whirlpool Venue ids in responses: `pumpswap` · `pumpfun` · `meteora_dbc` · `meteora_damm_v2` · `meteora_dlmm` · `meteora_pools` · `raydium_clmm` · `raydium_cpmm` · `raydium_v4` · `raydium_launchlab` · `orca`. ## What it does not read [Section titled “What it does not read”](#what-it-does-not-read) * **Prop AMMs** (SolFi, HumidiFi and the like) and **order books**. Most SOL/USDC and other major-pair flow runs there, so those pairs show far less volume on Chord than on an all-market source. The tape is accurate for pump.fun, Meteora and Raydium style tokens; do not use it for a market-wide SOL volume. * **Transfers.** A wallet’s PnL is average cost over the swaps inside the window. A token that arrived by transfer, or was bought before the window, and is then sold shows up as a sell without a buy: the position is marked `partial: true` and those sells carry no realized PnL. `heldAmount` is bought minus sold inside the window, never the on-chain balance. ## Coverage and freshness [Section titled “Coverage and freshness”](#coverage-and-freshness) * Totals are complete from `coverageSince` (Unix seconds, on `/overview`) to now; a “24 hours” window never starts before it (`coverageHours` under 24 = a partial day). Quote that field rather than a date. * `GET /v1/chains/solana/status` is the ingest’s own health: `ok`, `lagSlots`, `blockAgeS` (age of the newest block written), swaps per minute, per-venue decode counters. A `false` `ok` or a large `blockAgeS` means every other route is behind by that much: say so when you show the numbers. * Boards and stats are cached for 10 to 30 seconds, the trader board for 5 minutes. ## Addresses, units, names [Section titled “Addresses, units, names”](#addresses-units-names) * **Never lower-case a Solana address.** Base58 is case-sensitive: a lower-cased mint is another string, refused with `400 BAD_ADDRESS` when it is no longer valid base58 and answered `404 TOKEN_NOT_FOUND` otherwise. EVM validators (`0x` + 40 hex) do not apply. * **Amounts are whole units**: `tokenAmount`, `heldAmount`, `supply` are in tokens with decimals applied; `quoteAmount` is in whole units of the pool’s quote (SOL, USDC, USDT, or the other token of a token-to-token pool — see `pools[].quote`). Prices and `*Usd` fields are US dollars. * **Every timestamp is Unix seconds, `updatedAt` included** (elsewhere in the API `updatedAt` is milliseconds). * `symbol`, `name` and `image` are whatever the token’s creator wrote. Many mints share a symbol: identify a token by its mint. * **Most of Solana’s busiest tokens are wallets trading with themselves.** On 13 and 14 October 2026, about two thirds of the 400 most traded tokens on the tape (some 70 % of their volume) had under 3 % of their volume from wallets that went one way. The token boards leave out such volume-bot tapes, and tickers that imitate SOL, USDC or USDT on another mint: `screened` says how many and how much volume, every row carries `oneWayPct` (the share of 24-hour volume from wallets that bought or sold, not both at about the same size), `/chains/solana/token/{address}` carries `flow24h` and search rows carry `screen`. A low `oneWayPct` on a row that is shown (a deep market whose flow is mostly arbitrage) still means its volume is not demand. ## Endpoints [Section titled “Endpoints”](#endpoints) | Need | Call | | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | Is the tape current | `GET /v1/chains/solana/status` | | 24-hour totals, venue share, hourly buckets, `coverageSince` | `GET /v1/chains/solana/overview` | | The 24-hour token board | `GET /v1/chains/solana/tokens?sort=volume\|trades\|change\|new&limit=` | | Find a token by mint, symbol or name | `GET /v1/chains/solana/search?q=` (exact symbol or name; a mint returns that token) | | One token: price, change, market cap, liquidity, venues, pools, hourly | `GET /v1/chains/solana/token/{mint}?hours=24` (pass 24 or more: the 24-hour totals come from the same hourly rows) | | Newest prints of a token | `GET /v1/chains/solana/token/{mint}/trades?limit=&before=` | | Candles of the token’s main pool (or `pool=`) | `GET /v1/chains/solana/token/{mint}/candles?tf=1m\|5m\|15m\|1h\|4h\|1d&limit=` | | Who traded a token (whole UTC hours from `since`) | `GET /v1/chains/solana/token/{mint}/traders?hours=1..48&limit=` | | The day’s traders by realized PnL or volume | `GET /v1/chains/solana/traders?sort=pnl\|volume&days=1\|2&limit=` | | A wallet’s tokens and PnL | `GET /v1/chains/solana/wallet/{address}?days=1..45` | | A wallet’s swaps | `GET /v1/chains/solana/wallet/{address}/trades?limit=&before=` | Full parameters, response fields and real examples: the **Solana data** section of the API reference. No key is needed. `/v1/candles`, `/v1/tokens/*`, `/v1/quote` and the other chain-id routes do not take Solana. ```bash curl -s "https://api.getchord.xyz/v1/chains/solana/tokens?sort=trades&limit=5" curl -s "https://api.getchord.xyz/v1/chains/solana/token/7VertkgF9KLhxxJXHX6uaWuoYZTP9LdGj2bWmVXVpump?hours=24" curl -s "https://api.getchord.xyz/v1/chains/solana/token/7VertkgF9KLhxxJXHX6uaWuoYZTP9LdGj2bWmVXVpump/candles?tf=1h&limit=48" ``` ## Paging [Section titled “Paging”](#paging) `/trades` routes take `before` (Unix seconds, exclusive). Pass the last row’s `ts` for the next page; several swaps can share one second, so overlap with `ts + 1` and drop rows whose `tx` you already hold. A token’s page looks back at most two days from `before`, a wallet’s at most seven. # Bridge to Arc > Move USDC to Arc on Circle's CCTP rails, or bring any token from 60+ chains through LI.FI — the two bridge families and when to use which. **Goal**: a user with funds elsewhere ends up with USDC on Arc, ready to trade. ## Which rail [Section titled “Which rail”](#which-rail) | | CCTP (`/v1/bridge2/*`) | LI.FI (`/v1/crosschain/*`) | | ---------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | | Moves | USDC only, native burn and mint | any token the provider routes, swapped and bridged | | From | Ethereum, Base, Arbitrum, OP Mainnet, Polygon, Avalanche, Monad and the other CCTP domains | 60+ chains including Monad and Robinhood Chain (Arc as a destination is subject to provider support) | | Speed | fast transfer, seconds to a few minutes | route-dependent, minutes | | Gas on Arc | none for the user — Chord’s relayer submits the mint | destination gas handled by the route | | Fee | Circle’s fee (`/bridge2/fee`) | provider fee + the app fee in `/crosschain/config` | USDC in, Arc out: use CCTP. Anything else: LI.FI. ## CCTP fast transfer [Section titled “CCTP fast transfer”](#cctp-fast-transfer) 1. **Read the table.** `GET /bridge2/config` — the chains with their CCTP domains and USDC addresses, the TokenMessenger and MessageTransmitter contracts, and the relayer (address, Arc balance, enabled). 2. **Quote the fee.** `GET /bridge2/fee?src=6&dst=26` → `fastBps` and `standardBps`. 3. **Burn on the source chain.** The user approves USDC to `contracts.tokenMessengerV2` and calls `depositForBurn` with the Arc domain (`arcDomain`), the recipient as a 32-byte address, and the fast-finality threshold from `fastFinalityThreshold`. This is the only signature. 4. **Poll the attestation.** `GET /bridge2/status?srcDomain=6&tx=0x…` until `status: "complete"`. 5. **Relay the mint.** `POST /bridge2/relay { "srcDomain": 6, "tx": "0x…" }` — Chord’s relayer submits `receiveMessage` on Arc and returns the mint hash. `409 NOT_ATTESTED` means poll longer; `429 DAILY_CAP` means relay it yourself with the message and attestation from step 4. The user never needs USDC on Arc for gas, because the relayer pays the mint. ## LI.FI routes [Section titled “LI.FI routes”](#lifi-routes) 1. **Chains and tokens.** `GET /crosschain/config?provider=lifi` lists destinations; `GET /crosschain/currencies?chainId=8453&q=usdc&provider=lifi` lists bridgeable tokens on a chain. 2. **Quote.** `POST /crosschain/quote` with `user`, `originChainId`, `destinationChainId`, `originCurrency`, `destinationCurrency`, `amount` (smallest unit), `slippageBps` and `provider: "lifi"`. The answer carries the provider’s steps and fees and the transactions to sign on the origin chain; an approve step is prepended when the origin token is an ERC-20. 3. **Sign in order** and keep the deposit hash. 4. **Poll.** `GET /crosschain/status?requestId={depositHash}&provider=lifi&fromChain=8453&toChain=5042` until `success`, or `refund` / `failure`. `depositing` → `pending` → `submitted` → `success` is the happy path; `delayed` is a route waiting on the bridge. The Chord app embeds the LI.FI widget for this flow; the endpoints above are the same contract for a custom UI. ## After the bridge [Section titled “After the bridge”](#after-the-bridge) The user holds USDC on Arc as the predeploy balance, which is also their gas. Quote a trade with `inputMint=0x3600000000000000000000000000000000000000` and follow the [Swap recipe](/docs/recipes/swap/). # Charts > Candles from the tape, paging into history, live updates over the WebSocket, and trade markers. **Goal**: a candlestick chart for any indexed token on Arc or Robinhood Chain that loads in one call, pages backwards for history, and updates live. ## Load [Section titled “Load”](#load) ```ts const A = "https://api.getchord.xyz/v1"; const { candles, tf, source } = await fetch(`${A}/tokens/chart/${addr}?tf=1h`).then((r) => r.json()); // candles: [{ t, o, h, l, c, v }] oldest first, up to 200 ``` Timeframes: `1m` · `5m` · `15m` · `1h` · `4h` · `1d` · `1w`. `v` is USD volume in the bucket. `source: "db"` means Chord’s own tape. A `404 UNKNOWN_TOKEN` means the address is neither on a curated list nor a side of an indexed pool. ## Page into history [Section titled “Page into history”](#page-into-history) Pass the oldest `t` you have as `before`; each page is 200 candles. ```ts async function older() { const first = candles[0]?.t; const page = await fetch(`${A}/tokens/chart/${addr}?tf=1h&before=${first}`).then((r) => r.json()); candles.unshift(...page.candles); } ``` ## Live [Section titled “Live”](#live) Subscribe to the same token and timeframe on the WebSocket. The open candle is re-sent as it changes; `closed: true` seals it. ```ts ws.send(JSON.stringify({ op: "sub", channel: "candles", token: addr, tf: "1h" })); ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.op !== "candle" || m.token !== addr || m.tf !== "1h") return; const last = candles.at(-1); if (last && last.t === m.candle.t) Object.assign(last, m.candle); else candles.push(m.candle); }; ``` Switching timeframes: unsubscribe the old `tf`, fetch the new, subscribe the new. Eight channels per connection is enough for a chart, a tape and the price feed. ## Trade markers [Section titled “Trade markers”](#trade-markers) For a connected wallet, `GET /portfolio/{wallet}/trades?chain=5042` returns its buys and sells (`t`, `side`, `usd`, `tokenAmt`, `token`, `tx`); filter by token and draw markers at `t`. For the whole market, `GET /tokens/trades/{address}?min=1000` gives the large prints. ## Gaps [Section titled “Gaps”](#gaps) A bucket with no trades has no candle. Draw the gap or carry the last close forward — but do not invent a bar; the API does not. # Discover tokens > A markets board, a trending strip, a new-launches feed, search, and the attention signal — every discovery surface on Arc from four endpoints. **Goal**: the discovery layer of a trading app — what is traded, what is moving, what just launched, and search — on Arc. ## Markets board [Section titled “Markets board”](#markets-board) `GET /arc/tokens` returns every token that traded in the last 24 hours (about 1,500 on a normal day), with price, change, buy/sell volume, trades, traders, market cap, pool counts per venue and honesty flags. Sort server-side; page with `offset`. ```ts const { tokens, total } = await fetch(`${A}/arc/tokens?sort=volume&limit=100&offset=0`).then((r) => r.json()); ``` * Columns Chord shows: token (logo, symbol, `listed` check), price, 24h change, volume, buys / sells, traders, market cap (labelled FDV), pools. * `flags` present → grey the row and badge it. They already sort below clean rows. * `routable` → whether to draw a Buy button. * `includeUnlisted=1` adds tokens with no curated metadata or logo (most launches). Chord shows them, with the on-chain symbol. Keep the board moving between polls with the WebSocket `prices` channel — one subscription covers the whole board, prices and 24h counters alike, plus tokens trading for the first time: ```ts ws.send(JSON.stringify({ op: "sub", channel: "prices", chain: 5042 })); // { op: "prices", at, items: [{ address, priceUsd, ts, side, usd, volume24h, trades24h, buys24h, sells24h, … }] } // apply by address; use the counters when `at` is later than the REST page's `updatedAt` // { op: "new", items: [{ address, symbol, name, totalSupply, firstTs, priceUsd }] } — prepend to a "New" list ``` ## Trending [Section titled “Trending”](#trending) `GET /arc/trending?limit=20` — movers of the last two hours, scored from the hourly rollup. Each row is a full token row plus `score`, `volNow`, `tradesNow`, `change1hPct` and `momentum`. Poll every 30 s. ## New launches [Section titled “New launches”](#new-launches) `GET /arc/graduated?hours=48&limit=100` — tokens whose first pool on Arc was created in the window, routable today and screened (impostor symbols, launch farms, no-sell tokens, too few traders removed). Newest first; `launchedAt`, `launcher`, `launcherName` and `creator` on each row; `screened` counts what each filter removed, which is worth showing (“1,615 launch-farm tokens hidden”). Poll every 60 s. Pair it with `GET /arc/launchers?hours=24` for the launchpad strip: which launchers are active, pools per hour, and 24-hour volume over the pools each one created. ## Search [Section titled “Search”](#search) `GET /arc/tokens/search?q=argus&limit=10` — symbol, name or address over every token traded in the last 24 hours. Exact symbol first, then prefix, name, substring; listed tokens and volume break ties so the real ARGUS outranks a copy. A pasted address always returns that token. Debounce at 200 ms; `coverage` says how many tokens have a resolved name yet. ## Attention [Section titled “Attention”](#attention) `GET /arc/attention?days=1&limit=20` — what people on Chord are looking at (searches, views, questions to the analyst, watchlist adds). A demand signal, independent of price; use it for a “people are watching” rail. ## Putting it together [Section titled “Putting it together”](#putting-it-together) Chord’s markets page polls `/arc/tokens` every 20 s, `/arc/trending` every 30 s, `/arc/graduated` every 60 s, keeps prices live over the WebSocket, and runs search on demand. That is well inside the anonymous limit; a key is only needed when you serve many users from one server. # Launch lifecycle > From a launcher creating a pool to a token with holders and liquidity — following a launch on Arc through the API. **Goal**: a launch feed and the forensics behind it. On Arc most tokens are born through a launcher contract that creates a Uniswap V4 pool (often with a hook that runs a bonding curve) or a V3 / V2 pool with seeded liquidity. Chord indexes every one. ## 1. Who is launching [Section titled “1. Who is launching”](#1-who-is-launching) `GET /arc/launchers?hours=24` — every launcher seen in the window: name and site where the registry knows it (Uniswap Liquidity Launcher, aka.fun, Argus, Minara.fun, Rapid Launch, Sharc.fun, Bozo, …), the pool shapes it creates (hook, fee, tick spacing), pools per hour and day, distinct creators, and the 24-hour tape over its pools (swaps, volume, wallets, active pools). The [Launchpads](/docs/launchpads/) page lists the named ones. ## 2. What launched [Section titled “2. What launched”](#2-what-launched) `GET /arc/graduated?hours=48` — tokens whose first pool was created in the window, routable today and screened. Each row has `launchedAt`, `launcher`, `launcherName`, `creator`, `ageSec` and the full 24-hour token row. `screened` counts what the filters removed: | Screen | Removes | | ------------------------- | -------------------------------------------------------------- | | `serial_creator` | one creator, eight or more pools in the window — a launch farm | | `impostor` | a symbol copying a listed token | | `no_sells` | buys only — a token that cannot be sold | | `few_traders` | too few distinct wallets | | `not_routable` | no pool the engine can quote | | `no_trades` · `no_symbol` | nothing happened, or no name on-chain | Show the counts. On a busy day the farm screen alone removes over a thousand pools. ## 3. Is it real [Section titled “3. Is it real”](#3-is-it-real) For one launch, three calls tell you most of what matters: * `GET /arc/token/{address}/holders` — holder count, `heldByWalletsPct` (supply outside pools), `concentration.top10`, and the top rows tagged wallet / pool / burn. A launch where two wallets hold 90 % outside the pool is a different thing from one with 500 holders. * `GET /lp/token/{address}/pools?chain=5042` — the pools with `score`, `reasons` and `launch`: how much of the liquidity the launcher supplied and whether it has started pulling (`launcherRemovedUsd`, `launcherLastRemoveTs`). * `GET /tokens/stats/{address}` — buyers versus sellers per window, makers, and whether volume is many wallets or a few. `flags` on the token row (`wash`, `impostor`) and `suspect` on its pools are the same checks, precomputed. ## 4. Trade it [Section titled “4. Trade it”](#4-trade-it) A launch that is `routable` quotes like any token: `GET /quote?chain=5042&inputMint=0x3600…0000&outputMint={address}&amount=…`. Hooked V4 pools route only through hooks the engine has verified end to end; a pool on an unknown hook is `NO_POOLS` until it is. Expect high `priceImpactPct` on a fresh curve, and simulate before signing. ## 5. Watch it [Section titled “5. Watch it”](#5-watch-it) * Prices: WebSocket `prices` (chain 5042) for the board, `trades` for the token. * Liquidity: `GET /lp/events?chain=5042&token={address}` for adds and removes; `POST /lp/watch/pool` to get an alert when a pool drains. * Attention: `GET /arc/attention` shows what people on Chord are watching. ## Ask instead [Section titled “Ask instead”](#ask-instead) The analyst answers “is this launch a rug” in one call with the same data: `POST /v1/ask { "question": "launch forensics on 0x…", "stream": false }` with an API key. See [Ask agent API](/docs/agents/ask-api/). # LP dashboard > A pools screener, a pool page, a range planner and a positions view for liquidity providers on Arc. **Goal**: the liquidity side of a trading app — where the fees are, whether a pool is honest, what range to take, and how open positions are doing. ## Headline strip [Section titled “Headline strip”](#headline-strip) `GET /lp/overview?chain=5042` — fees paid to LPs in 24 hours, the best real yield (≥ 25 traders, not suspect), liquidity added and removed, volume, TVL and providers over pools with ≥ $10k TVL, the six hottest pools by fees (`hot`) and the three biggest net inflows (`inflow`). One call, memoised 30 s. ## Pools screener [Section titled “Pools screener”](#pools-screener) ```ts const { pools, total, hidden } = await fetch(`${A}/lp/pools?chain=5042&sort=fee_tvl&interval=24h&limit=50`).then((r) => r.json()); ``` Columns: pair (`token0` / `token1` with logos and `impostor` flags), venue (`dex`), fee tier (`feeBps`), TVL, volume and fees for the interval, `feeTvlPct`, `aprPct`, traders (`wallets24h`), LP net flow (`lpAdd24h − lpRemove24h`), providers, age (`createdTs`), `score`. * Sorts: `fee_tvl` · `vol_24h` · `vol_1h` · `tvl` · `fees_24h` · `first_seen` · `lp_net_24h` · `trades_24h` · `score`. * Filters: `quote=USDC` (anchor), `dex=uniswap_v4`, `search=argus`, `minTvl=`, `small=1` (under $10k), `flagged=1` (show suspect pools, greyed). * `hidden` is how many rows the filters removed — show it; users ask. * `lpAccess: "hooked"` means a V4 hook can refuse adds. Do not offer a mint button on those. ## Pool page [Section titled “Pool page”](#pool-page) `GET /lp/pools/{pool}?chain=5042` returns the row plus: * `hourly` — 7 days of volume, trades and price for the chart. * `topLps` — providers over 7 days with net dollars. * `health` — the score, its six parts and `reasons` in plain English. * `launch` — who launched it, the launcher’s share of all liquidity ever added, and when it last pulled. * `mint` — what a wallet needs to add liquidity: manager, pool key, Permit2, tick spacing, native flag. `GET /lp/pools/{pool}/positions?chain=5042&limit=20` lists the open positions in the pool, largest first, valued live. `GET /lp/events?chain=5042&pool={pool}&minUsd=1000` is the add/remove tape. ## Range planner [Section titled “Range planner”](#range-planner) ```ts const plan = await fetch(`${A}/lp/plan?chain=5042&token=${addr}&amountUsd=1000&days=7`).then((r) => r.json()); ``` `bands.profiles` gives tight, balanced and wide ranges from the token’s own volatility with the share of the last seven days inside each; `sims[]` backtests each against holding — fees, impermanent loss, exits, net versus hold, capital efficiency. Draw `bands.histogram` (hours the price spent in each bucket) behind the ranges. `young: true` means fewer than two days of candles: say so instead of drawing bands. For a user-drawn range call `GET /lp/simulate` with `lower` and `upper`. ## Positions [Section titled “Positions”](#positions) `GET /lp/positions?chain=5042&owner={wallet}&status=open` — each position with `valueUsd`, `uncollectedUsd`, `inRange`, `edgePct` (distance to the nearest edge), `pnlUsd` and `ageHours`; `summary` for the header. `GET /lp/position/{chain}/{manager}/{id}` opens one with its events and a hold-instead comparison. Closed positions page with `status=closed&limit=25&offset=25`, newest first, and `pool=` keeps one pool. Alerts: `POST /lp/watch { chain, wallet }` turns on out-of-range, fee-bar and drain alerts and returns a Telegram deep link; `GET /lp/watch?chain=&wallet=` is the inbox. ## Leaderboard [Section titled “Leaderboard”](#leaderboard) `GET /lp/leaderboard?chain=5042&sort=profit&limit=48` — providers by profit (all time, or `profit_7d` / `profit_30d`), win rate, fees, EV, age, invested, monthly profit or last activity, with inclusive filters (`minPositions`, `minWinRate`, `minEv`, `lastActiveDays`, …) and the last seven days of profit per wallet for a sparkline. Wallets whose profit came from the token’s price rather than fees are left out and counted in `hidden`; `all=1` keeps them. ## One wallet, one pool’s providers [Section titled “One wallet, one pool’s providers”](#one-wallet-one-pools-providers) `GET /lp/wallet/{address}?chain=5042` is the page behind a leaderboard row: the same figures for that wallet whether it is ranked or not (`summary`), one row per UTC day on which a position ended with the profit and the fees that landed on it (`history`: draw it as bars with a running total, or as a calendar), and the pools it provided to. `unscored` says how many of its positions the figures leave out and why. `GET /lp/pools/{pool}/lps?chain=5042` ranks a pool’s providers by what they made there (profit, fees, positions, average age, win rate), where the pool’s `topLps` ranks them by how much they moved. ## Cadence [Section titled “Cadence”](#cadence) Overview and screener every 30 s, pool page every 30 s, positions every 60 s. All are cached server-side at those intervals, so faster polling returns the same bytes. # Swap from your app > Quote, approve, simulate, build, sign — the full non-custodial swap flow on Arc, with the edge cases that bite. **Goal**: a working swap button. Chord finds the route and builds the transaction; the user’s wallet signs it. Chord never holds funds or keys. ## 1. Resolve tokens and decimals [Section titled “1. Resolve tokens and decimals”](#1-resolve-tokens-and-decimals) ```ts const A = "https://api.getchord.xyz/v1"; const { tokens } = await fetch(`${A}/tokens?chain=5042`).then((r) => r.json()); const USDC = tokens.find((t) => t.symbol === "USDC"); // 0x3600…0000, 6 decimals ``` For a token that is not on the curated list, `GET /arc/tokens/search?q=` returns its address and `decimals` from the chain. Never assume 18. ## 2. Quote on intent [Section titled “2. Quote on intent”](#2-quote-on-intent) Quote when the user has typed an amount and paused, not on every keystroke. Paint a first number with `fast=1` and replace it with the full answer. ```ts const params = new URLSearchParams({ chain: "5042", inputMint: USDC.address, outputMint: token.address, amount: (5n * 10n ** 6n).toString(), slippageBps: "100" }); const [fast, full] = await Promise.all([ fetch(`${A}/quote?${params}&fast=1`).then((r) => r.json()), fetch(`${A}/quote?${params}`).then((r) => r.json()), ]); const quote = full; // never build from `fast` (preliminary: true) if (quote.routePlan.length === 0) return showNoRoute(quote.noRouteReason); // INSUFFICIENT_LIQUIDITY → suggest a smaller size ``` Show `outputAmount` (scaled by the output token’s decimals), `priceImpactPct`, `feeBps`, and `otherAmountThreshold` as the minimum received. ## 3. Approve the router when needed [Section titled “3. Approve the router when needed”](#3-approve-the-router-when-needed) For an ERC-20 input — and on Arc every input is one, since the native unit aliases to the USDC predeploy — the router must be allowed to pull `inputAmount`. The router address is `transaction.to` in the `/swap` answer (`0x1b1fee89a381e595fe6536b99ba91f3e16e9601a` on both chains). Read the allowance first and skip the approve when it is enough. ```ts const allowance = await publicClient.readContract({ address: USDC.address, abi: erc20Abi, functionName: "allowance", args: [wallet, ROUTER] }); if (allowance < BigInt(quote.inputAmount)) { await walletClient.writeContract({ address: USDC.address, abi: erc20Abi, functionName: "approve", args: [ROUTER, BigInt(quote.inputAmount)] }); } ``` ## 4. Build [Section titled “4. Build”](#4-build) ```ts const { transaction } = await fetch(`${A}/swap`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ quoteResponse: quote, userPublicKey: wallet, chain: 5042 }), }).then((r) => r.json()); ``` Send the quote back **unmodified**. A changed body is `400 ROUTE_MISMATCH`; a different `slippageBps` is `400 SLIPPAGE_MISMATCH` — re-quote instead. Pass `feeAccount` if you are a referrer. ## 5. Simulate [Section titled “5. Simulate”](#5-simulate) ```ts const sim = await fetch(`${A}/swap/simulate`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ chain: 5042, from: wallet, to: transaction.to, data: transaction.data, value: transaction.value }), }).then((r) => r.json()); if (sim.ok === false && !/not approved/i.test(sim.revert)) return showRevert(sim.revert); ``` An allowance revert right after the approve is expected (the approve may not be mined yet); proceed. Any other revert, stop. ## 6. Sign and send [Section titled “6. Sign and send”](#6-sign-and-send) ```ts const hash = await walletClient.sendTransaction({ to: transaction.to, data: transaction.data, value: BigInt(transaction.value), gas: BigInt(transaction.gasLimit), chain: arc, }); ``` On Arc `value` is always `0`. Wait for the receipt; the output lands in the user’s wallet. Explorer: `https://explorer.arc.io/tx/${hash}`. ## Edge cases [Section titled “Edge cases”](#edge-cases) * **Quote expired.** A quote is good for about 30 seconds. If the user idled, quote again before `/swap`. * **Price moved past the threshold.** The transaction reverts with insufficient output. Quote again; do not resubmit. * **Gateway dropped the send.** Arc’s public gateway has been seen dropping one broadcast in six. Use a dedicated RPC for `sendRawTransaction` and retry with the same nonce on a timeout. * **Robinhood Chain.** Same flow with `chain: 4663`; native ETH is the zero address and is sent as `value`, WETH is wrapped for you. Stocks and USDG are 0 bps. * **Contracts calling the router.** `GET /swap/calldata` quotes and encodes in one call with the output to `msg.sender`. # Build a token page > Header, chart, tape, venues, pools, holders and a trade card for one token on Arc — which calls, in what order, and what to stream. **Goal**: the page Chord itself shows for a token on Arc — price and change in the header, a candle chart, the trade tape, venue split, pools, holders, and a route card — built from six calls on load and two WebSocket channels after. ## On load, in parallel [Section titled “On load, in parallel”](#on-load-in-parallel) | Component | Call | Read | | ----------------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | | Header (symbol, name, logo, price, 24h change, market cap, flags) | `GET /arc/token/{address}?hours=24` | `token` — the full token row; `series` for a 24-hour volume bar | | Windowed stats (5m / 1h / 6h / 24h, ATH, 24h range, makers) | `GET /tokens/stats/{address}` | `windows`, `ath`, `range24h`, `markets` | | Chart | `GET /tokens/chart/{address}?tf=1h` | `candles` (200, oldest first); page back with `before` | | Trade tape | `GET /tokens/trades/{address}?limit=50` | `trades`, `stats24h` | | Pools | `GET /lp/token/{address}/pools?chain=5042` | pools ranked by health, with launch facts | | Holders | `GET /arc/token/{address}/holders?limit=20` | `holders`, `concentration`, `top` (each tagged wallet / pool / burn) | ```ts const A = "https://api.getchord.xyz/v1"; const [tok, stats, chart, tape, pools, holders] = await Promise.all([ `${A}/arc/token/${addr}?hours=24`, `${A}/tokens/stats/${addr}`, `${A}/tokens/chart/${addr}?tf=1h`, `${A}/tokens/trades/${addr}?limit=50`, `${A}/lp/token/${addr}/pools?chain=5042`, `${A}/arc/token/${addr}/holders?limit=20`, ].map((u) => fetch(u).then((r) => (r.ok ? r.json() : null)))); ``` Treat a `null` (a `404` or `503`) per component: a `503 HOLDERS_PENDING` means the ledger just started tracking this token — show “building” and retry in a few minutes; a `404` on the chart means the token has no indexed pool yet. ## Then stream [Section titled “Then stream”](#then-stream) ```ts const ws = new WebSocket("wss://api.getchord.xyz/v1/ws/live"); ws.onopen = () => { ws.send(JSON.stringify({ op: "sub", channel: "candles", token: addr, tf: "1h" })); ws.send(JSON.stringify({ op: "sub", channel: "trades", token: addr })); }; ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.op === "candle") chart.upsert(m.candle); // by t; closed:true seals the bucket if (m.op === "trades") { tape.prepend(m.items); header.price = m.items[0].priceUsd; } }; ``` The header price is the latest print; a green dot while frames arrive is honest “live”. Re-fetch `/arc/token` and `/tokens/stats` every 30–60 s for the rolled-up figures. ## Header details [Section titled “Header details”](#header-details) * `token.listed` false: show the on-chain symbol with a “not on the list” hint; `logoURI` is a placeholder until art is found. * `token.flags` includes `wash` or `impostor`: badge it. The boards already sort such rows down; the page should say why. * `token.routable` false: hide the trade card, or show “no route yet”. * `marketCapUsd` is fully diluted; label it FDV. ## The trade card [Section titled “The trade card”](#the-trade-card) Quote on the user’s amount with `GET /quote?chain=5042&inputMint=0x3600…0000&outputMint={address}&amount=…`, then follow the [Swap recipe](/docs/recipes/swap/). Link the row to `https://getchord.xyz/arc/token/{address}?side=buy` if you would rather hand off to Chord. ## Venues and pools [Section titled “Venues and pools”](#venues-and-pools) `tok.byDex` (24-hour share per venue id) makes the venue table; map ids to names with the [venue ids](/docs/resources/venue-ids/) table. `pools` from the liquidity family carries `score` and `reasons` — show the reasons on hover, they are the difference between a pool with fifty providers and one where the launcher holds everything. ## Holders [Section titled “Holders”](#holders) `heldByWalletsPct` is supply outside pools and burn sinks. `concentration.top10` above \~60 % on a token with thousands of holders is worth a badge. Rows tagged `pool` are the pools themselves; `burn` is the dead address. # Trader dashboard > Top wallets on Arc, one wallet's PnL and history, its calendar, and its liquidity positions — a Nansen-style page from five calls. **Goal**: a “who is winning” board and a wallet profile page. ## Top wallets [Section titled “Top wallets”](#top-wallets) ```ts const board = await fetch(`${A}/smart-money/top?chain=5042&source=onchain&window=7d&limit=50`).then((r) => r.json()); ``` `wallets` are ranked by [Smart Score](/docs/concepts/wallet-pnl/#smart-score), with routers and bots already removed (`botsRemoved` says how many). Show `pnlUsd` (realized + open), `realizedUsd`, `winRate`, `trades`, `topToken` and `archetype`. `totalWallets` is how many qualified; `indexedToBlock` is the tape’s head when the board was built. `503 CHAIN_NOT_ENABLED` means the board is not published for the chain yet. Windows: `24h` (rebuilt every 15 minutes), `7d` and `30d` (hourly), `all` (three-hourly). On Arc a live delta sits on top of the last rebuild, so polling every 30 s shows movement. ## Wallet profile [Section titled “Wallet profile”](#wallet-profile) Four calls in parallel: | Panel | Call | | -------------------------------------------- | -------------------------------------------------------- | | Holdings and PnL per token | `GET /portfolio/{wallet}/pnl?chain=5042` | | Trade history (chart markers, activity list) | `GET /portfolio/{wallet}/trades?chain=5042` | | Calendar (realized PnL by day) | `GET /portfolio/{wallet}/pnl-calendar?chain=5042` | | Liquidity positions | `GET /lp/positions?chain=5042&owner={wallet}&status=all` | ```ts const [pnl, trades, cal, lp] = await Promise.all([ `${A}/portfolio/${w}/pnl?chain=5042`, `${A}/portfolio/${w}/trades?chain=5042`, `${A}/portfolio/${w}/pnl-calendar?chain=5042`, `${A}/lp/positions?chain=5042&owner=${w}&status=all`, ].map((u) => fetch(u).then((r) => r.json()))); ``` * `pnl.tokens[]` gives realized, unrealized, average cost, current amount and value, ROI, and the **untracked** balance that arrived by transfer (no cost basis). Show untracked separately; it is not a loss or a gain. * `pnl` is cached stale-while-revalidate: `updatedAt` tells you how old the answer is; a first view of a busy wallet may take a few seconds. * `cal.days[]` (`date`, `realizedUsd`, `trades`) draws the calendar; `realizedTotal` reconciles with `pnl.realized`. * `lp.summary` (open, closed, wins, win rate, realized LP PnL, fees, open value) and `lp.positions[]` (each with live value, in-range, fees, `jit` / `unreconciled` flags) make the liquidity tab. ## Is this wallet a bot? [Section titled “Is this wallet a bot?”](#is-this-wallet-a-bot) The board already removed bots. For a wallet you look up directly, the tells are in the data: hundreds of trades a day from the first trade, buy-then-sell inside a minute, dozens of launches sniped. The Ask agent can answer “is 0x… a bot” with its wallet profile tool if you would rather not implement the heuristics. ## Follow a trader [Section titled “Follow a trader”](#follow-a-trader) There is no server-side follow. Poll `GET /portfolio/{wallet}/trades?chain=5042` every 30–60 s and diff by `tx`, or subscribe to the WebSocket `trades` channel for the tokens the wallet holds and match `wallet` on incoming items. # Changelog > What changed in the API, newest first. ## 2026-10-16 [Section titled “2026-10-16”](#2026-10-16) * **Chord for agents and answer engines**: every docs page has a Markdown twin (add `.md` to its path, or send `Accept: text/markdown`), and [`/llms.txt`](/llms.txt) now lists them all with a line each. Agents can find Chord’s tools from the domain alone: [`/.well-known/api-catalog`](/.well-known/api-catalog) (RFC 9727), [`/.well-known/ai-catalog.json`](/.well-known/ai-catalog.json) with an MCP server card for each server (`https://api.getchord.xyz/v1/mcp/server-card`, `https://getchord.xyz/docs/mcp/server-card`), and [`/.well-known/agent-skills/index.json`](/.well-known/agent-skills/index.json) with the skill as one archive. `/llms-full.txt`, `/openapi.json` and `/skill.md` answer at the site root. See [llms.txt, Markdown and discovery files](/docs/agents/llms-txt/). * **Solana swaps are open to everyone** (2026-10-15 21:25 UTC): `/v1/sol/trade/quote`, `/send` and `/tx/{signature}` answer every caller, no key needed. Each quote builds Chord’s own route and Jupiter’s for the wallet, simulates both and returns the one that leaves the wallet with more; the wallet signs the returned transaction unchanged. See [Solana](/docs/networks/solana/#swaps). * **Robinhood Chain token list: one token per symbol.** A stock token owns its ticker (memes reusing GME, AMC, NET, FLY or BULL are left out); among memes that share a symbol the busiest in the last 24 hours stays. `/v1/tokens/search?chain=4663` follows the same rule, and lists the others as `verified: false` when they traded in the last 24 hours. Boards, token pages and charts are unchanged. * **Chord routes Solana swaps itself**: `/v1/sol/trade/quote` now builds a third route of Chord’s own, `direct`, on Raydium AMM v4 / CPMM / CLMM, Orca Whirlpool, Meteora DLMM / DAMM v2, Meteora DBC and Raydium LaunchLab (plus pump.fun and PumpSwap, as before), with pools from Chord’s tape and up to two pools per swap. It is built and simulated for the wallet next to Jupiter’s swap API and Jupiter’s order; the wallet gets whichever leaves it with more. New `venue` values on a quote: `raydium_v4`, `raydium_cpmm`, `raydium_clmm`, `orca`, `meteora_dlmm`, `meteora_damm_v2`, `meteora_dbc`, `raydium_launchlab`; `hops` lists the pools and their share. See [Solana](/docs/networks/solana/#swaps-beta). * **Fixed in the reference**: `GET /v1/tokens` and `GET /v1/logo/{chain}/{address}` list all eight EVM chains (they have answered on 43114, 8453, 56, 42161 and 1 since each chain went public; the reference said `5042`, `4663` and `143`). The function-calling manifest at `/agent/tools.json` carries `arbitrum` and `ethereum` like the hosted MCP. * **Robinhood Chain token list**: a look-alike USDG (`0x5fc54b6c…d168`, no trades) is no longer listed beside the real one (`0x5fc5360d…d168`). A token that takes the symbol of a chain anchor under another address is left out. ## 2026-10-15 [Section titled “2026-10-15”](#2026-10-15) * **Ethereum (1) is public**: `/v1/chains/ethereum/*`, `/v1/candles?chain=1`, `/v1/tokens/search?chain=1`, the hosted MCP and Ask read it; `/v1/quote` and `/v1/swap` route on it through the same Chord router (Uniswap V2 / V3 / V4, PancakeSwap V3, SushiSwap V2 / V3). Ethereum’s USDT refuses a new approval over a left-over one: `/v1/meta` answers carry `approval.resetFirst`. See [Ethereum](/docs/networks/ethereum/). * **Arbitrum One (42161) is public**: `/v1/chains/arbitrum/*`, `/v1/candles?chain=42161`, `/v1/tokens/search?chain=42161`, the hosted MCP and Ask read it; `/v1/quote` and `/v1/swap` route on it through the same Chord router. See [Arbitrum](/docs/networks/arbitrum/). * **Every chain has a network page**: [Monad](/docs/networks/monad/), [Avalanche](/docs/networks/avalanche/), [Base](/docs/networks/base/), [BNB Chain](/docs/networks/bnb-chain/) and [Arbitrum](/docs/networks/arbitrum/) join Arc, Robinhood Chain and Solana, with ids, anchors, contracts, venues and the routes that serve each one. * **Fixed in the reference**: `/v1/quote`, `/v1/swap`, `/v1/swap/calldata` and `/v1/swap/simulate` list chains `43114`, `8453`, `56` and `42161`. The first three have answered on those chains since 2026-10-02; the reference said `5042`, `4663` and `143` only. ## 2026-10-11 [Section titled “2026-10-11”](#2026-10-11) * **Backtests are in the reference**: `GET /v1/backtest` replays a bar-close strategy (Supertrend, EMA cross, RSI, Donchian, buy and hold) over stored candles of any Hyperliquid perp and 13 FX pairs and metals; `GET /v1/fx/lake` shows how far the FX store is filled. The reference now states the model, every parameter with its default, and that this endpoint’s times are in milliseconds. The endpoint has been live since 2026-09-24. * **Fixed**: `/v1/backtest` upper-cased the symbol, so Hyperliquid’s k-prefixed perps (`kPEPE`, `kSHIB`, `kBONK`, `kFLOKI`, `kLUNC`, `kNEIRO`, `kDOGS`) found no bars. The symbol is now matched without case. ## 2026-10-04 [Section titled “2026-10-04”](#2026-10-04) * **Solana data, read-only** (public since 2026-10-04): `GET /v1/chains/solana/status`, `/overview`, `/tokens`, `/search`, `/token/{mint}` (+ `/trades`, `/candles`, `/traders`), `/traders`, `/wallet/{address}` (+ `/trades`). Chord’s own tape of the swap events of 11 venues (PumpSwap, pump.fun, Meteora, Raydium, Orca); prop AMMs and order books are not read. Addresses are base58 and case-sensitive; `updatedAt` on these routes is Unix seconds. See [Solana](/docs/networks/solana/). ## 2026-09-30 [Section titled “2026-09-30”](#2026-09-30) * **Live boards on Robinhood Chain**: the WebSocket `prices` channel now serves chain `4663` as well as `5042` (and `143`), every print within \~400 ms. * **Live 24h counters**: `prices` items on Arc and Robinhood Chain carry `volume24h`, `trades24h` (and on Arc `buyVolume24h`, `sellVolume24h`, `buys24h`, `sells24h`); frames carry `at`. `GET /v1/tokens/market?chain=4663` returns `updatedAt` and, like `/v1/arc/tokens`, already includes trades the hourly rollup has not counted yet. * **First-time tokens**: `new` frames on the same subscription, with on-chain name and supply. ## 2026-09-20 [Section titled “2026-09-20”](#2026-09-20) * **Docs**: this site, with the API reference generated from the OpenAPI document and `llms.txt`. * **Liquidity**: `GET /v1/lp/overview` (fees paid to LPs, best real yield, flows, hot pools), `GET /v1/lp/plan` and `GET /v1/lp/simulate` (range bands and backtests), `GET /v1/lp/pools/{pool}` now returns `health`, `launch` and `mint`, `GET /v1/lp/token/{address}/pools` ranks by health. * **Top wallets on Arc** move between rebuilds: a live delta of the last minutes’ trades sits on the rolled board (`live` in the response). ## 2026-09-19 [Section titled “2026-09-19”](#2026-09-19) * **Venue names on Arc**: `synthra_v3`, `sushi_v2`, `sushi_v3`, `dyorswap` and `slipstream_fork` replace factory-keyed ids for those venues. * **Honesty flags** on token rows (`wash`, `impostor`) and pool rows (`suspect`, `token0.impostor`); boards sort flagged rows last and `/lp/pools` hides suspect pools unless `flagged=1`. ## 2026-09-18 [Section titled “2026-09-18”](#2026-09-18) * **Liquidity family** `/v1/lp/*` on Arc, Robinhood Chain and Monad: events, pools, positions, leaderboard, watch alerts. * **Ask agent API**: `POST /v1/ask` accepts a developer API key and `stream: false`; `GET /v1/ask/picks`; research notes via `POST /v1/ask/report`. * **Token art round two**: logos resolved from the token’s own creation transaction; the logo proxy serves every Arc row. ## 2026-09-17 [Section titled “2026-09-17”](#2026-09-17) * **Holder ledger**: `GET /v1/arc/token/{address}/holders` — balances from Transfer logs, tagged wallet / pool / burn, with concentration. * **Launch radar**: `GET /v1/arc/launchers` and launcher names on `GET /v1/arc/graduated`. * **Attention**: `GET /v1/arc/attention`. ## 2026-09-16 [Section titled “2026-09-16”](#2026-09-16) * **Trading live on Arc**: the router, fee collector and adapter registry at the same addresses as the other chains; `/quote` and `/swap` with `chain=5042`. Uniswap V4 pools route with native USDC, including verified launchpad hooks. The native sentinel aliases to the USDC predeploy. * **Live Arc prices** over `/v1/ws/live` channel `prices`. * **Bridge**: `/v1/bridge2/*` (Circle CCTP fast transfer to Arc with a gasless mint relay) and LI.FI on `/v1/crosschain/*` (`provider=lifi`). * **Portfolio and top wallets** on Arc (`chain=5042`). ## 2026-09-15 [Section titled “2026-09-15”](#2026-09-15) * **Arc index**: the trade tape, hourly and daily rollups, and `/v1/arc/*` (status, overview, venues, tokens, search, trending, token). * **Token list** for Arc: `GET /v1/tokens?chain=5042`. ## 2026-09-08 [Section titled “2026-09-08”](#2026-09-08) * **Chord** launches with the Robinhood Chain index: `/v1/rh/*` (overview, venues, tokens, token, stocks), the stocks page and the developer portal with API keys. # FAQ > Short answers to the questions integrators ask first. **Do I need a key?** No, to read. Anonymous calls get 60 requests a minute per IP (300 on the token and portfolio reads). A key raises that to your plan and is required for the Ask agent API. **Is Chord custodial?** No. `/swap` returns an unsigned transaction; your wallet signs and broadcasts. Chord never holds funds or keys, on any plan. **Where do prices come from?** From Chord’s own index of every swap on the chain, priced at index time against the chain’s anchors. No third-party price API on the request path. `priceUsd` on a token row is the last trade on the token’s dominant venue. **Why does `/quote` return an empty route?** No venue fills that size honestly. `noRouteReason` says `INSUFFICIENT_LIQUIDITY` (try a smaller amount) or `NO_POOLS` (no pool against an anchor, or only on an unverified hook). The engine never fabricates a price. **Why is my Arc transaction’s `value` 0 when I sell “native” USDC?** Because on Arc the native unit and the USDC predeploy are one balance, and the router pulls the predeploy by `transferFrom`. Approve the router on `0x3600…0000` like any ERC-20. See [Chains, addresses and amounts](/docs/concepts/chains-and-amounts/). **How fresh is the data?** Read `coverage` on rollup answers and `/v1/arc/status`, `/v1/rh/status`, `/v1/lp/status` for the lanes. Prices over WebSocket are per print. See [Data freshness](/docs/concepts/data-freshness/). **What is a 503 `NOT_READY`?** A lane that has not run on this deployment yet, or a token the holder ledger just started tracking. Retry later; do not show it as “no data”. **Why are some tokens missing from `/v1/tokens`?** `/v1/tokens` is the curated list. `/v1/arc/tokens?includeUnlisted=1` is every token that traded in 24 hours, listed or not, with the on-chain symbol. **How are bots removed from the top-wallets board?** By cadence (hundreds of transactions a day from the first trade), nonce rate and deny lists, and behaviour (bursts, sub-minute round trips, sniping dozens of launches). `botsRemoved` counts each pass. **Can I stream Arc prices?** Yes — subscribe to the `prices` channel on `/v1/ws/live` with `chain: 5042`. One subscription covers the whole board. **Can I get the whole API in one file?** [openapi.json](/docs/openapi.json). And this documentation as text at [llms.txt](/docs/llms.txt). **Where do fees go?** The protocol fee on the output token (5 bps by default on every chain, 0 on USDC / EURC / USDG / stocks) goes to the fee collector; a referrer passed as `feeAccount` earns 50 % of it on that swap. Quotes and API usage are free. # Troubleshooting > The failures integrators hit, what they mean, and the fix. ## `400 INVALID_PARAMS` on `/quote` [Section titled “400 INVALID\_PARAMS on /quote”](#400-invalid_params-on-quote) The message names the parameter. The usual ones: `amount` sent as a float or with decimals (it must be an integer string in the smallest unit); `inputMint` equal to `outputMint`; a chain id the API does not serve. ## `400 SLIPPAGE_MISMATCH` on `/swap` [Section titled “400 SLIPPAGE\_MISMATCH on /swap”](#400-slippage_mismatch-on-swap) You sent a `slippageBps` that differs from the quote’s. The signed minimum is the quote’s `otherAmountThreshold`; the field on `/swap` is a consistency check. Omit it, or quote again at the slippage you want. ## `400 ROUTE_MISMATCH` on `/swap` [Section titled “400 ROUTE\_MISMATCH on /swap”](#400-route_mismatch-on-swap) The quote body was edited between `/quote` and `/swap` (re-serialised numbers, dropped fields). Pass the parsed object back untouched. ## The transaction reverts with insufficient output [Section titled “The transaction reverts with insufficient output”](#the-transaction-reverts-with-insufficient-output) The price moved past `otherAmountThreshold` between quote and execution. Quote again. Do not resubmit an old transaction — and if the route is a fresh launchpad curve, expect the number to move fast. ## The transaction reverts before the wallet opens [Section titled “The transaction reverts before the wallet opens”](#the-transaction-reverts-before-the-wallet-opens) Run `POST /v1/swap/simulate`. `revert` names it: `Router is not approved…` means approve first (an approve that is not mined yet also triggers this — proceed); `ERC20InsufficientBalance` means the wallet does not hold `inputAmount`; a paused venue is muted within seconds, quote again. ## Broadcast times out on Arc [Section titled “Broadcast times out on Arc”](#broadcast-times-out-on-arc) The public gateway has been seen dropping one send in six. Broadcast through a dedicated RPC and, on a timeout, resend the same signed transaction (same nonce) rather than rebuilding. ## `404 UNKNOWN_TOKEN` on charts, trades or stats [Section titled “404 UNKNOWN\_TOKEN on charts, trades or stats”](#404-unknown_token-on-charts-trades-or-stats) The address is neither on a curated list nor a side of an indexed pool. For Arc, check `GET /v1/arc/tokens/search?q=0x…` — if it returns a row with `pools` counts, the token is indexed and the chart will fill as trades arrive; if not, the token has no pool yet. ## `503 HOLDERS_PENDING` [Section titled “503 HOLDERS\_PENDING”](#503-holders_pending) The holder ledger just pinned the token. The backfill walks Transfer logs back to the creation block; retry in a few minutes and read `complete`. ## `503 CHAIN_NOT_ENABLED` on `/smart-money/top` [Section titled “503 CHAIN\_NOT\_ENABLED on /smart-money/top”](#503-chain_not_enabled-on-smart-moneytop) The board is not published for that chain on this deployment, or `source=onchain` was omitted on 5042 / 4663. ## `429` on a page that “only reads” [Section titled “429 on a page that “only reads””](#429-on-a-page-that-only-reads) Logos, token reads and the default bucket are separate. A list page that paints hundreds of logos uses the logo bucket (3,000 a minute); table reads use the data bucket (300); `/arc/*` and `/lp/*` use the default (60). If you serve many users from one server IP, use a key so the limit is yours. ## Numbers differ from another explorer [Section titled “Numbers differ from another explorer”](#numbers-differ-from-another-explorer) Chord counts every swap with no dust floor, attributes wallets through routers and executors, flags wash volume instead of summing it, and prices a token on its dominant venue. Read [Data freshness and honesty](/docs/concepts/data-freshness/) before comparing. ## WebSocket disconnects after \~100 s behind a proxy [Section titled “WebSocket disconnects after \~100 s behind a proxy”](#websocket-disconnects-after-100-s-behind-a-proxy) The server pings every 25 s; make sure your proxy passes WebSocket frames and does not idle-close at a lower interval. Reconnect with jittered backoff and re-subscribe — the server keeps no state for a closed socket. ## Still stuck [Section titled “Still stuck”](#still-stuck) `GET /v1/health` for the service, `/v1/arc/status` · `/v1/rh/status` · `/v1/lp/status` for the lanes. Then the Chord developer page has the contact. # Venue ids > The dex ids that appear in routePlan, byDex, pools and venue tables, with display names. Every `dex` field — in a quote’s `routePlan`, a token’s `byDex`, a pool row, a venue table — is a stable id string set by the engine and the indexer. Map it to a name for display. ## Arc (5042) [Section titled “Arc (5042)”](#arc-5042) | id | Display name | Note | | ----------------- | ---------------- | -------------------------------------------- | | `uniswap_v4` | Uniswap V4 | includes hooked launchpad pools | | `uniswap_v3` | Uniswap V3 | | | `uniswap_v2` | Uniswap V2 | | | `pools_trade` | Pools.trade | V4 pools created by the Pools.trade launcher | | `synthra_v3` | Synthra | | | `sushi_v3` | SushiSwap V3 | | | `sushi_v2` | SushiSwap V2 | | | `dyorswap` | DYORSwap | | | `slipstream_fork` | Aero | an Aerodrome Slipstream fork | | `v3fork_<8hex>` | V3 fork `<8hex>` | unnamed V3 factory, keyed by its first 8 hex | | `v2fork_<8hex>` | V2 fork `<8hex>` | unnamed V2 factory | ## Robinhood Chain (4663) [Section titled “Robinhood Chain (4663)”](#robinhood-chain-4663) | id | Display name | | --------------- | ------------------ | | `uniswap_v3` | Uniswap V3 | | `uniswap_v4` | Uniswap V4 | | `uniswap_v2` | Uniswap V2 | | `giga_v3` | GIGA V3 | | `swaphood_v3` | SwapHood V3 | | `pancake_v3` | PancakeSwap V3 | | `up_v3` | up v3 | | `metric` | Metric OMM | | `nadfun_dex` | nad.fun DEX | | `pons_v2_curve` | Pons bonding curve | ## Monad (143) [Section titled “Monad (143)”](#monad-143) | id | Display name | | ---------------------------- | ---------------- | | `uniswap_v4` | Uniswap V4 | | `uniswap_v3` | Uniswap V3 | | `pancake_v3` | PancakeSwap V3 | | `capricorn` | Capricorn V3 | | `atlantis` | Atlantis | | `lfj` | LFJ (Trader Joe) | | `lfj_poe` | LFJ POE | | `kuru` | Kuru | | `hanji` | Hanji | | `metric` | Metric | | `woofi` | WOOFi | | `balancer_v3` | Balancer V3 | | `curve` | Curve | | `mento` | Mento | | `erc4626` | Vault deposit | | `nadfun_bc` · `nadfun_bc_v2` | Nad.fun | | `nadfun_dex` | Nad.fun DEX | ## Avalanche (43114) [Section titled “Avalanche (43114)”](#avalanche-43114) | id | Display name | | --------------------------- | ------------------ | | `pharaoh_v3` | Pharaoh V3 | | `pharaoh_dlmm` | Pharaoh DLMM | | `uniswap_v3` | Uniswap V3 | | `uniswap_v4` | Uniswap V4 | | `blackhole_v3` | Blackhole CL | | `blackhole_v2` | Blackhole | | `lfj_lb_v22` · `lfj_lb_v21` | LFJ Liquidity Book | | `lfj_v1` | LFJ V1 | | `pangolin_v3` | Pangolin V3 | | `pangolin_v2` | Pangolin V2 | ## Base (8453) [Section titled “Base (8453)”](#base-8453) | id | Display name | | ---------------------------------------------------------------------------- | ---------------------------------------- | | `aerodrome_slipstream` · `aerodrome_slipstream_2` · `aerodrome_slipstream_3` | Aerodrome Slipstream (three deployments) | | `aerodrome_v2` | Aerodrome V2 | | `uniswap_v3` | Uniswap V3 | | `uniswap_v4` | Uniswap V4 | | `uniswap_v2` | Uniswap V2 | | `pancake_v3` | PancakeSwap V3 | | `hydrex_integral` | Hydrex | | `quickswap_v4` | QuickSwap V4 | | `sushi_v3` | SushiSwap V3 | ## BNB Chain (56) [Section titled “BNB Chain (56)”](#bnb-chain-56) | id | Display name | | --------------------- | -------------------- | | `pancake_v3` | PancakeSwap V3 | | `pancake_infinity_cl` | PancakeSwap Infinity | | `pancake_v2` | PancakeSwap V2 | | `uniswap_v4` | Uniswap V4 | | `uniswap_v3` | Uniswap V3 | | `topaz` | Topaz | | `thena_v3` | THENA V3 | | `flap` | Flap | | `fstswap` | FstSwap | ## Arbitrum (42161) [Section titled “Arbitrum (42161)”](#arbitrum-42161) | id | Display name | | ------------ | -------------- | | `uniswap_v3` | Uniswap V3 | | `uniswap_v4` | Uniswap V4 | | `uniswap_v2` | Uniswap V2 | | `pancake_v3` | PancakeSwap V3 | | `pancake_v2` | PancakeSwap V2 | | `camelot_v3` | Camelot V3 | | `camelot_v2` | Camelot V2 | | `sushi_v3` | SushiSwap V3 | | `sushi_v2` | SushiSwap V2 | | `ramses_v2` | Ramses V2 | ## Ethereum (1) [Section titled “Ethereum (1)”](#ethereum-1) | id | Display name | | --------------- | -------------- | | `uniswap_v3` | Uniswap V3 | | `uniswap_v4` | Uniswap V4 | | `uniswap_v2` | Uniswap V2 | | `pancake_v3` | PancakeSwap V3 | | `pancake_v2` | PancakeSwap V2 | | `sushi_v3` | SushiSwap V3 | | `sushi_v2` | SushiSwap V2 | | `ring_v2` | Ring | | `supernova_cl` | Supernova CL | | `supernova_amm` | Supernova AMM | | `shibaswap` | ShibaSwap | | `defi_swap` | DefiSwap | | `fraxswap` | Fraxswap | ## Solana [Section titled “Solana”](#solana) | id | Display name | | ------------------- | ------------------------------ | | `pumpswap` | PumpSwap | | `pumpfun` | pump.fun (bonding curve) | | `meteora_dbc` | Meteora DBC | | `meteora_damm_v2` | Meteora DAMM v2 | | `meteora_dlmm` | Meteora DLMM | | `meteora_pools` | Meteora pools (dynamic AMM v1) | | `raydium_clmm` | Raydium CLMM | | `raydium_cpmm` | Raydium CPMM | | `raydium_v4` | Raydium AMM v4 | | `raydium_launchlab` | Raydium LaunchLab | | `orca` | Orca Whirlpool | The live lists with volume and share: `GET /v1/arc/venues`, `GET /v1/rh/venues`, `GET /v1/chains/{avalanche,base,bnb,arbitrum,ethereum}/venues` and `venues` on `GET /v1/chains/solana/overview`. Monad has no venue table; a quote’s `routePlan` names its venues. An id you do not recognise is a fork the index labelled by factory; show the id.