WebSocket Guide

Nodius provides a WebSocket proxy for real-time streaming of Solana data. Subscribe to account changes, transaction logs, slot updates, and more.

Connecting

WebSocket connections require authentication via a session token or API key.

Endpoint

wss://rpc.nodius.xyz/ws

Authentication

Three options are available:

Option 1: Authorization header (session token or API key)

GET /ws HTTP/1.1
Authorization: Bearer <session-token-or-api-key>
Upgrade: websocket
Connection: Upgrade

Option 2: X-Api-Key header (API key only)

GET /ws HTTP/1.1
X-Api-Key: srpc_live_<base64url>
Upgrade: websocket
Connection: Upgrade

Option 3: Sec-WebSocket-Protocol header (for browser clients that don't support custom headers)

Both auth.<token> and solana-rpc subprotocols must be sent together:

GET /ws HTTP/1.1
Sec-WebSocket-Protocol: auth.<token>, solana-rpc
Upgrade: websocket
Connection: Upgrade

The server responds with Sec-WebSocket-Protocol: solana-rpc โ€” the token is never echoed back for security.

Where <token> is either a session token (from the challenge/verify flow) or a persistent API key (from POST /account/api-key).

Obtain a Session Token

// Using the SDK
const rpc = new NodiusClient("https://rpc.nodius.xyz", {

  keypair,
  auth: "session",
});

const token = await rpc.getSessionToken();

Or manually via the challenge-response flow.

Connect

// Using Authorization header
const ws = new WebSocket("wss://rpc.nodius.xyz/ws", {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

// Or using Sec-WebSocket-Protocol (browser-friendly)
const ws = new WebSocket(
  "wss://rpc.nodius.xyz/ws",
  [`auth.${token}`]
);

ws.on("open", () => {
  console.log("Connected");
});

ws.on("message", (data) => {
  const msg = JSON.parse(data.toString());
  console.log(msg);
});

ws.on("close", (code, reason) => {
  console.log(`Disconnected: ${code} ${reason}`);
});

Connection Requirements

Subscriptions

Creating a Subscription

Send a JSON-RPC subscription request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "accountSubscribe",
  "params": [
    "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    {
      "encoding": "base64",
      "commitment": "confirmed"
    }
  ]
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": 42
}

The result is the subscription ID. Use it to unsubscribe later.

Cost: 5 credits per subscription created (WS_SUBSCRIBE).

Receiving Notifications

{
  "jsonrpc": "2.0",
  "method": "accountNotification",
  "params": {
    "subscription": 42,
    "result": {
      "context": {
        "slot": 285943216
      },
      "value": {
        "data": ["base64data...", "base64"],
        "executable": false,
        "lamports": 1000000000,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 400,
        "space": 200
      }
    }
  }
}

Cost: 1 credit per notification received (WS_NOTIFICATION).

Unsubscribing

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "accountUnsubscribe",
  "params": [42]
}

Response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": true
}

Unsubscribing does not refund the subscription cost but stops further notification charges.

Supported Subscription Methods

Subscribe Unsubscribe Description Access
accountSubscribe accountUnsubscribe Account data changes All
logsSubscribe logsUnsubscribe Transaction logs (all or by pubkey) All
programSubscribe programUnsubscribe All accounts owned by a program All
signatureSubscribe signatureUnsubscribe Transaction confirmation All
slotSubscribe slotUnsubscribe Slot number updates All
rootSubscribe rootUnsubscribe Finalized root slot All
blockSubscribe blockUnsubscribe Full block data streaming Credit-gated

accountSubscribe

Monitor changes to a specific account.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "accountSubscribe",
  "params": [
    "pubkeyBase58...",
    {"encoding": "base64", "commitment": "confirmed"}
  ]
}

logsSubscribe

Monitor transaction logs.

// All transactions
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logsSubscribe",
  "params": ["all", {"commitment": "confirmed"}]
}

// Transactions mentioning a specific pubkey
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logsSubscribe",
  "params": [
    {"mentions": ["pubkeyBase58..."]},
    {"commitment": "confirmed"}
  ]
}

programSubscribe

Monitor all accounts owned by a program.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "programSubscribe",
  "params": [
    "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    {"encoding": "base64", "commitment": "confirmed"}
  ]
}

Warning: programSubscribe on popular programs (Token Program, System Program) generates very high notification volume and will consume credits rapidly.

signatureSubscribe

Wait for a transaction to be confirmed.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "signatureSubscribe",
  "params": [
    "txSignatureBase58...",
    {"commitment": "confirmed"}
  ]
}

This subscription automatically unsubscribes after delivering one notification.

slotSubscribe / rootSubscribe

{"jsonrpc": "2.0", "id": 1, "method": "slotSubscribe"}
{"jsonrpc": "2.0", "id": 1, "method": "rootSubscribe"}

Note: slotSubscribe fires every ~400ms. At 1 credit per notification, this costs approximately 150 credits per minute.

Subscription Limits

WebSocket limits are per-account operational safety caps applied uniformly to all accounts.

Limit Default
Max concurrent connections per account 50
Max concurrent subscriptions per account 100

Attempting to create a subscription beyond the limit returns an error:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "Subscription limit reached (100/100)"
  }
}

Credit Metering

Event Credits
Creating a subscription 5
Each notification received 1
Unsubscribing 0 (free)
Connection/disconnection 0 (free)

Estimating Costs

Subscription Approx. Frequency Credits/Hour
slotSubscribe ~2.5/sec ~9,000
accountSubscribe (active account) varies varies
accountSubscribe (cold account) rare ~5 (subscription only)
signatureSubscribe 1 (then auto-unsub) ~6
logsSubscribe (all) very high 10,000+
programSubscribe (Token Program) extremely high 100,000+

Be mindful of high-frequency subscriptions. Monitor your credit balance.

Connection Lifecycle

1. Client connects with token (Authorization header or Sec-WebSocket-Protocol)
2. Server validates token and checks credit balance (โ‰ฅ100)
3. Connection established
4. Client sends subscribe/unsubscribe messages
5. Server streams notifications, deducting credits
6. If credits drop below 10:
   a. Server sends warning message
   b. Server closes connection (code 4002)
7. Client can reconnect after depositing more credits

Close Codes

Code Reason Description
1000 normal Clean disconnect by client
1008 policy_violation Invalid or expired token
4001 auth_failed Authentication failed
4002 insufficient_credits Credits below minimum
4003 rate_limited Too many messages

SDK WebSocket Usage

import { NodiusClient } from "@nodius/sdk";

const rpc = new NodiusClient("https://rpc.nodius.xyz", {

  keypair,
  auth: "session",
});

// Subscribe to account changes
const subId = await rpc.ws.accountSubscribe(
  "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
  { encoding: "base64", commitment: "confirmed" },
  (notification) => {
    console.log("Account changed:", notification);
  }
);

// Later: unsubscribe
await rpc.ws.accountUnsubscribe(subId);

// Subscribe to slot changes
await rpc.ws.slotSubscribe((slot) => {
  console.log("New slot:", slot);
});

// Clean disconnect
rpc.ws.close();

The SDK handles: - Automatic session token management and renewal - Reconnection with exponential backoff - Subscription restoration after reconnect - Credit balance monitoring

Best Practices

  1. Unsubscribe when done โ€” Don't rely on disconnection to clean up subscriptions. Unsubscribe explicitly.
  2. Monitor credit consumption โ€” High-frequency subscriptions (slots, logs, active programs) can drain credits quickly.
  3. Use commitment levels โ€” confirmed is a good default. finalized reduces notification frequency. processed increases it.
  4. Handle reconnections โ€” Network issues happen. Implement reconnection logic or use the SDK which handles this automatically.
  5. Avoid subscribing to the entire log stream โ€” logsSubscribe("all") generates enormous traffic. Filter by pubkey when possible.