Skip to main content
The Helius TypeScript SDK provides type-safe methods for all Helius APIs, making it the fastest way for agents to interact with Solana.
  • Package: helius-sdk (npm / pnpm / yarn)
  • Version: 2.x (uses @solana/kit, not @solana/web3.js)
  • Runtime: Any JavaScript runtime — browsers, Deno, Bun, edge runtimes (Cloudflare Workers, Vercel Edge), Node.js 20+
  • TypeScript: 5.8+ (full type definitions included)
  • License: ISC

Installation

npm install helius-sdk

Quick Start

import { createHelius } from "helius-sdk";

const helius = createHelius({
  apiKey: "YOUR_API_KEY",
  network: "mainnet", // or "devnet"
});

// Get all NFTs and tokens owned by a wallet
const assets = await helius.getAssetsByOwner({
  ownerAddress: "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  page: 1,
  limit: 50,
});

// Get transaction history (with token account activity)
const txs = await helius.getTransactionsForAddress([
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  { limit: 100, transactionDetails: "full", filters: { tokenAccounts: "balanceChanged" } },
]);

// Send a transaction via Helius Sender (ultra-low latency)
const sig = await helius.tx.sendTransactionWithSender({
  instructions: [transferInstruction],
  signers: [walletSigner],
  region: "US_EAST",
});

Client Options

const helius = createHelius({
  apiKey: "YOUR_API_KEY",       // Required for webhooks, enhanced txs, wallet API
  network: "mainnet",           // "mainnet" (default) or "devnet"
  baseUrl: "https://custom..",  // Override RPC URL (optional)
  rebateAddress: "wallet",      // Wallet for RPC rebates (optional)
  userAgent: "my-agent/1.0",   // Sent as X-Helius-Client header (optional)
});

Namespaces

All methods are accessed through the helius client. DAS API methods and standard Solana RPC methods are available directly on helius.*. Other functionality is organized into namespaces:
NamespaceAccessPurpose
DAS APIhelius.getAsset(), helius.getAssetsByOwner(), etc.Query NFTs, tokens, compressed assets
RPC V2helius.getTransactionsForAddress(), helius.getProgramAccountsV2()Enhanced RPC with pagination and filters
Transactionshelius.tx.*Smart transactions and Helius Sender
Enhancedhelius.enhanced.*Parse transactions into human-readable format
Webhookshelius.webhooks.*Create and manage webhook subscriptions
WebSocketshelius.ws.*Real-time blockchain data streams
Stakinghelius.stake.*Stake SOL to Helius validator
ZK Compressionhelius.zk.*Compressed accounts and proofs
Wallet APIhelius.wallet.*Balances, history, identity lookups
Standard RPChelius.getBalance(), helius.getSlot(), etc.All standard Solana RPC methods via proxy
Raw RPChelius.rawDirect access to the underlying @solana/kit Rpc client
Authimport { makeAuthClient } from "helius-sdk/auth/client"Agent signup and API key management (standalone import)

Recommendations for Agents

Use getTransactionsForAddress instead of two-step lookup

getTransactionsForAddress combines signature lookup and transaction fetching into a single call with server-side filtering. It supports time/slot ranges, token account filtering, and pagination.
// GOOD: Single call, server-side filtering
const txs = await helius.getTransactionsForAddress([
  "address",
  {
    transactionDetails: "full",
    limit: 100,
    filters: {
      tokenAccounts: "balanceChanged",
      blockTime: { gte: Math.floor(Date.now() / 1000) - 86400 },
    },
  },
]);

// BAD: Two calls, client-side filtering, no token account support
const sigs = await helius.raw.getSignaturesForAddress(address).send();
const txs = await Promise.all(sigs.map(s => helius.raw.getTransaction(s.signature).send()));

Use sendSmartTransaction for standard sends

It automatically simulates, estimates compute units, fetches priority fees, and confirms. Do not manually build ComputeBudget instructions — the SDK adds them automatically.
const sig = await helius.tx.sendSmartTransaction({
  instructions: [yourInstruction],
  signers: [walletSigner],
  commitment: "confirmed",
  priorityFeeCap: 100_000,   // Optional: cap fees in microlamports/CU
  bufferPct: 0.1,            // 10% compute unit headroom (default)
});

Use Helius Sender for ultra-low latency

For time-sensitive transactions (arbitrage, sniping, liquidations), use sendTransactionWithSender. It routes through Helius’s multi-region infrastructure and Jito.
const sig = await helius.tx.sendTransactionWithSender({
  instructions: [yourInstruction],
  signers: [walletSigner],
  region: "US_EAST",          // Default, US_SLC, US_EAST, EU_WEST, EU_CENTRAL, EU_NORTH, AP_SINGAPORE, AP_TOKYO
  swqosOnly: true,            // Route through SWQOS only (lower tip requirement)
  pollTimeoutMs: 60_000,
  pollIntervalMs: 2_000,
});

Use getAssetBatch for multiple assets

When fetching more than one asset, batch them. Do not call getAsset in a loop.
// GOOD: Single request
const assets = await helius.getAssetBatch({
  ids: ["mint1", "mint2", "mint3"],
  options: { showFungible: true, showCollectionMetadata: true },
});

// BAD: N requests
const assets = await Promise.all(mints.map(id => helius.getAsset({ id })));

Use webhooks or WebSockets instead of polling

Do not poll getTransactionsForAddress in a loop. Use webhooks for server-to-server notifications or WebSockets for real-time client-side streaming.
// Webhook: server receives POST on matching transactions
const webhook = await helius.webhooks.create({
  webhookURL: "https://your-server.com/webhook",
  webhookType: "enhanced",
  transactionTypes: ["TRANSFER", "NFT_SALE", "SWAP"],
  accountAddresses: ["address_to_monitor"],
  authHeader: "Bearer your-secret",
});

// WebSocket: stream logs in real-time
const req = await helius.ws.logsNotifications({ mentions: ["address"] });
const stream = await req.subscribe({ abortSignal: controller.signal });
for await (const log of stream) {
  console.log(log);
}

Pagination

The SDK uses different pagination strategies depending on the method.

Token/Cursor-Based (RPC V2 Methods)

// getTransactionsForAddress uses paginationToken
let paginationToken = null;
const allTxs = [];
do {
  const result = await helius.getTransactionsForAddress([
    "address",
    { limit: 100, paginationToken },
  ]);
  allTxs.push(...result.data);
  paginationToken = result.paginationToken;
} while (paginationToken);

// getProgramAccountsV2 uses paginationKey
let paginationKey = null;
do {
  const result = await helius.getProgramAccountsV2([
    programId,
    { limit: 1000, paginationKey },
  ]);
  // process result.accounts
  paginationKey = result.paginationKey;
} while (paginationKey);

Page-Based (DAS API)

let page = 1;
const allAssets = [];
while (true) {
  const result = await helius.getAssetsByOwner({ ownerAddress: "...", page, limit: 1000 });
  allAssets.push(...result.items);
  if (result.items.length < 1000) break;
  page++;
}

tokenAccounts Filter

When querying getTransactionsForAddress, the tokenAccounts filter controls whether token account activity is included:
ValueBehaviorUse When
omitted / "none"Only transactions directly involving the addressYou only care about SOL transfers and program calls
"balanceChanged"Also includes token transactions that changed a balanceRecommended for most agents — shows token sends/receives without noise
"all"Includes all token account transactionsYou need complete token activity (can return many results)

changedSinceSlot — Incremental Account Fetching

changedSinceSlot returns only accounts modified after a given slot. Useful for syncing or indexing workflows. Supported by getProgramAccountsV2, getTokenAccountsByOwnerV2, getAccountInfo, getMultipleAccounts, getProgramAccounts, and getTokenAccountsByOwner.
// First fetch: get all accounts
const baseline = await helius.getProgramAccountsV2([programId, { limit: 10_000 }]);
const lastSlot = currentSlot;

// Later: only get accounts that changed since your last fetch
const updates = await helius.getProgramAccountsV2([
  programId,
  { limit: 10_000, changedSinceSlot: lastSlot },
]);

Common Mistakes

  1. transactionDetails: "full" is not the default — By default, getTransactionsForAddress returns signatures only. Set transactionDetails: "full" to get full transaction data.
  2. Do not add ComputeBudget instructions with sendSmartTransaction — The SDK adds them automatically. Adding your own causes duplicate instructions and transaction failure.
  3. Priority fees are in microlamports per compute unit — Not lamports. Values from getPriorityFeeEstimate are already in the correct unit for SetComputeUnitPrice.
  4. DAS pagination is 1-indexedpage: 1 is the first page, not page: 0.
  5. blockTime is Unix seconds, not milliseconds — Use Math.floor(Date.now() / 1000) when filtering by blockTime.
  6. getAsset hides fungible tokens by default — Pass options: { showFungible: true } to include them.
  7. WebSocket streams need cleanup — Always use an AbortController signal and call helius.ws.close() when done to avoid connection leaks.

Error Handling and Retries

The SDK throws native Error objects with the HTTP status code embedded in the message string (e.g., "API error (429): ..."). There is no .status property on the error object, so status detection requires message parsing.
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const msg = error instanceof Error ? error.message : "";
      const status = msg.match(/\b(\d{3})\b/)?.[1];
      const retryable = status === "429" || (status && status.startsWith("5"));
      if (!retryable || attempt === maxRetries) throw error;
      await new Promise(r => setTimeout(r, 1000 * 2 ** attempt));
    }
  }
  throw new Error("Unreachable");
}
StatusMeaningAction
401Invalid or missing API keyCheck API key
429Rate limited or out of creditsBack off and retry
5xxServer errorRetry with exponential backoff

Programmatic Signup (Auth Module)

The auth module is a standalone import — it is not on the main HeliusClient. Use it for programmatic agent signup flows.
import { makeAuthClient } from "helius-sdk/auth/client";

const auth = makeAuthClient();

// All-in-one shortcut:
const result = await auth.agenticSignup({ secretKey: keypair.secretKey });
// result: { jwt, walletAddress, projectId, apiKey, endpoints, credits }

// Or step-by-step:
const keypair = await auth.generateKeypair();
const address = await auth.getAddress(keypair);
const { message, signature } = await auth.signAuthMessage(keypair.secretKey);
const { token } = await auth.walletSignup(message, signature, address);
const project = await auth.createProject(token);
const apiKey = await auth.createApiKey(token, project.id, address);

API Quick Reference

Here is a full list of all API methods supported by the Helius TypeScript SDK:

DAS API (Digital Asset Standard)

helius.getAsset({ id })                                    // Single asset by mint
helius.getAssetBatch({ ids })                              // Multiple assets
helius.getAssetsByOwner({ ownerAddress, page, limit })     // Assets by wallet
helius.getAssetsByAuthority({ authorityAddress })           // Assets by update authority
helius.getAssetsByCreator({ creatorAddress })               // Assets by creator
helius.getAssetsByGroup({ groupKey, groupValue })           // Assets by collection
helius.searchAssets({ ownerAddress, tokenType, ... })       // Flexible search
helius.getAssetProof({ id })                               // Merkle proof (cNFTs)
helius.getAssetProofBatch({ ids })                         // Batch Merkle proofs
helius.getTokenAccounts({ owner })                         // Token accounts
helius.getNftEditions({ id })                              // Print editions
helius.getSignaturesForAsset({ id })                       // Transaction history for asset

RPC V2 Methods

helius.getTransactionsForAddress([address, config])        // Transaction history (paginationToken)
helius.getProgramAccountsV2([programId, config])           // Program accounts (paginationKey)
helius.getTokenAccountsByOwnerV2([owner, filter?, config]) // Token accounts (paginationKey)
helius.getPriorityFeeEstimate({ accountKeys, options })    // Fee estimates

Transactions

helius.tx.sendSmartTransaction({ instructions, signers })  // Auto-optimized send
helius.tx.createSmartTransaction({ instructions, signers })// Build without sending
helius.tx.sendTransactionWithSender({ ..., region })       // Helius Sender (low latency)

Enhanced Transactions

helius.enhanced.getTransactions({ transactions })          // Parse by signatures
helius.enhanced.getTransactionsByAddress({ address })      // Parse by address

Webhooks

helius.webhooks.create({ webhookURL, transactionTypes, accountAddresses })
helius.webhooks.get(webhookID)
helius.webhooks.getAll()
helius.webhooks.update(webhookID, params)
helius.webhooks.delete(webhookID)

WebSockets

helius.ws.logsNotifications(filter, config)                // Transaction logs
helius.ws.accountNotifications(address, config)            // Account changes
helius.ws.signatureNotifications(signature, config)        // Tx confirmation
helius.ws.slotNotifications(config)                        // Slot updates
helius.ws.programNotifications(programId, config)          // Program account changes
helius.ws.close()                                          // Clean up connections

Staking

helius.stake.createStakeTransaction(owner, amountSol)                          // Stake SOL
helius.stake.createUnstakeTransaction(ownerSigner, stakeAccount)               // Unstake
helius.stake.createWithdrawTransaction(withdrawAuth, stakeAcct, dest, lamports)// Withdraw
helius.stake.getHeliusStakeAccounts(wallet)                // List stake accounts

Wallet API

helius.wallet.getBalances({ wallet })                      // Token balances
helius.wallet.getHistory({ wallet })                       // Transaction history
helius.wallet.getTransfers({ wallet })                     // Transfer history
helius.wallet.getIdentity({ wallet })                      // Known identity lookup
helius.wallet.getBatchIdentity({ addresses })              // Batch identity (max 100)
helius.wallet.getFundedBy({ wallet })                      // Funding source

ZK Compression

helius.zk.getCompressedAccount({ address })                // Single compressed account
helius.zk.getCompressedAccountsByOwner({ owner })          // By owner
helius.zk.getCompressedTokenAccountsByOwner({ owner })     // Compressed tokens
helius.zk.getCompressedAccountProof({ hash })              // Merkle proof
helius.zk.getCompressedBalance({ address })                // Balance
helius.zk.getValidityProof({ hashes })                     // Validity proof

Standard Solana RPC

All standard Solana RPC methods are available directly on helius.* via a proxy to the underlying @solana/kit Rpc client:
const balance = await helius.getBalance(address).send();
const blockhash = await helius.getLatestBlockhash().send();
const slot = await helius.getSlot().send();
The helius.raw property exposes the same Rpc client explicitly, useful when passing to third-party libraries that expect a standard Rpc object.

Resources