Skip to content

Streaming

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

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.

{ "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.

{ "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.
{ "op": "unsub", "channel": "candles", "token": "0x171a…", "tf": "1m" }
{ "op": "unsub", "channel": "prices", "chain": 5042 }
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.

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
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.

  • 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.