Bot & Agent Onboarding Guide

Nodius is purpose-built for automated systems. This guide covers the recommended onboarding flow, authentication method selection, endpoint-profile behavior, and hot-path optimization tips for bots, trading systems, and AI agents.

How Identity & Credits Work

Your Solana keypair is your identity. Credits are tied to your public key โ€” no signup, no email, no account creation step. Three things that sound interchangeable are actually separate:

What you want to do What it requires
Authenticate (prove you own the keypair) A valid wallet signature. Always works, regardless of balance.
Call account-info endpoints (GET /account/info, POST /account/api-key) An account record, which is created automatically on first deposit or by calling POST /account/api-key (zero balance).
Make billable RPC calls (getSlot, getBalance, sendTransaction, etc.) A positive credit balance. Credits come from USDC deposits.

If you call a billable method before funding, you'll get 402 Payment Required with deposit instructions. The signature is valid โ€” the credits aren't there yet.

  1. Generate or load a Solana keypair (Ed25519)
  2. Generate an API key via generateApiKey() (TypeScript) or generate_api_key() (Python). This creates the account record and auto-stores the key for subsequent calls.
  3. Get your deposit address via getBillingAccount() / get_billing_account() and send USDC (SPL) on Solana mainnet from that wallet (minimum $0.01). Credits appear within seconds.
  4. Start making RPC calls. Wallet-sig auth works from the start; the API key avoids per-request signing overhead.

Before funding: The account record exists (created in step 2) with zero balance. GET /account/info works and returns your deposit address. Billable RPC calls return 402 until the deposit lands. With x402 auto-pay enabled (autoPay: true / auto_pay=True), the first 402 triggers an automatic micro-deposit and the call is retried.

Minimal TypeScript flow

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

// No @solana/web3.js import needed โ€” pass your base58 secret key directly
const rpc = NodiusClient.fromSecretKey("https://rpc.nodius.xyz", "your-base58-secret-key");

// Step 1: Generate an API key (also creates the account record):
const result = await rpc.generateApiKey();
console.log("API key:", result.api_key);

// Step 2: Get your deposit address and fund with USDC (SPL):
const info = await rpc.getBillingAccount();
console.log("Deposit USDC to:", info.deposit_address);
// Credits appear within ~30 seconds of on-chain confirmation.

// Step 3: Make billable RPC calls:
const slot = await rpc.call("getSlot");
console.log("Slot:", slot);

Minimal Python flow

from nodius import NodiusClient

# Accepts 32-byte seeds and 64-byte expanded keys in base58
client = NodiusClient.from_base58("https://rpc.nodius.xyz", secret_key="your-base58-secret-key")

# Step 1: Generate an API key (also creates the account record):
result = client.generate_api_key()
print("API key:", result["api_key"])

# Step 2: Get your deposit address and fund with USDC (SPL):
info = client.get_billing_account()
print("Deposit USDC to:", info.get("deposit_address"))
# Credits appear within ~30 seconds of on-chain confirmation.

# Step 3: Make billable RPC calls:
slot = client.call("getSlot")
print("Slot:", slot)

Alternative: explicit Keypair object (TypeScript)

import { Keypair } from "@solana/web3.js";
import { NodiusClient } from "@nodius/sdk";

const keypair = Keypair.generate();
const rpc = new NodiusClient("https://rpc.nodius.xyz", { keypair });
await rpc.generateApiKey();  // also auto-stores API key

API keys are auto-stored by generateApiKey() / generate_api_key(). The POST /account/api-key endpoint generates an API key and returns it. Manual key management is rarely needed:

Auth Methods Comparison

Method Latency Security Best For
API Key (X-Api-Key header or ?api-key= URL) Lowest โ€” no per-request signing Medium (secret storage) Latency-sensitive bots, drop-in with standard Solana libraries
Per-request wallet sig Low โ€” Ed25519 sign + SHA-256 hash + nonce check per request Highest (no API key secret) Security-critical automated systems
Session token (Bearer) Low Medium (1h expiry) WebSocket connections, dApps

All three modes work for every request type. The difference is latency and convenience. Wallet signatures are the zero-setup default โ€” the SDK handles signing automatically. API keys avoid per-request signing entirely and enable drop-in compatibility with standard Solana libraries via ?api-key= in the URL.

Recommendation for bots: wallet signatures are fully supported for keyless autonomous operation and must remain available. Use API keys when the bot operator is comfortable managing a generated secret and wants the absolute lowest auth overhead.

Available Methods

The default Frankfurt endpoint serves all standard Solana RPC methods. Heavy methods like getTokenAccountsByOwner and getBlock are available and cost 25 credits per call. getTransaction and getSignaturesForAddress are served directly by the hot node.

Some historical methods (getEnrichedTransaction, explainTransaction, getConfirmedTransaction) are not available and return -32004 at no charge. getProgramAccounts is not available.

Hot-Path Optimization Tips

  1. Choose auth mode deliberately. Wallet signatures are the zero-setup default โ€” the SDK signs every request automatically. API keys avoid per-request signing and are the lowest-latency option. If you are latency-sensitive, generate an API key early. Session tokens are useful for long-lived dApp or WebSocket clients.

  2. Hold persistent connections. A cold TLS handshake adds ~60-80ms to the first request. Reuse HTTP connections via requests.Session() (Python), a shared Agent (Node.js), or a connection pool. Nodius keeps server-side connections alive with a 30s idle timeout โ€” a request every 30s keeps a connection warm. For real-time data, a single WebSocket subscription avoids per-request HTTP overhead entirely.

  3. Batch requests when possible. A batch of 10 getBalance calls = 1 HTTP round-trip, billed as 10 credits. Rate limit counts as 1 request.

  4. Use getMultipleAccounts instead of N ร— getAccountInfo. 1 credit per account, single round-trip. Max 100 accounts per call.

  5. Cache getLatestBlockhash locally. Blockhash is valid for ~60 seconds. Cache client-side, refresh every 30s.

  6. Prefer confirmed over finalized commitment. Finalized adds ~13 seconds of latency. Use confirmed for reads, finalized only when required.

  7. Monitor X-Credits-Remaining header. Included in every response. Automate reloads when credits drop below threshold. Unused deposit credits expire after 10 days.

  8. Use bulk endpoints for multi-account queries. POST /bulk/getBalances (up to 100 pubkeys), POST /bulk/getTokenBalances (up to 50 owners), POST /bulk/getTransactions (up to 50 signatures).

  9. For streaming data, use WebSocket or Yellowstone gRPC. WS: 5 credits per subscription + 1 per notification. Yellowstone: 60 credits/minute (flat rate, unlimited notifications). Better than polling for real-time account changes.

Machine-Readable Error Codes

HTTP RPC Code Constant Credits? Retry? SDK error class
402 -32010 INSUFFICIENT_CREDITS No After deposit InsufficientCreditsError
402 -32002 PAYMENT_REQUIRED No After deposit InsufficientCreditsError
429 -32005 RATE_LIMITED No Yes (Retry-After) RateLimitError
429 -32005 CONCURRENCY_LIMITED No Yes (1s + jitter) RateLimitError
502 -32003 BACKEND_UNAVAILABLE No Yes (backoff) BackendUnavailableError
503 -32003 SERVICE_TEMPORARILY_UNAVAILABLE No Yes (backoff) BackendUnavailableError
403 -32001 METHOD_NOT_ALLOWED No No MethodNotAllowedError
200 -32004 SERVICE_PROFILE_DISABLED No No ServiceProfileDisabledError
403 โ€” NONCE_REUSED No No (new nonce) AuthenticationError
401 -32000 AUTH_FAILED No No (fix creds) AuthenticationError / ExpiredSessionError
400 -32600 INVALID_REQUEST No No (fix request) NodiusError
200 -32601 METHOD_NOT_FOUND No No MethodNotAllowedError / RpcError

Credits are never consumed on any error response โ€” billing happens only after the upstream node returns a successful result. For the full error reference including upstream Solana node codes and disambiguation guidance, see Error Reference.

Response headers on every request: - X-Credits-Remaining: current credit balance - X-Credits-Low: true (when balance < 1000) - Retry-After: seconds (on 429)

Error Handling Best Practice

Use SDK error classes for production bots. This keeps wallet-only auth intact and avoids hand-written signing bugs.

import {
  BackendUnavailableError,
  InsufficientCreditsError,
  NodiusClient,
  RateLimitError,
  ServiceProfileDisabledError,
} from "@nodius/sdk";

async function rpcCall(rpc: NodiusClient, method: string, params: unknown[] = []) {
  try {
    return await rpc.call(method, params);
  } catch (err) {
    if (err instanceof RateLimitError) {
      await new Promise((resolve) => setTimeout(resolve, err.retryAfter * 1000));
      return rpcCall(rpc, method, params);
    }

    if (err instanceof InsufficientCreditsError) {
      throw new Error("Out of credits - deposit USDC from the registered wallet");
    }

    if (err instanceof ServiceProfileDisabledError) {
      throw new Error(`Method not available โ€” use an archive provider for ${method}`);
    }

    if (err instanceof BackendUnavailableError) {
      throw new Error("Backend unavailable - retry with jitter or fail over");
    }

    throw err;
  }
}