Skip to main content
Complete API reference for the @boltzpay/sdk package. Every public class, method, type, and error is documented here with exact TypeScript signatures.

Installation

npm install @boltzpay/sdk

BoltzPay class

The main entry point. Instantiate once and reuse across requests.

Constructor

import { BoltzPay } from '@boltzpay/sdk';

const sdk = new BoltzPay(config: BoltzPayConfig);
See BoltzPayConfig for the full configuration type.
Coinbase credentials are optional at construction time. Read-only methods (quote, getBudget, getHistory, getCapabilities, discover) work without them. Payment methods (fetch) require credentials and will throw at execution time if missing.

Methods

fetch(url, options?)

Fetch data from a paid API endpoint. Automatically detects the payment protocol, pays the required amount, and returns the response. If no payment protocol is detected, the request passes through as a normal fetch. Concurrent calls are serialized internally to prevent double-spend.
async fetch(url: string, options?: FetchOptions): Promise<BoltzPayResponse>
ParameterTypeRequiredDescription
urlstringYesURL of the paid API endpoint
optionsFetchOptionsNoRequest options (method, headers, body, maxAmount, chain)
Returns: BoltzPayResponse Throws: ProtocolError, BudgetExceededError, NetworkError
const response = await sdk.fetch('https://invy.bot/api');
const data = await response.json();
console.log(data);
console.log(response.payment); // { protocol: 'x402', amount: Money, ... }

quote(url)

Check the cost of a paid endpoint without paying. Probes the URL and returns pricing information.
async quote(url: string): Promise<QuoteResult>
ParameterTypeRequiredDescription
urlstringYesURL of the paid endpoint
Returns: QuoteResult Throws: ProtocolError with code protocol_detection_failed if the endpoint is free.
const quote = await sdk.quote('https://invy.bot/api');
console.log(quote.amount.toDisplayString()); // "$0.05"
console.log(quote.protocol);                 // "x402"

getBudget()

Get the current budget state, including limits, spending, and remaining amounts.
getBudget(): BudgetState
Returns: BudgetState
const budget = sdk.getBudget();
console.log(budget.dailySpent.toDisplayString());     // "$1.25"
console.log(budget.dailyRemaining?.toDisplayString()); // "$8.75"

resetDailyBudget()

Reset the daily spending counter to zero. Call this at the start of each day if you manage budget resets manually.
resetDailyBudget(): void

getHistory()

Get all payment records. When persistence is enabled, history survives restarts (stored as history.jsonl, last 500 entries by default).
getHistory(): readonly PaymentRecord[]
Returns: Array of PaymentRecord, ordered chronologically.

getCapabilities()

Return the configured network, supported protocols, payment readiness, chain namespaces, and cached wallet addresses.
getCapabilities(): {
  network: string;
  protocols: string[];
  canPay: boolean;
  canPayLightning: boolean;
  chains: ChainNamespace[];
  addresses: { evm?: string; svm?: string };
}
FieldTypeDescription
networkstring"base" or "base-sepolia"
protocolsstring[]["x402"] or ["x402", "l402"]
canPaybooleantrue if Coinbase credentials are configured
canPayLightningbooleantrue if NWC connection string is configured
chainsChainNamespace[]["evm", "svm"]
addresses{ evm?: string; svm?: string }Cached wallet addresses (populated after first use)

getBalances()

Query USDC balance per chain from the wallet manager. Degrades gracefully: returns an empty object if credentials are missing or the query fails.
async getBalances(): Promise<{
  evm?: { address: string; balance: Money | undefined };
  svm?: { address: string; balance: Money | undefined };
}>

getWalletStatus()

Comprehensive wallet health check. Probes Coinbase CDP connectivity, fetches on-chain balances, checks Lightning (NWC) wallet connectivity and balance, and reports credential and budget status. This is the only method that actively tests connections — other methods use cached data.
async getWalletStatus(): Promise<WalletStatus>
Returns: WalletStatus
const status = await sdk.getWalletStatus();
console.log(status.connection.status); // "connected"
console.log(status.canPay);           // true
if (status.lightning?.balance) {
  console.log(status.lightning.balance.display); // "4800 sats"
}

discover(options?)

Browse the built-in API directory with real-time endpoint probing. Each endpoint is checked live to verify availability and current pricing. Optionally merges live endpoints from the Bazaar Discovery API.
async discover(options?: DiscoverOptions): Promise<readonly DiscoveredEntry[]>
ParameterTypeRequiredDescription
optionsDiscoverOptionsNoFilter by category, toggle live discovery, pass an AbortSignal

close()

Close open connections (NWC WebSocket, etc.). Call when done using the SDK instance.
close(): void

on(event, callback)

Subscribe to SDK events. Returns this for chaining.
on<E extends EventName>(event: E, listener: EventListener<E>): this
See BoltzPayEvents for the complete event map.

off(event, callback)

Unsubscribe from SDK events. Returns this for chaining.
off<E extends EventName>(event: E, listener: EventListener<E>): this

sdk
  .on('payment', (record) => {
    console.log(`Paid ${record.amount.toDisplayString()} via ${record.protocol}`);
  })
  .on('budget:warning', (event) => {
    console.log(`${(event.usage * 100).toFixed(0)}% of ${event.period} budget used`);
  })
  .on('error', (err) => {
    console.error('SDK error:', err.message);
  });

Types

BoltzPayConfig

Configuration object passed to the BoltzPay constructor. All fields are optional.
interface BoltzPayConfig {
  coinbaseApiKeyId?: string;
  coinbaseApiKeySecret?: string;
  coinbaseWalletSecret?: string;
  nwcConnectionString?: string;      // Must start with "nostr+walletconnect://"
  network?: "base" | "base-sepolia"; // Default: "base"
  preferredChains?: ChainNamespace[];
  budget?: BudgetConfig;
  persistence?: {
    enabled?: boolean;                // Default: false
    directory?: string;               // Default: "~/.boltzpay/"
    historyMaxRecords?: number;       // Default: 500
  };
  logLevel?: "debug" | "info" | "warn" | "error" | "silent"; // Default: "warn"
}
FieldTypeDefaultDescription
coinbaseApiKeyIdstringCoinbase CDP API key ID
coinbaseApiKeySecretstringCoinbase CDP API key secret
coinbaseWalletSecretstringCoinbase CDP wallet secret
nwcConnectionStringstringNWC connection string (enables L402 protocol)
network"base" | "base-sepolia""base"Blockchain network
preferredChainsChainNamespace[]Preferred chain order for multi-chain endpoints
budgetBudgetConfigSpending limits
persistencePersistenceConfigEnable history and budget persistence to disk
logLevelstring"warn"Logging verbosity

BudgetConfig

interface BudgetConfig {
  daily?: string | number;            // e.g. "10.00" or 10
  monthly?: string | number;
  perTransaction?: string | number;
  warningThreshold?: number;          // 0..1, default: 0.8
  satToUsdRate?: number;              // Default: 0.001 (~$100K/BTC)
}
Budget amounts accept both string ("10.50") and number (10.50) for convenience. Strings must match the pattern ^\d+(\.\d{1,2})?$. The warningThreshold controls when the budget:warning event fires (e.g. 0.8 = 80% of the limit). The satToUsdRate converts L402 satoshi payments to USD for budget accounting. At the default rate of 0.001 (1 sat = 0.001, 0.001, ~100K/BTC), a 100-sat payment counts as $0.10 in the budget.

FetchOptions

interface FetchOptions {
  maxAmount?: number | string;
  headers?: Record<string, string>;
  method?: string;                    // Default: "GET"
  body?: Uint8Array;
  chain?: ChainNamespace;
}
FieldTypeDescription
maxAmountnumber | stringMaximum amount in dollars (e.g. 1 or "1.00"). Throws BudgetExceededError with code per_transaction_exceeded if the price exceeds this. Prefer strings to avoid float rounding.
headersRecord<string, string>Additional HTTP headers sent with the request.
methodstringHTTP method. Defaults to "GET".
bodyUint8ArrayRequest body as raw bytes.
chainChainNamespaceOverride chain selection for this request. Takes priority over preferredChains in config.

BoltzPayResponse

Returned by fetch(). Wraps the HTTP response with payment metadata.
class BoltzPayResponse {
  readonly ok: boolean;
  readonly status: number;
  readonly headers: Record<string, string>;
  readonly payment: PaymentDetails | undefined;
  readonly protocol: string | undefined;

  async json<T = unknown>(): Promise<T>;
  async text(): Promise<string>;
  get body(): ReadableStream<Uint8Array> | null;
}
Field / MethodTypeDescription
okbooleantrue if status is 200-299
statusnumberHTTP status code
headersRecord<string, string>Response headers
paymentPaymentDetails | undefinedPayment metadata, or undefined for free endpoints
protocolstring | undefinedProtocol used ("x402", "l402", or undefined)
json<T>()Promise<T>Parse body as JSON
text()Promise<string>Decode body as UTF-8 string
bodyReadableStream<Uint8Array> | nullRaw body as a ReadableStream

QuoteResult

Returned by quote().
interface QuoteResult {
  amount: Money;
  protocol: string;
  network: string | undefined;
  allAccepts?: readonly AcceptOption[];
  inputHints?: EndpointInputHints;
}
FieldTypeDescription
amountMoneyPrice of the endpoint
protocolstringDetected protocol ("x402" or "l402")
networkstring | undefinedCAIP-2 network identifier (e.g. "eip155:8453")
allAcceptsreadonly AcceptOption[]All available payment options (multi-chain)
inputHintsEndpointInputHintsHints about expected parameters (from 402 metadata)

PaymentDetails

Attached to BoltzPayResponse.payment after a successful payment.
interface PaymentDetails {
  readonly protocol: string;
  readonly amount: Money;
  readonly url: string;
  readonly timestamp: Date;
  readonly txHash: string | undefined;
}

PaymentRecord

Stored in payment history. Extends PaymentDetails with additional fields.
interface PaymentRecord {
  readonly id: string;                // UUID
  readonly url: string;
  readonly protocol: string;
  readonly amount: Money;
  readonly timestamp: Date;
  readonly txHash: string | undefined;
  readonly network: string | undefined;
}

BudgetState

Returned by getBudget().
interface BudgetState {
  readonly dailySpent: Money;
  readonly monthlySpent: Money;
  readonly dailyLimit: Money | undefined;
  readonly monthlyLimit: Money | undefined;
  readonly perTransactionLimit: Money | undefined;
  readonly dailyRemaining: Money | undefined;
  readonly monthlyRemaining: Money | undefined;
}
When no budget is configured, limits and remaining values are undefined and spent values are Money.zero().

DiscoverOptions

interface DiscoverOptions {
  readonly category?: string;
  readonly signal?: AbortSignal;
  readonly enableLiveDiscovery?: boolean; // Default: true
}
FieldTypeDefaultDescription
categorystringFilter by category (e.g. "crypto-data", "utilities")
signalAbortSignalAbort signal for cancellation
enableLiveDiscoverybooleantrueFetch live endpoints from Bazaar Discovery API and merge with static directory

DiscoveredEntry

interface DiscoveredEntry extends ApiDirectoryEntry {
  readonly live: DiscoverEntryStatus;
}
Where DiscoverEntryStatus is:
type DiscoverEntryStatus =
  | { status: "live"; livePrice: string; protocol: string; network: string | undefined }
  | { status: "free" }
  | { status: "offline"; reason: string }
  | { status: "error"; reason: string };

WalletStatus

Returned by getWalletStatus().
interface WalletStatus {
  readonly network: string;
  readonly isTestnet: boolean;
  readonly protocols: readonly string[];
  readonly canPay: boolean;
  readonly credentials: {
    readonly coinbase: CredentialStatus;
  };
  readonly connection: ConnectionStatus;
  readonly accounts: {
    readonly evm: AccountStatus | undefined;
    readonly svm: AccountStatus | undefined;
  };
  readonly budget: BudgetState;
  readonly lightning?: LightningStatus;
}
FieldTypeDescription
networkstring"base" or "base-sepolia"
isTestnetbooleantrue on "base-sepolia"
protocolsstring[]["x402"] or ["x402", "l402"]
canPaybooleantrue if Coinbase credentials are configured
credentialsobjectCredential configuration status
connectionConnectionStatusCDP connection probe result
accountsobjectEVM and Solana wallet addresses + USDC balances
budgetBudgetStateCurrent spending state
lightningLightningStatusLightning wallet status (only present if NWC configured)
Where ConnectionStatus is:
type ConnectionStatus =
  | { status: "connected"; latencyMs: number }
  | { status: "error"; error: string; latencyMs?: number }
  | { status: "skipped"; reason: string };
And LightningStatus is:
interface LightningStatus {
  readonly configured: boolean;
  readonly connection: {
    readonly status: "connected" | "error" | "skipped";
    readonly latencyMs?: number;
    readonly error?: string;
  };
  readonly balance?: { readonly sats: bigint; readonly display: string };
}

BoltzPayEvents

Event map for the on() method.
interface BoltzPayEvents {
  payment: [PaymentRecord];
  "budget:warning": [BudgetWarningEvent];
  "budget:exceeded": [BudgetExceededEvent];
  error: [Error];
}
EventPayloadWhen
paymentPaymentRecordAfter every successful payment
budget:warningBudgetWarningEventWhen spending crosses the warning threshold
budget:exceededBudgetExceededEventWhen a transaction is rejected for exceeding a budget limit
errorErrorOn any SDK error (protocol, budget, network)

BudgetWarningEvent

interface BudgetWarningEvent {
  readonly spent: Money;
  readonly limit: Money;
  readonly period: "daily" | "monthly";
  readonly usage: number; // 0..1 ratio
}

BudgetExceededEvent

interface BudgetExceededEvent {
  readonly requested: Money;
  readonly limit: Money;
  readonly period: "daily" | "monthly" | "per_transaction";
}

Re-exported types from @boltzpay/core

The SDK re-exports commonly used types so you do not need to install @boltzpay/core separately.

Money

Immutable value object representing a USD amount. Uses bigint internally for precision.
import { Money } from '@boltzpay/sdk';
MethodSignatureDescription
Money.fromDollars(dollars)static fromDollars(dollars: string): MoneyParse from dollar string (e.g. "10.50" or "$10.50")
Money.fromCents(cents)static fromCents(cents: bigint): MoneyCreate from cent amount as bigint
Money.zero()static zero(): MoneyCreate a zero-value Money
money.centsreadonly cents: bigintRaw cent amount
money.currencyreadonly currency: "USD"Always "USD"
money.add(other)add(other: Money): MoneyAddition
money.subtract(other)subtract(other: Money): MoneySubtraction (throws if result would be negative)
money.multiply(factor)multiply(factor: bigint): MoneyMultiply by integer factor
money.isZero()isZero(): booleanCheck if zero
money.greaterThan(other)greaterThan(other: Money): booleanComparison
money.greaterThanOrEqual(other)greaterThanOrEqual(other: Money): booleanComparison
money.equals(other)equals(other: Money): booleanEquality check
money.toDisplayString()toDisplayString(): stringFormat as "$10.50"
money.toJSON()toJSON(): { cents: string; currency: string; display: string }JSON-safe representation (avoids BigInt serialization crash)

ChainNamespace

type ChainNamespace = "evm" | "svm";

AcceptOption

A single payment option from a multi-chain endpoint.
interface AcceptOption {
  readonly namespace: ChainNamespace;
  readonly network: string;
  readonly amount: bigint;     // USD cents
  readonly payTo: string;
  readonly asset: string;
  readonly scheme: string;
}

Other re-exports

export type { ProtocolType, WalletInfo } from '@boltzpay/core';

API Directory exports

The SDK exports the static API directory for programmatic access:
import {
  API_DIRECTORY,
  getDirectoryCategories,
  filterDirectory,
  toDiscoverJson,
} from '@boltzpay/sdk';
ExportTypeDescription
API_DIRECTORYreadonly ApiDirectoryEntry[]Full directory of verified endpoints
getDirectoryCategories()() => string[]Get all distinct categories
filterDirectory(category?)(category?: string) => readonly ApiDirectoryEntry[]Filter directory by category
toDiscoverJson(entry)(entry: DiscoveredEntry) => DiscoverJsonEntryConvert a discovered entry to a JSON-serializable format

ApiDirectoryEntry

interface ApiDirectoryEntry {
  readonly name: string;
  readonly url: string;
  readonly protocol: string;
  readonly category: string;
  readonly description: string;
  readonly pricing: string;
  readonly chain?: string;
  readonly status?: "live" | "testnet";
}

Errors

import {
  BoltzPayError,
  BudgetExceededError,
  ConfigurationError,
  InsufficientFundsError,
  NetworkError,
  ProtocolError,
} from '@boltzpay/sdk';
The SDK wraps all internal errors. You only need to catch BoltzPayError subclasses.

Error hierarchy

All subclasses extend the abstract BoltzPayError, which adds code and statusCode to the native Error.
BoltzPayError (abstract)
├── BudgetExceededError      429   + requested: Money, limit: Money
├── ConfigurationError       400
├── InsufficientFundsError   402
├── NetworkError             503
└── ProtocolError            502
abstract class BoltzPayError extends Error {
  abstract readonly code: string;
  abstract readonly statusCode: number;
}

Error codes

CodeClassWhen thrown
daily_budget_exceededBudgetExceededErrorPayment would exceed daily budget
monthly_budget_exceededBudgetExceededErrorPayment would exceed monthly budget
per_transaction_exceededBudgetExceededErrorPayment exceeds per-transaction or maxAmount limit
missing_coinbase_credentialsConfigurationErrorCoinbase keys required but missing
invalid_configConfigurationErrorConfig fails Zod validation
insufficient_usdcInsufficientFundsErrorNot enough USDC in wallet
insufficient_lightning_balanceInsufficientFundsErrorNot enough Lightning balance
network_timeoutNetworkErrorRequest timed out
endpoint_unreachableNetworkErrorEndpoint unreachable
blockchain_errorNetworkErrorBlockchain RPC or transaction error
protocol_detection_failedProtocolErrorNo payment protocol detected
protocol_not_supportedProtocolErrorRequested protocol adapter not available
payment_failedProtocolErrorPayment not accepted by server (may include diagnosis)
no_compatible_chainProtocolErrorNo chain overlap between endpoint and SDK
x402_payment_failedProtocolErrorx402 payment execution failed
x402_quote_failedProtocolErrorx402 quote extraction failed
l402_payment_failedProtocolErrorL402 payment execution failed
l402_quote_failedProtocolErrorL402 quote extraction failed
l402_detection_failedProtocolErrorL402 protocol detection failed
l402_credentials_missingProtocolErrorL402 detected but no NWC connection string
cdp_provisioning_failedProtocolErrorCDP wallet provisioning failed

Catching errors

By class (instanceof)

try {
  const response = await sdk.fetch('https://invy.bot/api');
} catch (error) {
  if (error instanceof BudgetExceededError) {
    console.log(`Budget: ${error.requested.toDisplayString()} exceeds ${error.limit.toDisplayString()}`);
  } else if (error instanceof InsufficientFundsError) {
    console.log('Wallet needs more USDC');
  } else if (error instanceof ConfigurationError) {
    console.log('Check your API keys');
  } else if (error instanceof ProtocolError) {
    console.log(`Protocol error: ${error.code}`);
  } else if (error instanceof NetworkError) {
    console.log('Network issue, retrying...');
  } else if (error instanceof BoltzPayError) {
    console.log(`SDK error [${error.code}]: ${error.message}`);
  } else {
    throw error;
  }
}

By code (switch)

try {
  await sdk.fetch(url);
} catch (error) {
  if (error instanceof BoltzPayError) {
    switch (error.code) {
      case 'daily_budget_exceeded':
      case 'monthly_budget_exceeded':
        console.log('Budget exhausted — wait for reset');
        break;
      case 'per_transaction_exceeded':
        console.log('This endpoint is too expensive');
        break;
      case 'missing_coinbase_credentials':
        console.log('Configure Coinbase keys to enable payments');
        break;
      case 'insufficient_usdc':
        console.log('Fund your wallet with USDC');
        break;
      default:
        console.log(`${error.code}: ${error.message}`);
    }
  }
}

Constants

export const VERSION = "0.1.1";