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.

  1. Generate a Solana keypair (Ed25519)
  2. POST /account/activate with wallet signature headers
  3. Returns: pubkey, optional api_key, deposit_address, funding instructions, balance
  4. Send USDC to the deposit_address from the same wallet
  5. Wait ~30s for deposit confirmation
  6. Start making RPC calls using either wallet signatures or the optional API key

Minimal wallet-only TypeScript flow:

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

const keypair = Keypair.generate();
const rpc = new NodiusClient("https://rpc.nodius.xyz", { keypair });

const account = await rpc.activate();
console.log("Deposit USDC from this wallet to:", account.deposit_address);
console.log("Credit rate:", account.credits_per_usdc, "credits / USDC");
console.log("Credit expiry:", account.credit_expiry_seconds, "seconds");

const info = await rpc.getAccountInfo();
if (info.balance <= 0) throw new Error("Deposit USDC before sending traffic");

const slot = await rpc.getSlot();
console.log(slot);

API keys remain optional. Generate one only when the bot can safely manage a generated secret:

const { api_key } = await rpc.generateApiKey();

Auth Methods Comparison

Method Latency Security Best For
API Key (X-Api-Key) Lowest (~0ms overhead) Medium (secret storage) Bots, scripts, high-frequency trading
Per-request wallet sig Low (~1ms overhead) Highest (no API key secret) Security-critical automated systems
Session token (Bearer) Low (~0.5ms lookup) Medium (1h expiry) WebSocket connections, dApps

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

Endpoint Profile

The default Frankfurt endpoint is a hot-node profile optimized for:

Archive/history methods such as getTransaction, getSignaturesForAddress, and getBlock, plus heavy indexed scans such as getProgramAccounts, are enabled on dedicated endpoint profiles. When a profile is disabled, the request is rejected before billing with a deterministic service-profile error. Bots should treat -32004 as "route to an archive/heavy endpoint or skip this workflow."

Hot-Path Optimization Tips

  1. Choose auth mode deliberately
  2. Wallet signatures avoid API-key storage and are the preferred keyless bot mode
  3. API key auth is lowest latency when a bot can safely manage a generated secret
  4. Session tokens are useful for long-lived dApp or WebSocket clients

  5. Batch requests when possible

  6. A batch of 10 getBalance calls = 1 HTTP round-trip, billed as 10 credits
  7. Rate limit counts as 1 request

  8. Use getMultipleAccounts instead of N x getAccountInfo

  9. 1 credit per account, single round-trip
  10. Max 100 accounts per call

  11. Cache getLatestBlockhash locally

  12. Blockhash is valid for ~60 seconds
  13. Cache client-side, refresh every 30s

  14. Prefer confirmed over finalized commitment

  15. Finalized adds ~13 seconds of latency
  16. Use confirmed for reads, finalized only when required

  17. Monitor X-Credits-Remaining header

  18. Included in every response
  19. Automate reloads when credits drop below threshold
  20. Unused deposit credits expire after 10 days

  21. Use bulk endpoints for multi-account queries

  22. POST /bulk/getBalances (up to 100 pubkeys)
  23. POST /bulk/getTokenBalances (up to 100 pubkeys)
  24. POST /bulk/getTransactions (up to 20 signatures)

  25. For streaming data, use WebSocket or Yellowstone gRPC

  26. WS: 5 credits per subscription + 1 per notification
  27. Yellowstone: 60 credits/minute (flat rate, unlimited notifications)
  28. Better than polling for real-time account changes

Machine-Readable Error Codes

HTTP Status JSON-RPC Code Constant Description
402 -32010 INSUFFICIENT_CREDITS Balance too low for this request
429 -32005 RATE_LIMITED Per-second rate limit exceeded
429 -32005 CONCURRENCY_LIMITED Too many concurrent requests
502 -32003 BACKEND_UNAVAILABLE Upstream Solana node unreachable
403 -32001 METHOD_NOT_ALLOWED Method denied
200 -32004 SERVICE_PROFILE_DISABLED Archive/history or heavy-indexed profile is not enabled; no credits consumed
503 -32003 SERVICE_TEMPORARILY_UNAVAILABLE Transient service gate/dependency condition; no credits consumed when rejected before billing
401 -32000 AUTH_FAILED Invalid signature, expired token, or bad API key
400 -32600 INVALID_REQUEST Malformed JSON-RPC request
200 -32601 METHOD_NOT_FOUND Unknown RPC method

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(`Route ${method} to another endpoint profile or skip it`);
    }

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

    throw err;
  }
}