@aioum/sdk

Mirrored from packages/sdk/README.md in the repository — edit that file, not this page.

Payment rails for autonomous agents. Give an agent one budget-capped key and it pays for exactly the tools, models, and APIs it calls — per request, settled on-chain, with no human signing each transaction. No API keys, no subscriptions.

Framework-agnostic: just viem. Runs in Node (agents, servers, cron) and the browser.

npm install @aioum/sdk viem

Quick start

import { AIOUMClient, devnet } from "@aioum/sdk";

// Point at a network: load your local development network's deployments, or pass an explicit config.
const aioum = new AIOUMClient(await devnet("./deployments.json"));

// Discover what's for sale — filtered + ranked by reputation, then price.
const services = await aioum.discover({ category: "search", maxPrice: "0.01" });

// Authorize ONCE: a budget-capped session key. The agent can never spend past the cap.
const agent = await aioum.createAgent({
  ownerKey: process.env.OWNER_KEY as `0x${string}`,
  budget: "10 USDC",
  expiresIn: "24h",
});

// Pay per call — autonomously, no per-call signing.
const res = await agent.call("web.search", { query: "the x402 spec" });
console.log(res.text, "·", agent.remaining, "left");

await agent.revoke(); // kill the key any time (owner-signed)

Session reuse (make micro-payments economical)

agent.call() opens a fresh on-chain session (a full ERC-4337 UserOp + a settle) for every call — simple, but the gas/latency dwarfs a sub-cent payment. For repeated calls to the same service, open a session once and pay per call with cheap client-signed incrementing-cumulative-amount vouchers (no chain round trip), then settle once:

const session = await agent.openSession("web.search", { deposit: "1 USDC" });

const a = await session.call({ query: "erc-4337" });   // signs cumulative = price
const b = await session.call({ query: "erc-1271" });   // signs cumulative = 2·price ...
console.log(session.spent, "spent,", session.callsRemaining, "calls of headroom left");

await session.close();   // ONE on-chain settle for all calls; unspent deposit refunds

session.settle() redeems on demand mid-session; session.reclaim() is the liveness backstop (owner- signed) if the node never settles. agent.call() stays available for one-offs.

Refunds

Escrowed funds you didn't spend come back automatically when a session settles (you authorize each amount, so a node can only ever redeem what you signed). Two explicit paths for the unhappy cases:

await agent.reclaim(sessionId);  // node went dark → reclaim the unspent deposit (after inactivityTimeout)
await agent.withdraw();          // pull a refund that was escrowed because a direct push failed

Discovery across many nodes

aioum.discover() sees one node's catalogue. To span a marketplace, fan out over a set of nodes (or a registry/subgraph endpoint that lists them); results are tagged with their nodeUrl and ranked globally:

import { discoverAcross } from "@aioum/sdk";
const svcs = await discoverAcross({ nodes: [nodeA, nodeB], registryUrl, category: "search" });

How it works

  1. createAgent runs the one-time owner-signed setup: deploy an ERC-4337 smart account (counterfactual address), fund it, approve the PaymentManager, and authorize a budget-capped, expiring session key. Where the network's paymaster only sponsors billing-signed operations, it also keeps a small ETH gas deposit on the account (gasDeposit). Each step is idempotent — a retry resumes.
  2. agent.call opens a payment session through the bundler (no owner signature; gas sponsored by the paymaster, or paid from the account's own deposit), signs a per-call EIP-712 voucher with the session key, invokes the node's tool, and settles on-chain. You pay for exactly what you received. (A session-key voucher is settled via the smart account's ERC-1271 isValidSignature, so the SDK wraps it as the enriched abi.encode(sessionId, cumulativeAmount, innerSig) the account expects — handled for you by signEnrichedVoucher.)
  3. Because every amount is client-signed, a node can only ever redeem what the agent authorized — funds sit in escrow and the unused budget refunds. You can't be overcharged.

Configuration

import { AIOUMClient, fromDeployments, type AIOUMConfig } from "@aioum/sdk";

const config: AIOUMConfig = {
  chainId: 8453,
  rpcUrl: "https://...",
  nodeUrl: "https://node.example.com",
  bundlerUrl: "https://bundler.example.com",
  addresses: { payment, usdc, accountFactory, entryPoint, paymaster },
};
const aioum = new AIOUMClient(config);

fromDeployments(json, overrides?) builds a config from a deployments object; devnet(path) reads your local development network's deployments.json and fills in its Anvil endpoints.

API

  • new AIOUMClient(config) — discover(opts?), createAgent(opts), accountAddress(owner).
  • AIOUMAgent — call(ref, args, { tool? }), openSession(ref, { deposit? }) → PaidSession, reclaim(sessionId), withdraw(), budget(), revoke(); getters address, cap, remaining, spentAmount, expiresAt, isExpired().
  • PaidSession — call(args, { tool? }), settle(), close(), reclaim(), onchain(); getters spent, remaining, callsRemaining, pricePerCall, isClosed.
  • Multi-node: discoverAcross({ nodes?, registryUrl?, ...filters }) → services tagged with their nodeUrl.
  • Low-level building blocks are exported too: setupSmartAccount, openSession, signVoucher, signEnrichedVoucher, encodeEnrichedVoucherSignature, remainingBudget, revokeSessionKey, discover.

The control client: everything the app does, in code

AIOUMControl is the layer the aioum CLI and the @aioum/mcp server are built on: one method per route of the indexer, the agent runner, the catalogue node, the staking node, the deposit service and your private node, configured from the AIOUM_* environment.

import { AIOUMControl, controlFromEnv, readEvents } from "@aioum/sdk";

const c = new AIOUMControl(controlFromEnv());          // AIOUM_INDEXER_URL, AIOUM_AGENTS_URL, … with local defaults
const { services } = await c.status();                  // every part of the stack probed
const agent = await c.agentCreate({ name: "Brief", mode: "assistant", instructions: "…", access: "prefer",
  skills: ["anthropics-skills-skills-pdf"], budget: { capUsdc: 5, perRunMaxUsdc: 0.25 } });
const run = await c.agentRun(agent.id, "Today's brief", { wait: true });
await c.runWatch(run.id, (ev) => console.log(ev.event, ev.data));   // the live stream: step, now, done
const spend = await c.agentSpend(agent.id, "24h");                  // per service, per day
  • Monitoring status, activity, wallets.
  • Marketplace services, service, serviceDemand, operator, refreshIndex, tools, pay (one paid call through a budget-capped session key).
  • Reviews reviewRequest (asks the runner to review a listing, by serviceId or nodeUrl and key; wait follows it to its end, onState; budgetUsdc: a budget of your own, signed by your wallet, for the listing's operator or the runner's owner), reviewStatus, reviews, reviewsBackfill.
  • Agents superAgent(prompt, budgetUsdc) (prompt first: the Super Agent from a prompt, started), agentList, agentGet, agentCreate (budget with both caps required), agentUpdate, agentDelete, agentRun, agentSchedule, agentPublish, agentUnpublish, starters, starterCreate(id, budget), pipelineCreate(id, { budgetUsdc, agentBudgetsUsdc, … }), planners, skills, skill.
  • Runs and spend runs, runGet, runStop, runWatch, projectWatch, runSpend, agentSpend, projectSpend; readEvents and parseFrame for the event stream.
  • Projects projectList, projectGet, projectCreate, projectStart, projectPause, projectResume, projectStages, projectDelete.
  • Selling sellTemplates, sellPreview, sellAdd, sellSkillUpload, sellList, sellRemove, sellVerifyDomain.
  • Staking and the staking node stakeOperators, stakePositions, stakeDelegate, stakeClaim, stakeUndelegate, stakeWithdraw, backerHealth, stakeRequest (follows the review to its final state; onState), stakeRequestGet, stakeRequests.
  • Jury juryStatus, juryJoin, juryLeave, juryWithdraw, juryCases, juryCommit, juryReveal, juryFinalize, juryEscalate, juryClaimReward (the salt store is a SaltStore; MemorySaltStore by default).
  • Deposits aiWallet, depositHealth, depositChains, depositTokens, depositAddress, depositQuote, depositSend, depositRecord, deposits, depositGet, depositSweep, depositCardPartners, depositCard.
  • Private node nodeHealth, nodeConnections, nodeConnect, nodeDisconnect, nodeTools, nodeCall, nodeMemoryAdd, nodeMemoryList, nodeMemoryDelete, nodeForgetAll, nodeSchedules, nodeScheduleCreate, nodeScheduleRun, nodeScheduleToggle, nodeScheduleDelete, nodeBackupExport, nodeBackupRestore.

Errors are ControlError with the HTTP status and body. Types: ControlConfig, ServiceRecord, AgentSpecInput, ProjectSpecInput, BackRequestRecord, Review, ReviewState, DepositQuote, DepositRecord, RunnerEvent, SpendPeriod and the rest are exported beside them.

License

MIT