WebSocket
Stream decoded blocks, DEX swaps, and token transfers over a single persistent connection. Path-based subscription, server-side filters, replay on reconnect, and per-message billing.
What you get
- Solana DEX swaps —
solana@swaps. Raydium, Orca, Meteora, Pump.fun and more, normalized per trade. - Solana transfers —
solana@spl_transfer,solana@system_transfer. SPL, SPL-2022, and native SOL. - EVM DEX swaps —
mainnet@swaps,base@swaps, and 6 more EVM chains. - EVM ERC-20 transfers —
mainnet@erc20_transfers, plus the same 8 EVM networks.
Live catalog at ws.pinax.network/streams. Supported networks at api.pinax.network/v1/networks.
Subscription URL
Channels are encoded in the URL path — no JSON-RPC subscribe message needed.
wss://ws.pinax.network/ws/<network>@<table>?token=<API_KEY>
Single channel, raw payload:
wss://ws.pinax.network/ws/solana@swaps?token=$PINAX_KEY
Multi-channel (wrapped envelope — { "stream": "<id>", "data": <raw> }):
wss://ws.pinax.network/ws/solana@swaps/mainnet@erc20_transfers?token=$PINAX_KEY
Wildcards work on either side — *@swaps, solana@*. Bare /ws is HTTP 400; use /ws/*@* to opt into everything.
Messages vs events — billing
Two counters matter, and they are not the same number:
- Messages — one WebSocket frame per
(network, table)per block. This is the billable unit. - Events — items inside each message's
events[]array. A single message can carry dozens of swaps or transfers.
Pricing is $0.00005 per message (= $0.50 per 10K). A package that emits two tables produces two messages per block — one per table — regardless of how many events each contains. Use server-side SET_FILTER to reduce billable messages further; heartbeats and protocol frames are free.
Sample envelope (Solana swaps):
{
"network": "solana",
"table": "swaps",
"block_num": 422102644,
"block_hash": "6AEzeSFDZstnhagF1D2FsCPNVELz1YBTvHFMHDSNP4fs",
"timestamp": "2026-05-25T16:20:05Z",
"timestamp_seconds": 1779726005,
"module_hash": "411d6a46…b295",
"events": [
{ "protocol": "pumpfun_amm", "user": "B6r52E…YUbC", ... },
{ "protocol": "raydium_clmm", "user": "9KaPDQ…X4tN", ... }
]
}Authentication
Every connection needs your API key. Two equivalent options:
- Header (server libs):
Authorization: Bearer <jwt> - Query param (browsers — can't set headers on the WS upgrade):
?token=<jwt>
Same JWT as the rest of Pinax — RPC, Firehose, Token API. Quota is shared.
Reconnects & replay
The server retains a 600s window per package on disk. On reconnect, pass ?from_timestamp=<n> (epoch seconds or ISO-8601). Every retained block with block_num > n is replayed oldest-first before the live stream resumes.
wss://ws.pinax.network/ws/solana@swaps?from_timestamp=1715619600 wss://ws.pinax.network/ws/solana@swaps?from_timestamp=2026-05-25T16:00:00Z
If n falls below the oldest retained block, a gap lifecycle message fires — backfill via Substreams gRPC with an explicit start_block. Wildcards skip replay.
Server-side filtering
Drop non-matching events before they hit the wire — reduces billable messages, not just bandwidth. String equality only; fields AND; values OR; missing field counts as a miss.
{ "method": "SET_FILTER",
"params": { "selector": "solana@swaps",
"filter": { "protocol": ["pumpfun_amm", "raydium_clmm"] } },
"id": 1 }Per-selector. Wildcards always pass through. Max 16 keys, 64 values per filter. Top-level fields (block_num, network) are not filterable — only keys inside events[*].
Use cases
Push DEX swaps and ERC-20 / SPL transfers into a UI the moment they confirm. One socket per network@table — no polling, no per-block REST fan-out.
Apply server-side SET_FILTER rules to drop non-matching events on the wire. Trigger Discord, Slack, or webhook notifications only on the trades you actually care about.
undo lifecycle events surface chain reorganizations explicitly. Roll back materialized state past last_valid_block instead of rebuilding from scratch.
Stream pre-parsed swaps into an agent loop with no schema work. Each message ships the protocol, the user, and the trade — ready to be summarized or acted on.
Frequently asked
module_hash in production and watch for stream lifecycle fatal messages.ping/pong frames are protocol-level and free. The server pings every 180s; clients that don't pong within 600s are closed.decimals) to scale.start_block, or query Token API for indexed history.Related
- WebSocket reference — full endpoint, message, and command catalog.
- Token API guide — historical equivalents for the same data.
- Product page — pricing, calculator, live demo.