tokens:live

A single stream of token lifecycle events across every mint. Subscribe once, then dispatch on each message's type field.

WStokens:live lifecycle events for every token

Event types

typeWhenData
token_createdToken is deployed on chain.{mint, symbol, name, deployed_at, launchpad, image_uri}
token_graduatedMigrates to Raydium/PumpSwap.{mint, symbol, name, migrated_at, mcap}
token_dex_paidDexScreener paid order confirmed.{mint, symbol, name, dex_paid_at}
token_metadata_retrievedIPFS/Arweave metadata merged.{mint, symbol, name, image_uri, description, twitter, telegram, website}
token_duplication_status_updatedAny duplication flag flipped.{mint, symbol, name, duplication: { ... }}

Wire frame

[null,null,"tokens:live","token_event",{
  "type": "token_graduated",
  "data": {
    "mint":         "BgNrWZK...",
    "symbol":       "SMP",
    "name":         "Sample Token",
    "migrated_at": "2026-07-11T13:00:00Z",
    "mcap":        42000
  }
}]

Connect (terminal)

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"

Requires websocat. The block sends the join frame + a heartbeat every 25s so Phoenix doesn't drop the connection.

Connect (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);
});

Connect (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())

Wire protocol details on the frames:live page (join / reply / heartbeat frames are identical across channels).

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

Ready to build? Mint an API key.