frames:live

Every enriched trade, streamed as soon as we finish classifying it. One message per Solana {"{signature, mint}"} unit, so multi-hop swaps and arbitrage fills arrive grouped together.

WSframes:live enriched trades, tx-atomic

Wire frame

[null,null,"frames:live","frame",{
  "type": "frame",
  "data": {
    "signature": "5xyz...",
    "mint":      "BgNrWZK...",
    "slot":       12345,
    "timestamp": "2026-07-11T13:00:00Z",
    "trades": [
      { /* same shape as /v1/tokens/:mint/trades entries */ }
    ]
  }
}]

Each frame's trades[] has the same shape as /v1/tokens/:mint/trades entries. Customers wanting per-trade emit can flatten client-side.

Frames with no trades

Metadata-only txs, migration events, and mayhem-mode flips are not broadcast here (empty trades[] arrays would just be noise). Subscribe to the corresponding tokens:live event instead.

Connect frame

Same Phoenix v2 wire format as tokens:live. Send a join, wait for reply, send heartbeats every 25s:

// → join
["1","1","tokens:live","phx_join",{}]

// ← reply
["1","1","tokens:live","phx_reply",{"response":{},"status":"ok"}]

To subscribe to frames:live, replace tokens:live in the join frame with frames:live.

Full example (websocat)

export API_KEY=sk_live_yourkeyhere

{
  printf '["1","1","tokens:live","phx_join",{}]\n'
  n=2
  while sleep 25; do
    printf '[null,"%s","phoenix","heartbeat",{}]\n' "$n"
    n=$((n+1))
  done
} | websocat "wss://api.cookin.fun/socket/websocket?vsn=2.0.0&api_key=$API_KEY"

Full example (Node.js)

const WebSocket = require("ws");

const API_KEY = process.env.API_KEY;
const url = `wss://api.cookin.fun/socket/websocket?vsn=2.0.0&api_key=${API_KEY}`;
const ws  = new WebSocket(url);

ws.on("open", () => {
  // Join tokens:live (ref="1", join_ref="1").
  ws.send(JSON.stringify(["1", "1", "tokens:live", "phx_join", {}]));

  // Heartbeat every 25s so Phoenix doesn't drop us.
  let n = 2;
  setInterval(() => {
    ws.send(JSON.stringify([null, String(n++), "phoenix", "heartbeat", {}]));
  }, 25_000);
});

ws.on("message", (buf) => {
  const [joinRef, ref, topic, event, payload] = JSON.parse(buf);
  if (event === "token_event")  console.log("token:", payload.type, payload.data);
  if (event === "frame")        console.log("frame:", payload.data.signature);
});

Full example (Python)

import asyncio, json, os, websockets

API_KEY = os.environ["API_KEY"]
URL = f"wss://api.cookin.fun/socket/websocket?vsn=2.0.0&api_key={API_KEY}"

async def run():
    async with websockets.connect(URL) as ws:
        # Join tokens:live.
        await ws.send(json.dumps(["1", "1", "tokens:live", "phx_join", {}]))

        # Heartbeat every 25s so Phoenix doesn't drop us.
        async def heartbeat():
            n = 2
            while True:
                await asyncio.sleep(25)
                await ws.send(json.dumps([None, str(n), "phoenix", "heartbeat", {}]))
                n += 1

        asyncio.create_task(heartbeat())

        async for msg in ws:
            _joinRef, _ref, _topic, event, payload = json.loads(msg)
            if event == "token_event":
                print("token:", payload["type"], payload["data"])
            elif event == "frame":
                print("frame:", payload["data"]["signature"])

asyncio.run(run())

Bug or unclear docs? Include the request_id from the response envelope when reporting.

Ready to build? Mint an API key.