Skip to main content

Stream Quotes

WS /api/v1/stream is a WebSocket endpoint that pushes live swap quotes. Subscribe to one or more token pairs and the server sends an updated quote whenever the on-chain price for that pair materially changes — no polling required.
wss://api.vulcx.xyz/api/v1/stream?key=vulcx_your_key_here
The transport is raw JSON over WebSocket (plain text frames — not socket.io or STOMP). Open a standard WebSocket connection, then exchange the JSON messages described below.
Use streaming when you need a continuously up-to-date price (e.g. a swap UI showing a live rate). For one-off quotes, GET /api/v1/quote is simpler.

Connecting

This endpoint requires an API key like every other endpoint (see Authentication) — but since browsers can’t set custom headers on a WebSocket handshake, the key must be passed as a ?key= query parameter, not an Authorization header. A handshake without a valid key is rejected before the upgrade completes. The same per-plan rate limits as the REST endpoints apply to the upgrade request (see Rate Limits); once upgraded, the connection is long-lived and is not subject to the per-request rate limiter.

Client messages

Send a JSON text frame with an op and a pairs array.
op
string
required
Operation to perform: subscribe or unsubscribe.
pairs
object[]
required
One or more pair specifications to subscribe or unsubscribe.
A subscription is keyed by the full (in, out, amount, exactIn) tuple — two subscriptions that differ only in amount are distinct streams.

Subscribe

{
  "op": "subscribe",
  "pairs": [
    {
      "in": "So11111111111111111111111111111111111111112",
      "out": "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
      "amount": "50000000",
      "exactIn": true
    }
  ]
}
On subscribe, the server sends an immediate first quote for each newly accepted pair (so you don’t wait for the next price change), followed by a subscribed ack. The first quote may arrive just before the ack.

Unsubscribe

{
  "op": "unsubscribe",
  "pairs": [
    {
      "in": "So11111111111111111111111111111111111111112",
      "out": "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
      "amount": "50000000",
      "exactIn": true
    }
  ]
}

Server messages

Quote push

Sent for the immediate first quote and again only when the quote materially changes (a change in amountOut, priceImpactBps, or hops). Identical re-quotes are suppressed.
type
string
Always "quote".
in
string
Input token mint.
out
string
Output token mint.
amount
string
The subscribed amount, in smallest units.
amountOut
string
Estimated output amount in smallest units (ExactIn) — the live quote.
priceImpactBps
integer
Price impact in basis points.
hops
integer
Number of hops in the route. 1 = direct, 2+ = multi-hop.
slot
integer
The Fogo slot the quote was computed at.

Acknowledgement

Sent in response to a subscribe / unsubscribe, or to report a problem with a message.
type
string
"subscribed", "unsubscribed", or "error".
message
string
Present on errors — e.g. "invalid json", "unknown op".
count
integer
Number of pairs accepted by a subscribe/unsubscribe. Invalid or duplicate pairs are skipped and not counted.

Examples

{
  "type": "quote",
  "in": "So11111111111111111111111111111111111111112",
  "out": "uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG",
  "amount": "50000000",
  "amountOut": "452",
  "priceImpactBps": 0,
  "hops": 1,
  "slot": 587964937
}
{ "type": "subscribed", "count": 1 }
{ "type": "error", "message": "unknown op" }

Limits & behavior

BehaviorValue
Max subscriptions per connection256
Push policyOnly when the quote materially changes (amountOut / priceImpactBps / hops)
Update coalescingBursts of pool changes are debounced into a single recompute (~50 ms)
First quoteSent immediately on subscribe
BackpressureA connection whose outbound queue overflows (slow reader) is dropped — reconnect and resubscribe
If your client can’t keep up with the push rate, the server drops the connection rather than buffering unboundedly. Read frames promptly, and on an unexpected close, reconnect and re-send your subscriptions.
Last modified on July 5, 2026