Quickstart

Get from zero to your first RPC call in under 5 minutes. No signup, no subscription, no KYC.

Prerequisites

1. Install

npm install @nodiusxyz/sdk

Also available via:

npx @nodiusxyz/sdk        # run without installing
deno add @nodiusxyz/sdk   # Deno
bun add @nodiusxyz/sdk    # Bun
pip install nodiusxyz

No install needed โ€” just use curl, fetch, or urllib.

2. Get a Keypair

Already have a Solana wallet? Use its secret key (base58). Otherwise:

import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";

const kp = Keypair.generate();
const secretKeyBase58 = bs58.encode(kp.secretKey);
console.log("Pubkey:", kp.publicKey.toBase58());
console.log("Secret (base58):", secretKeyBase58);
// Save this base58 string โ€” you'll pass it as SECRET_KEY_BASE58
from nacl.signing import SigningKey
import base58

sk = SigningKey.generate()
pubkey = base58.b58encode(bytes(sk.verify_key)).decode()
secret = base58.b58encode(bytes(sk) + bytes(sk.verify_key)).decode()
print("Pubkey:", pubkey)
print("Secret (base58):", secret)

Store your secret key securely โ€” it's your identity and controls your credits. Both examples output a base58-encoded secret key.

3. Buy Credits

Send USDC (SPL token) on Solana mainnet to the deposit address, from the same wallet you generated above. Credits are attributed to the wallet that signed the transfer (the SPL token authority), not the transaction fee payer โ€” so the sending wallet must be the one you use for authentication.

Field Value
Token USDC (SPL)
Chain Solana mainnet
USDC mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
Deposit address CQKviPv5QupKhE6MuhSuqP4uh1JfrL93nxtcx23tLMRk
Minimum deposit $0.01 USDC (10,000 base units)

Credits appear within seconds of the deposit confirming on-chain (~30 seconds). The deposit address is static โ€” you can send USDC to it at any time.

โš ๏ธ Do not send SOL or any token other than USDC. Only SPL USDC transfers to the deposit address are credited. Sending other tokens will result in permanent loss of funds.

Canonical source: The deposit address above is for convenience. Always obtain and verify it programmatically via GET /account/info (returns deposit_address and funding fields) or the 402 Payment Required response data.deposit_address. Bots should fetch it at runtime โ€” do not hardcode it in application logic.

4. Make Your First Call

Billable RPC calls require a positive credit balance โ€” if you skipped step 3, you'll get 402 Payment Required. Both SDKs' call() method returns the JSON-RPC result field directly (unwrapped from the response envelope). For example, getBalance returns {"value": 12345, ...} โ€” not the full {"jsonrpc":"2.0","result":{...}} envelope.

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

const rpc = NodiusClient.fromSecretKey(
  "https://rpc.nodius.xyz",
  process.env.SECRET_KEY_BASE58!
);

const slot = await rpc.call("getSlot");
console.log("Slot:", slot);

const bal = await rpc.call("getBalance", [
  "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
]);
console.log("Balance:", bal.value, "lamports");
from nodiusxyz import NodiusClient

rpc = NodiusClient.from_base58(
    "https://rpc.nodius.xyz",
    secret_key="your_base58_secret_key",
)

slot = rpc.call("getSlot")
print("Slot:", slot)

bal = rpc.call("getBalance", ["vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg"])
print("Balance:", bal["value"], "lamports")
import time, hashlib, json, urllib.request, base58, os
from nacl.signing import SigningKey

SK = base58.b58decode("your_base58_secret_key")
key = SigningKey(SK[:32]) if len(SK) == 64 else SigningKey(SK)
pub = SK[32:] if len(SK) == 64 else bytes(key.verify_key)

body = json.dumps({"jsonrpc":"2.0","id":1,"method":"getSlot"}).encode()
ts = str(int(time.time()))
nonce = os.urandom(16).hex()
h = hashlib.sha256(body).hexdigest()
msg = f"solana-nodius:v2:POST:/:{ts}:{nonce}:{h}"
sig = key.sign(msg.encode()).signature

req = urllib.request.Request("https://rpc.nodius.xyz", data=body, headers={
    "Content-Type":"application/json",
    "X-Pubkey": base58.b58encode(pub).decode(),
    "X-Signature": base58.b58encode(sig).decode(),
    "X-Timestamp": ts, "X-Nonce": nonce,
})
with urllib.request.urlopen(req) as r:
    print("Credits:", r.headers.get("X-Credits-Remaining"))
    print("Slot:", json.loads(r.read())["result"])
const crypto = require("crypto");
const nacl = require("tweetnacl");
const bs58 = require("bs58");

const SK = bs58.decode("your_base58_secret_key");
const kp = SK.length === 32 ? nacl.sign.keyPair.fromSeed(SK) : {
  secretKey: SK, publicKey: SK.slice(32)
};

const body = JSON.stringify({jsonrpc:"2.0",id:1,method:"getSlot"});
const ts = Math.floor(Date.now()/1000).toString();
const nonce = crypto.randomBytes(16).toString("hex");
const h = crypto.createHash("sha256").update(body).digest("hex");
const msg = `solana-nodius:v2:POST:/:${ts}:${nonce}:${h}`;
const sig = nacl.sign.detached(new TextEncoder().encode(msg), kp.secretKey);

const res = await fetch("https://rpc.nodius.xyz", {
  method:"POST", body,
  headers:{
    "Content-Type":"application/json",
    "X-Pubkey": bs58.encode(kp.publicKey),
    "X-Signature": bs58.encode(sig),
    "X-Timestamp": ts, "X-Nonce": nonce,
  },
});
console.log("Credits:", res.headers.get("X-Credits-Remaining"));
console.log("Slot:", (await res.json()).result);
# curl uses API key auth. Get one first:
# POST /account/api-key with wallet sig, then:
curl -X POST https://rpc.nodius.xyz \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: srpc_live_..." \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}'

5. Generate an API Key

API keys avoid per-request signing and give you the lowest latency. They also enable drop-in compatibility with standard Solana libraries:

const result = await rpc.generateApiKey();
console.log("API key:", result.api_key);
// The SDK auto-stores the API key for subsequent calls
result = rpc.generate_api_key()
print("API key:", result["api_key"])
# The SDK auto-stores the API key for subsequent calls

Once you have an API key, you can use it in any standard Solana library by embedding it in the URL:

import { Connection } from "@solana/web3.js";

// Drop-in: paste one URL, every standard method works
const conn = new Connection("https://rpc.nodius.xyz/?api-key=srpc_live_...");
const slot = await conn.getSlot();
from solana.rpc.api import Client

# Drop-in: paste one URL, every standard method works
client = Client("https://rpc.nodius.xyz/?api-key=srpc_live_...")
slot = client.get_slot()
curl -X POST "https://rpc.nodius.xyz/?api-key=srpc_live_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}'

Or pass it as a header โ€” both work:

curl -X POST https://rpc.nodius.xyz \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: srpc_live_..." \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}'

6. Check Your Balance

Every response includes an X-Credits-Remaining header. Or check programmatically:

const info = await rpc.getBillingAccount();
console.log("Balance:", info.balance);
console.log("Deposit address:", info.deposit_address);
info = rpc.get_billing_account()
print("Balance:", info["balance"])
print("Deposit address:", info.get("deposit_address"))
import json, urllib.request
req = urllib.request.Request(
    "https://rpc.nodius.xyz/account/info",
    headers={"X-Api-Key": "srpc_live_..."},
)
with urllib.request.urlopen(req) as r:
    info = json.loads(r.read())
    print("Balance:", info["balance"])
const res = await fetch("https://rpc.nodius.xyz/account/info", {
  headers: { "X-Api-Key": "srpc_live_..." },
});
const info = await res.json();
console.log("Balance:", info.balance);
curl https://rpc.nodius.xyz/account/info \
  -H "X-Api-Key: srpc_live_..."

Blockhash Best Practices

Solana transactions embed a recent blockhash for replay protection. A transaction is valid for ~150 blocks (~60โ€“90 seconds), but a blockhash from one RPC node may not be visible at another node at submission time โ€” different nodes sit at slightly different slots, and a blockhash fetched at the tip of one node may not yet exist in another's working set.

Always fetch the blockhash from Nodius when submitting to Nodius. Fetching from a different RPC (e.g. api.mainnet-beta.solana.com) and submitting here with preflight enabled will produce BlockhashNotFound if our node is 1โ€“2 slots behind the one that issued the blockhash. This is inherent to Solana's multi-node architecture, not a Nodius-specific issue โ€” every RPC provider has the same constraint.

// Fetch blockhash from Nodius, not public RPC
const blockhash = await rpc.call("getLatestBlockhash");
// ...build and sign transaction with that blockhash...
const sig = await rpc.call("sendTransaction", [signedTx, { encoding: "base64" }]);
# Fetch blockhash from Nodius, not public RPC
blockhash = rpc.call("getLatestBlockhash")
# ...build and sign transaction with that blockhash...
sig = rpc.call("sendTransaction", [signed_tx, {"encoding": "base64"}])

For latency-sensitive racing paths (liquidations, MEV, snipes), use skipPreflight: true โ€” preflight simulation adds 50โ€“100ms and the on-chain program is the real validity check anyway.


Connection Hygiene

For latency-sensitive workloads, hold persistent HTTP connections. A cold TLS handshake adds ~60-80ms to the first request; reusing a warm connection eliminates that entirely.

Next Steps