Skip to content
New Listings Feed
v2 WebSocketCode examples

Code examples

v2 clients with retry handling in Node.js and Python.

Choose a client below. Both clients handle control messages and reconnect after transient failures. Set NLF_KEY in your environment before running them. The examples use the FREE host; for STARTER or PRO, use a regional host.

Save as client.cjs. This example uses ws 8.21.3.

// npm install [email protected]
const WebSocket = require("ws");

const url = "wss://ws.newlistings.pro/v2/full";
const key = process.env.NLF_KEY;
if (!key) throw new Error("Set NLF_KEY before starting the client.");
let retryMs = 1000;

function readJson(raw) {
  try { return JSON.parse(raw.toString()); } catch { return null; }
}

function retryAfterMs(value = "") {
  if (/^\d+$/.test(value)) return Number(value) * 1000;
  return Math.max(0, Date.parse(value) - Date.now()) || 0;
}

function receiveSession() {
  return new Promise((resolve) => {
    let stop = false;
    let minimumWaitMs = 0;
    let rejectedUpgrade = false;
    const ws = new WebSocket(url, {
      headers: { authorization: `Bearer ${key}` },
      handshakeTimeout: 10000,
    });

    ws.on("unexpected-response", (_request, response) => {
      rejectedUpgrade = true;
      const status = response.statusCode;
      minimumWaitMs = retryAfterMs(response.headers["retry-after"]);
      stop = status < 500 && status !== 408 && status !== 429;
      let body = "";
      response.setEncoding("utf8");
      response.on("data", (chunk) => { body += chunk.slice(0, 65536 - body.length); });
      response.on("end", () => {
        const message = readJson(body);
        console.error("upgrade rejected", status, message?.code);
        if (["AUTHENTICATION_FAILED", "KEY_EXPIRED", "INVALID_REQUEST"]
            .includes(message?.code)) stop = true;
        ws.terminate();
      });
      response.on("error", () => ws.terminate());
      response.once("close", () => ws.terminate());
      response.setTimeout(10000, () => response.destroy());
    });

    ws.on("message", (data) => {
      const message = readJson(data);
      if (!message || typeof message !== "object") {
        console.error("Invalid JSON message; inspect the response before retrying.");
        stop = true;
        ws.close();
      } else if (message.type === "success" && message.code === "READY") {
        retryMs = 1000;
        console.log("ready", message.subscription);
      } else if (message.type === "error") {
        console.error(message.code, message.message);
        stop = message.code !== "SERVER_UNAVAILABLE";
        ws.close();
      } else if (["announcement", "tweet"].includes(message.type)) {
        console.log(message);
      }
    });

    ws.on("error", (error) => {
      if (!rejectedUpgrade) console.error(error.message);
    });
    // Only close completes a session. Errors never schedule a second retry.
    ws.once("close", (code) => resolve({ stop: stop || code === 1008, minimumWaitMs }));
  });
}

async function connect() {
  while (true) {
    const result = await receiveSession();
    if (result.stop) {
      console.error("Stopped. Check the request, key, and connection limits.");
      return;
    }
    const waitMs = Math.max(retryMs, result.minimumWaitMs) + Math.random() * 250;
    console.log("retry in", Math.ceil(waitMs), "ms");
    await new Promise((resolve) => setTimeout(resolve, waitMs));
    retryMs = Math.min(retryMs * 2, 30000);
  }
}

connect().catch(console.error);

The clients honor Retry-After and reset backoff after READY. Invalid requests, rejected credentials, policy closes, and connection limits stop the client for correction. See Connection lifecycle for retry rules. Keep event processing brief so it does not delay later messages.

wscat

wscat -H "authorization: Bearer YOUR_KEY" \
  -c wss://ws.newlistings.pro/v2/full

For raw events, use /v2/fast on a regional host with a STARTER or PRO key.

Filters belong in the connection URL:

const url = "wss://ws.newlistings.pro/v2/full?exchange=upbit&data_type=announcement&market_type=spot";

See /v2/full and /v2/fast for the endpoint-specific filters.

Full history

STARTER and PRO keys can use the Historical API over HTTPS using the same bearer key:

curl -H "authorization: Bearer YOUR_KEY" \
  "https://tokyo.newlistings.pro/v2/full?limit=50"

These clients resume live events after reconnecting. They do not fetch history automatically.