Agents need wallets, and the single most important property of an agent wallet is that nobody else ever sees the private key — not a SaaS, not a marketplace, and not Agent402. This guide is the flow we test in CI end to end: a keypair born inside the test runner completes a real x402 purchase, and the run fails if the key ever appears in any log.
transferWithAuthorization: your agent signs an off-chain
authorization and the facilitator pays the gas. A fresh wallet needs
only USDC — no ETH, ever.import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
const pk = generatePrivateKey(); // stays on YOUR machine
const account = privateKeyToAccount(pk);
console.log("agent address:", account.address); // the ONLY thing you share
Store pk in your secret manager (env var, keychain, KMS) — never in
code, never in git. If you prefer managed custody, Coinbase's
Embedded Wallets give end users
email-login wallets where you never handle keys at all; everything below
works the same since only addresses are exchanged.
Fund the new address with testnet USDC via the paid
testnet-fund tool — a tenth of a cent buys a
full testnet dollar from the Coinbase faucet:
curl -X POST https://agent402.tools/api/testnet-fund \
-H "Content-Type: application/json" \
-d '{"address":"<your agent address>","token":"usdc"}'
Then point your x402 client at any base-sepolia seller (or run the
open-source Agent402 server locally with NETWORK=base-sepolia) and
make a paid call:
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { wrapFetchWithPayment } from "@x402/fetch";
const client = new x402Client();
registerExactEvmScheme(client, { signer: account });
const payFetch = wrapFetchWithPayment(fetch, client);
const res = await payFetch("http://localhost:3000/api/hash", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: "first paid call" }),
});
// The PAYMENT-RESPONSE header carries the on-chain settlement tx.
When the rehearsal settles, fund the same address with real USDC on Base. Two ways:
onramp-link mints a
single-use Coinbase Onramp URL for your agent's address with a
fee-inclusive quote. Open it, pay, done.Verify with wallet-balances, then the same
buyer code works against every seller in the index — and every
tool here. Budget guardrails: the
agent402-mcp server adds
pre-signature spend controls (per-call and per-session caps) on top.
The exact flow above runs in our CI as a gated test: a fresh keypair is generated inside the runner, faucet-funded, and completes a real x402 settlement against a paid-mode server — then the test scans every byte of its own output and the server's full log for the key material (all prefix/case forms) and fails on any hit. Keys in, addresses out, provably.