402.md

@402md/client

Agent SDK reference for building AI agents with USDC wallets

Installation

npm install @402md/client

createAgent(config)

import { createAgent } from '@402md/client'

const agent = createAgent({
  wallet: {
    privateKey: process.env.AGENT_WALLET_KEY!,
    network: 'base'
  },
  budget: {
    daily: '100.00',
    perTransaction: '50.00'
  }
})

AgentConfig

FieldTypeRequiredDescription
wallet.privateKeystringYesHex private key for USDC wallet
wallet.network'base' | 'base-sepolia'NoNetwork. Defaults to 'base-sepolia'
budget.dailystringNoMax USDC per day (e.g. '100.00')
budget.perTransactionstringNoMax USDC per transaction (e.g. '50.00')
apiBaseUrlstringNoOverride API URL. Defaults to 'https://api.402.md'

Methods

agent.call(skill, path, options?)

Call a paid API endpoint. Handles x402 payment automatically.

const result = await agent.call('sentiment-api', '/analyze', {
  method: 'POST',
  body: { text: 'Hello world' },
  headers: { 'X-Custom': 'value' }
})

Flow: request → 402 response → check budget → sign payment → retry with X-402-Payment header → return response.

CallOptions

FieldTypeRequiredDescription
bodyunknownNoRequest body (JSON-serialized)
headersRecord<string, string>NoAdditional request headers
methodstringNoHTTP method. Defaults to 'GET'

Returns: Promise<unknown> — the API response body.

agent.subscribe(skill)

Subscribe to a SaaS service.

const sub = await agent.subscribe('analytics-dashboard')

Returns: Promise<SubscriptionResult>

interface SubscriptionResult {
  ticket: string      // JWT access ticket
  accessUrl: string   // URL to access the service
  expiresAt: string   // ISO 8601 expiration
}

agent.purchase(skill, path, options?)

Purchase a product.

const order = await agent.purchase('store', '/buy/SKU-001', {
  quantity: 2,
  shipping: {
    name: 'Jane Doe',
    address: '456 Oak Ave',
    city: 'Austin',
    state: 'TX',
    zip: '73301',
    country: 'US'
  }
})

PurchaseOptions

FieldTypeRequiredDescription
quantitynumberNoNumber of items
shipping.namestringNoRecipient name
shipping.addressstringNoStreet address
shipping.citystringNoCity
shipping.statestringNoState/province
shipping.zipstringNoZIP/postal code
shipping.countrystringNoCountry code

Returns: Promise<PurchaseResult>

interface PurchaseResult {
  orderId: string   // Order identifier
  status: string    // Order status
  txHash: string    // On-chain transaction hash
}

agent.search(query)

Search for available skills on 402.md.

const results = await agent.search('image generation')

Returns: Promise<SearchResult>

interface SearchResult {
  skills: Array<{
    name: string
    description: string
    pricing: {
      model: string   // 'per_call', 'subscription', etc.
      price: string   // Price in USDC
    }
    category: string
  }>
}

agent.getBalance()

Returns the current USDC balance of the agent's wallet.

const balance = await agent.getBalance() // '847.50'

Returns: Promise<string> — USDC balance as a decimal string.

agent.getSpentToday()

Returns the total USDC spent today (tracked locally).

const spent = agent.getSpentToday() // 52.5

Returns: number — total spent today as a number.

getSpentToday() returns a number, not a string. It tracks spend locally based on transactions signed during the current process.

agent.address

Getter that returns the agent's wallet address.

console.log(agent.address) // '0x742d...5f0b'

Returns: string

Budget enforcement

The SDK enforces spending limits locally before signing any transaction:

  • perTransaction — checked first. If the payment amount exceeds this limit, an error is thrown immediately.
  • daily — checked second. If cumulative spend today + the new payment would exceed this limit, an error is thrown.

Daily spend resets at midnight (local time). Spend is tracked in-memory — restarting the process resets the counter.

try {
  await agent.call('expensive-api', '/endpoint')
} catch (err) {
  if (err.message.includes('budget') || err.message.includes('limit')) {
    console.log('Budget exceeded:', err.message)
  }
}

No USDC is spent when a budget error is thrown — the check happens before the payment is signed.

Wallet utilities

The client package also exports lower-level wallet functions:

createWalletClient(privateKey, network?)

Creates viem wallet and public clients from a private key.

import { createWalletClient } from '@402md/client'

const clients = createWalletClient('0xabc...', 'base')
// { wallet, public, network, address }

signPayment(clients, amount, recipient)

Signs a USDC transfer and returns the transaction hash and encoded payment header.

import { signPayment } from '@402md/client'

const { txHash, payment } = await signPayment(clients, '0.05', '0x742d...')
// payment is a Base64-encoded JSON string for the X-402-Payment header

getBalance(clients)

Queries the on-chain USDC balance.

import { getBalance } from '@402md/client'

const balance = await getBalance(clients) // '847.50'