What you will build
An AI agent with its own USDC wallet on Base. By the end the agent can pay any endpoint that speaks x402, settled in USDC, bounded by a spend limit you set once. The wallet is provisioned for you, so there is no seed phrase to store and no key for your agent code to hold. You create the agent, the wallet comes with it, and you fund it.
This is the starting point for everything else. Once an agent has a wallet, paying for tools, paying other agents, and receiving payments are all small additions on top. The agent wallets product page is the broader reference.
Why a per-agent wallet
You could give every agent in your system one shared wallet and a shared key. Do not. The wallet is where money, identity, and risk meet, and binding it to a single agent buys you three things that a shared wallet throws away.
First, isolation. A prompt injection that hijacks one agent can only spend that agent's balance and only up to that agent's limit. The rest of your fleet keeps running with their budgets intact. With a shared wallet, one compromised agent puts the whole balance at risk.
Second, attribution. When the dashboard shows spend per agent, you can see which agent costs what and tune each one. A shared wallet collapses every agent's activity into one untraceable stream, and you lose the ability to price or debug per agent.
Third, identity. Each agent gets its own public profile that a counterparty can check before accepting a payment. A shared wallet has one identity for many behaviors, which is exactly the ambiguity a careful payee distrusts. One agent, one wallet, one reputation.
Prerequisites
Have these ready:
- A Blockchain0x account.
- A
sk_test_API key for this walkthrough. Switch tosk_live_when you ship. - Node 18 or newer. The SDK targets
>=18.
Set the key where your code reads env:
export B0X_API_KEY=sk_test_... # sk_test_ -> Base Sepolia, sk_live_ -> Base mainnetCreate the agent and its wallet
Creating the agent provisions its wallet. One call.
import { createClient } from "@blockchain0x/node";
const client = createClient({ apiKey: process.env.B0X_API_KEY! });
const agent = await client.agents.create({ name: "research-agent" });
console.log(agent.id, agent.network); // e.g. agt_..., "testnet"The returned agent carries its id and the network the key pins it to. Hold onto the id; every later call (reading the spend limit, looking the agent up) keys off it. You did not touch a private key, and you will not. The wallet is bound to this agent and signs on its behalf when it pays.
Confirm the wallet is live
The wallet is deployed on chain a moment after you create the agent. Blockchain0x signals that with a wallet.deployed webhook event. If you run a webhook endpoint, verify the delivery and watch for it:
import express from "express";
import { webhooks } from "@blockchain0x/node";
const app = express();
app.use(express.raw({ type: "application/json" }));
app.post("/webhooks/blockchain0x", (req, res) => {
const result = webhooks.verify({
headers: req.headers,
rawBody: req.body, // raw bytes, not parsed JSON
secret: process.env.B0X_WEBHOOK_SECRET!,
});
if (!result.ok) return res.status(400).json({ code: result.code });
if (result.eventType === "wallet.deployed") {
// the agent's wallet is live; it can now send and receive USDC
}
return res.status(200).end();
});No webhook yet? The dashboard shows the wallet status for the agent, and a new wallet is usually ready within a few seconds. The agent's public profile lives at https://wallet.blockchain0x.com/a/{slug}, which is also where you copy the wallet address to fund it.
Fund it on Base Sepolia
A sk_test_ agent settles on Base Sepolia. Copy the wallet address from the dashboard (or the public profile) and send it test USDC from a public Base Sepolia USDC faucet. That balance is what the agent spends when it pays. On mainnet, you fund the same way from your own treasury instead of a faucet.
Fund a small amount first. You want enough to exercise a few real payments, not your whole budget, while you are still validating the flow. A few dollars of test USDC covers hundreds of typical sub-cent calls, which is plenty to prove the loop works before you trust it with real money. If a payment later fails for insufficient balance, the symptom is a non-2xx from the paid call rather than a crash, so treat a sudden run of failures as a signal to check the wallet balance first, the same way you would check a credit-card balance before assuming the merchant is down.
Let the agent pay
With a funded wallet, the agent pays any x402 endpoint through the x402 client. The client turns an HTTP 402 into a settled payment and a retried request.
import { createX402Client } from "@blockchain0x/x402/client";
const fetchWithPay = createX402Client({ sdk: client });
// On a 402, fetchWithPay builds the X-Payment: exact-usdc:<base64> header,
// settles in USDC, and re-issues the request. You await the final Response.
const res = await fetchWithPay("https://api.example.com/paid-endpoint");That is the whole pay path. Wrap fetchWithPay inside whatever calls the endpoint, an agent tool, a background job, a script, and the agent pays without a human in the loop. The framework-specific versions are in how-to-add-payments-to-langchain-agent.
The same wallet can also receive. The agent's public profile at wallet.blockchain0x.com/a/{slug} is where another agent or a person sends it USDC, and incoming payments surface as a payment.received webhook event you verify the same way as wallet.deployed. So one wallet handles both directions: it pays the endpoints your agent calls, and it collects when your agent is the one being paid. You do not set up a second wallet for the receive side.
Set a spend limit
A funded, autonomous wallet needs a ceiling. You set the limit in the dashboard, where the wallet enforces it server-side before any payment, which is the one place a prompt injection cannot reach. Read it back to confirm what is enforced:
const res = await fetch(
`https://api.blockchain0x.com/v1/agents/${agent.id}/spend-permissions`,
{ headers: { Authorization: `Bearer ${process.env.B0X_API_KEY!}` } },
);
const permissions = await res.json();
// allowance_wei, per_tx_wei, period_seconds (86400 / 604800 / 2592000), start_at, end_atThe full treatment of caps and periods is in how-to-set-up-agent-spending-limits. Do not skip it. An agent with a wallet and no limit is one bad input away from spending everything you funded.
Common pitfalls
Three traps worth knowing on day one.
Funding before the wallet is live. Sending USDC to an address you copied before the wallet.deployed event can mean sending to a wallet that is not ready. Wait for the event or the dashboard status, then fund.
Creating one agent and sharing it everywhere. One agent, one wallet, one limit. If you reuse a single agent for three different jobs, you lose per-job budgets and per-job audit. Create an agent per job instead.
Putting a sk_live_ key in a test run. The key prefix decides the chain. A live key on testnet code, or the reverse, is rejected by the server with apikey.network_mismatch. Check the prefix at boot.
What to ship today
Create one agent, wait for its wallet.deployed event, fund it with a few test dollars, and make one paid call through fetchWithPay. That is a working agent wallet end to end. Then set a spend limit before you move the key from sk_test_ to sk_live_. Pricing for production is on the pricing page; the Free tier covers everything here.