Quickstart
Get from zero to your first RPC call in under 5 minutes. No signup, no subscription, no KYC.
Prerequisites
- A Solana wallet (or we'll generate one below)
- USDC for credits ($0.01 minimum)
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.
- Rate: 1 USDC = 10000 credits
- Expiry: 10 days
โ ๏ธ 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(returnsdeposit_addressandfundingfields) or the402 Payment Requiredresponsedata.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.
- Use a persistent client โ
requests.Session()(Python),fetchwith a sharedAgent(Node.js), or a connection pool. Do not create a new HTTP client per request. - Keep-alive is on by default โ Nodius keeps server-side connections alive with a 30s idle timeout. A request every 30s keeps a connection warm indefinitely.
- WebSocket avoids HTTP overhead entirely โ for real-time data, a single WS subscription replaces polling and avoids per-request TLS/HTTP overhead.
Next Steps
- Authentication โ wallet sig, API keys, session tokens
- API Reference โ all endpoints
- Pricing โ method costs and credit details
- Streaming Guide โ streaming data