Skip to main content

Stream Quotes

The Vulcx quote stream pushes a fresh quote whenever the price of a token pair changes, so your UI can show a live rate without polling. It’s a WebSocket endpoint that speaks plain JSON.
wss://api.vulcx.xyz/api/v1/stream?key=vulcx_your_key_here
Stream vs. poll. Use streaming for a continuously updating price (a swap form, a price ticker). For a single quote — for example, right before building a transaction — use GET /api/v1/quote. The streamed amountOut matches what /quote returns for the same pair and amount. For the full message schema, see the Stream Quotes API reference.
Like every endpoint except GET /health and GET /api/v1/tokens, this requires an API key. Browsers can’t set custom headers on a WebSocket handshake, so the key goes in the URL as ?key= — see Authentication.

How it works

  1. Open a WebSocket connection.
  2. Send a subscribe message listing the pairs you care about.
  3. Receive an immediate first quote for each pair, then a subscribed ack.
  4. Receive a new quote message whenever that pair’s price materially changes.
  5. Send unsubscribe to stop a stream, or close the socket to end them all.

Subscribe

Each pair is { in, out, amount, exactIn }:
in
string
required
Input token mint address (base58-encoded public key).
out
string
required
Output token mint address (base58-encoded public key).
amount
string
required
Amount in smallest token units, as a string. For FOGO (9 decimals): 1000000000 = 1 FOGO.
exactIn
boolean
required
true quotes amount as the exact input (ExactIn); false treats it as the exact desired output (ExactOut).

Handle messages

Two server message types arrive on the socket:
  • quote — a live quote: { type, in, out, amount, amountOut, priceImpactBps, hops, slot }.
  • subscribed / unsubscribed / error — acks. Errors include a message; subscribe/unsubscribe acks include a count of accepted pairs.
A quote is only re-sent when amountOut, priceImpactBps, or hops changes — so every message you receive is a genuine price update.

Examples

const ws = new WebSocket(`wss://api.vulcx.xyz/api/v1/stream?key=${VULCX_KEY}`);

ws.onopen = () => {
  ws.send(JSON.stringify({
    op: "subscribe",
    pairs: [
      {
        in: "So11111111111111111111111111111111111111112",
        out: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
        amount: "50000000",
        exactIn: true,
      },
    ],
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "quote") {
    console.log(`${msg.amount} in → ${msg.amountOut} out`
      + ` (${msg.hops} hop(s), impact ${msg.priceImpactBps} bps, slot ${msg.slot})`);
  } else {
    console.log("ack:", msg);
  }
};

ws.onclose = () => {
  // Reconnect and resubscribe on unexpected close.
};
import WebSocket from "ws";

const ws = new WebSocket(`wss://api.vulcx.xyz/api/v1/stream?key=${process.env.VULCX_KEY}`);

ws.on("open", () => {
  ws.send(JSON.stringify({
    op: "subscribe",
    pairs: [
      {
        in: "So11111111111111111111111111111111111111112",
        out: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
        amount: "50000000",
        exactIn: true,
      },
    ],
  }));
});

ws.on("message", (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.type === "quote") {
    console.log(`out=${msg.amountOut} hops=${msg.hops} slot=${msg.slot}`);
  } else {
    console.log("ack:", msg);
  }
});

Unsubscribe

Send the same pair with op: "unsubscribe" to stop receiving updates for it:
ws.send(JSON.stringify({
  op: "unsubscribe",
  pairs: [
    {
      in: "So11111111111111111111111111111111111111112",
      out: "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
      amount: "50000000",
      exactIn: true,
    },
  ],
}));
Closing the socket cancels all of a connection’s subscriptions.

Reconnection & limits

  • Reconnect on close. Subscriptions live with the connection. After an unexpected close, reopen the socket and re-send your subscribe messages.
  • Read promptly. A connection whose outbound queue overflows (a slow reader) is dropped rather than buffered. If this happens, reconnect and resubscribe.
  • Up to 256 subscriptions per connection. Spread more across multiple connections.
Last modified on July 5, 2026