Aurelia

Live new token launches over WebSocket

The pulse channel: a Pulse list, the whole list first, then only the rows that changed.

Subscribe to pulse with view and any of Pulse's filters, sort, order, limit and offset, as parameters of the message. They are checked as REST checks them: a bad one is 400 with the same error text.

Subscribe:

{"op":"subscribe","id":"g","channel":"pulse","chain":"solana","view":"graduating","progress":"0.5..","limit":20}
typeWhendata
subscribedOnce, firstEchoes view, sort, order, limit, offset
pulseRight after, with the whole list; then after each rebuild that changed the list or a listed tokenview, total, updatedAt, order, tokens
  • order is the whole list, as addresses in order. It is authoritative: render it.
  • tokens carries only the rows that are new or changed since the previous message. The first message, and the first after resubscribed, carries every row.
  • Keep a map from address to row, apply tokens to it, and render order. A token missing from order has left the list: filters are checked again at every rebuild.

Captured on a test instance:

{"type":"subscribed","id":"u1","channel":"pulse","chain":"evm:56","view":"new","sort":"createdAt","order":"desc","limit":1,"offset":0}
{
  "id": "u1",
  "type": "pulse",
  "data": {
    "view": "new",
    "total": 2,
    "updatedAt": 1790618622692,
    "order": [
      "0x5eed00000000000000000000000000000000c444"
    ],
    "tokens": [
      {
        "address": "0x5eed00000000000000000000000000000000c444",
        "symbol": "NEWT3",
        "name": "Newt Three",
        "logo": "http://localhost:7170/logos/evm:56/0x5eed00000000000000000000000000000000c444?v=cccccccccccc",
        "launchpad": "fourmeme",
        "pool": "0xed80c90b543397140863599d535a4427ed378a30e094a01a025bea52acb9fcc7",
        "createdAt": 1790548061920,
        "creator": "0x0f325bd174c70440fa62c31dce9f69d54baf717e",
        "socials": {
          "website": null,
          "twitter": null,
          "telegram": null,
          "discord": null,
          "others": {}
        },
        "priceUsd": 0.000015000000000000002,
        "marketCapUsd": 15000.000000000002,
        "liquidityUsd": null,
        "progress": 0.18,
        "graduatedAt": null,
        "latestTradeAt": 1790548064920,
        "creatorNetShare": 0,
        "sniperCount": 2,
        "sniperNetShare": 0.022,
        "windows": {
          "5m": {
            "priceChange": 0,
            "volumeUsd": 0,
            "buyVolumeUsd": 0,
            "sellVolumeUsd": 0,
            "trades": 0,
            "buys": 0,
            "sells": 0,
            "traders": 0,
            "buyers": 0,
            "sellers": 0,
            "feesPaidUsd": null
          },
          "1h": {
            "priceChange": 0,
            "volumeUsd": 0,
            "buyVolumeUsd": 0,
            "sellVolumeUsd": 0,
            "trades": 0,
            "buys": 0,
            "sells": 0,
            "traders": 0,
            "buyers": 0,
            "sellers": 0,
            "feesPaidUsd": null
          },
          "6h": {
            "priceChange": 0,
            "volumeUsd": 0,
            "buyVolumeUsd": 0,
            "sellVolumeUsd": 0,
            "trades": 0,
            "buys": 0,
            "sells": 0,
            "traders": 0,
            "buyers": 0,
            "sellers": 0,
            "feesPaidUsd": null
          },
          "24h": {
            "priceChange": null,
            "volumeUsd": 330,
            "buyVolumeUsd": 330,
            "sellVolumeUsd": 0,
            "trades": 2,
            "buys": 2,
            "sells": 0,
            "traders": 2,
            "buyers": 2,
            "sellers": 0,
            "feesPaidUsd": null
          }
        }
      }
    ]
  }
}

Client:

// Follow a Pulse list: keep rows by address, apply each message's tokens, render its order.
// Bun, Node 22+ or a browser. Reconnects with backoff; a refused key is not retried.
const subscribe = {
  op: "subscribe", id: "new", channel: "pulse", chain: "solana", view: "new",
  launchpad: "pumpfun", marketCapUsd: "5000..", limit: 20,
};
const rows = new Map(); // address → token

function render(order) {
  const lines = order.map((address) => {
    const t = rows.get(address);
    const cap = t.marketCapUsd === null ? "-" : `$${Math.round(t.marketCapUsd)}`;
    const progress = t.progress === null ? "" : ` ${Math.round(t.progress * 100)}%`;
    return `${t.symbol ?? address.slice(0, 6)} ${cap}${progress}`;
  });
  console.log(lines.join("\n"), "\n");
}

let delay = 1000;
function connect() {
  const ws = new WebSocket("wss://app.aurelia.build/api/live");
  ws.onopen = () => ws.send(JSON.stringify(subscribe));
  ws.onmessage = (e) => {
    const msg = JSON.parse(e.data);
    if (msg.type === "subscribed") delay = 1000;
    if (msg.type === "error") return console.error(msg.status, msg.error); // fix the filters
    if (msg.type !== "pulse") return;
    for (const t of msg.data.tokens) rows.set(t.address, t);
    const listed = new Set(msg.data.order);
    for (const address of rows.keys()) if (!listed.has(address)) rows.delete(address); // left the list
    render(msg.data.order);
  };
  ws.onclose = (e) => {
    if (e.code === 4401) return console.error("refused:", e.reason);
    setTimeout(connect, delay);
    delay = Math.min(delay * 2, 30_000);
  };
}
connect();

Try it in the interactive docsCreate a free account