Solana Firehose (WebSocket) — /ws/sol-stream

The Solana Firehose: one WebSocket, wss://triport.io/ws/sol-stream, that pushes a fixed feed of Solana non-vote transactions as compact JSON frames — slot, signature and fee — plus a once-per-second stats frame. The server applies no per-client filter.

Network
Solana
Scope
— (gated by tier, not scope)
Auth
x-token: $TRIPORT_API_KEY on upgrade (Authorization: Bearer also accepted), or ?api-key= query param
Rate limit
Pro tier and above; no per-key connection cap, and Firehose connections do not count toward the gRPC (Yellowstone) stream limit; not RPS-limited

Endpoint and plans: Solana RPC endpoint.

This is the Solana Firehose (WebSocket): every non-vote transaction, one fixed feed, no filters. Plans and when to pick it over gRPC are on the product page: Firehose plans and use cases. If you need filters, use gRPC (Yellowstone) at https://grpc.triport.io — a native gRPC endpoint with server-side filters, not a WebSocket.

/ws/sol-stream is a push-only fan-out. Triport holds one upstream Yellowstone subscription for non-vote transactions and forwards every transaction it receives to every connected client, in the same compact frame format. There is no subscribe step and no filter: all clients receive the same feed.

Measured 2026-09-22: a client that sent a SubscribeRequest for slots was answered with a transaction frame ("t":"tx"), not a slot update. The server reads client messages only to notice that the connection closed; their content is ignored.

Use this channel when you want the whole non-vote transaction flow as a signal — for example, to count or sample activity, or to trigger your own reads. To follow specific accounts, programs or slots, use the JSON-RPC pub/sub channel /ws/sol (accountSubscribe, logsSubscribe, slotSubscribe, …) or gRPC (Yellowstone) at https://grpc.triport.io, where the filter you send is applied.

Parameters

There are no subscription parameters. The only inputs are the API key (header or ?api-key=) on the upgrade request.

Response

Every frame is a JSON object with a t field naming its kind.

A transaction frame:

A stats frame (once per second; the values here are illustrative):

{ "t": "stats", "urps": 3120, "brps": 3118, "drop": 0.1, "cc": 42 }
tstring
tx or stats.
linteger
Slot of the transaction.
sstring
Transaction signature, base58.
finteger
Fee in lamports; omitted when zero or unknown.
eboolean
Present and true only for a failed transaction; omitted otherwise.
urpsnumber
Transactions received from upstream in the last second. On tx frames it is always 0.
brpsnumber
Frames broadcast in the last second. On tx frames it is always 0.
dropnumber
Share of frames dropped for slow clients in the last second, percent. On tx frames it is always 0.
ccinteger
Clients connected to the hub. On tx frames it is always 0.

Source, proto & delivery semantics

PropertyValue
UpstreamA Yellowstone subscription for non-vote transactions held by Triport, requesting transactions with vote: false and failed: false; the hub can switch between configured sources
Client filtersNot applied. Client messages are read only to detect a close; a message larger than 1 KiB closes the connection
Framestx (one per transaction) and stats (once per second) — see Response
CommitmentNot selectable by the client
DeliveryAt-most-once push — no replay or backfill of transactions produced before you connected
BackpressureEach client has a bounded buffer; when it is full, frames for that client are dropped, not queued (the hub-wide drop share is in the stats frame)
KeepaliveThe server sends a WebSocket ping every 30 s; standard clients answer with a pong automatically

There is no cursor or historical replay on this channel. To fill a gap, fetch the missed range over JSON-RPC (e.g. getBlock / getSignaturesForAddress).

Keepalive

Nothing to send. The server pings every 30 seconds and extends the read deadline on each pong; WebSocket libraries answer pings automatically.

Errors

WhenWhat you get
No key or an unknown keyHTTP 401 on the upgrade request; no WebSocket is opened.
Key below proThe upgrade succeeds, then one text frame with the error envelope and a close with code 4003.
Trial or subscription expiredThe upgrade succeeds, then an error frame and a close with code 4030.

Example frame before a 4003 close:

{
  "error": "tier_insufficient",
  "message": "…",
  "current_tier": "free",
  "required_tier": "pro",
  "method": "/ws/sol-stream",
  "category": "sol_yellowstone",
  "upgrade_url": "…"
}

See the shared errors page for the full WSErrorFrame envelope and SDK error-class mapping.

Examples

JavaScript (ws)

import WebSocket from "ws";


const ws = new WebSocket("wss://triport.io/ws/sol-stream", {
  headers: { Authorization: `Bearer ${process.env.TRIPORT_API_KEY}` },
});


ws.on("message", (raw) => {
  const f = JSON.parse(raw);
  if (f.t === "tx") console.log("tx", f.s, "@ slot", f.l, "fee", f.f ?? 0);
  else if (f.t === "stats") console.log("upstream tx/s", f.urps, "dropped %", f.drop);
});

Notes

  • One feed for everyone. The server does not apply per-client filters on this channel; filter on your side, or use /ws/sol or Yellowstone gRPC when the filter must run server-side.
  • Not RPS-limited. The channel is gated by tier (pro and above); there is no per-message RPS bucket and no daily quota.
  • Pick the right channel. For Ethereum/Polygon streams see /ws/eth and /ws/poly. For account-change notifications, use accountSubscribe on /ws/sol.