@aioum/sdk
Mirrored from
packages/sdk/README.mdin 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
createAgentruns 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.agent.callopens 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-1271isValidSignature, so the SDK wraps it as the enrichedabi.encode(sessionId, cumulativeAmount, innerSig)the account expects — handled for you bysignEnrichedVoucher.)- 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(); gettersaddress,cap,remaining,spentAmount,expiresAt,isExpired().PaidSession—call(args, { tool? }),settle(),close(),reclaim(),onchain(); gettersspent,remaining,callsRemaining,pricePerCall,isClosed.- Multi-node:
discoverAcross({ nodes?, registryUrl?, ...filters })→ services tagged with theirnodeUrl. - 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, byserviceIdornodeUrlandkey;waitfollows 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(budgetwith 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;readEventsandparseFramefor 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 aSaltStore;MemorySaltStoreby 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