Skip to main content
HomeLanding pagesHow to receive payments as an AI agent
LANDING PAGE

How to receive payments as an AI agent

8 min read·Last updated June 2, 2026

An AI agent receives USDC two ways. Passively: funds sent to its wallet on Base arrive and a payment.received webhook fires, which you verify with webhooks.verify. Actively: gate the agent's HTTP endpoint with createX402Plugin or createX402Middleware from @blockchain0x/x402, which returns a 402 and verifies the X-Payment header through paymentRequests.settle before serving. Both settle in USDC; the agent never holds keys.

What you will build

An AI agent that gets paid in USDC on Base. Maybe it earns tips, maybe it receives payouts from a system you run, maybe it sells a service and charges per call. All three are the same underlying capability: the agent has a wallet, USDC arrives in it, and you find out when it does. By the end you can both receive money passively and charge for a service actively, with verification you can trust.

If your agent does not have a wallet yet, start with how-to-add-wallet-to-my-agent. The payment API product page is the broader reference.

Two ways an agent gets paid

It is worth separating these up front, because they need different code.

The first is passive receipt. Someone, a person or another agent, sends USDC to your agent's wallet address. You did not gate anything; the money simply arrives, and you want to know when. This is the shape for tips, payouts, treasury transfers, and any case where the decision to pay was made elsewhere.

The second is active charging. Your agent offers a service over an HTTP endpoint, and you want callers to pay before they get a result. Here you put a paywall in front of the endpoint so an unpaid request gets a 402 and a paid one gets the response. This is the shape for an agent that sells research, generation, lookups, or any per-call product.

Most agents start with the first and add the second when they have something worth charging for.

Prerequisites

  • A Blockchain0x account with one agent created, so it has a wallet.
  • A sk_test_ API key for this walkthrough.
  • Node 18 or newer. The SDK targets >=18.
BASH
export B0X_API_KEY=sk_test_...        # sk_test_ -> Base Sepolia
export B0X_WEBHOOK_SECRET=...         # the webhook signing secret, shown once when you create the webhook

Receive directly to the wallet

Passive receipt needs almost nothing from you. The agent's wallet has an address on Base, shown in the dashboard and on the agent's public profile at wallet.blockchain0x.com/a/{slug}. Anyone who sends USDC to that address on the right network credits the agent's balance. On a sk_test_ agent that is Base Sepolia; on sk_live_ it is Base mainnet.

The public profile is also where a counterparty checks the agent before paying it. The verification badges on that page, email, GitHub, and domain, are what turn an address into something a careful payer trusts. If your agent will receive money from strangers, earn those badges early; they materially change whether a first-time payer goes through with it.

Watch for incoming payments

You want to act when money arrives, so subscribe to the payment.received webhook and verify every delivery. Verify against the raw bytes, never the parsed JSON, because the HMAC is computed over exactly what arrived.

TYPESCRIPT
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
    secret: process.env.B0X_WEBHOOK_SECRET!,
  });
  if (!result.ok) return res.status(400).json({ code: result.code });

  if (result.eventType === "payment.received") {
    const payload = JSON.parse(req.body.toString("utf8"));
    creditAgentLedger(payload); // your logic: thank the payer, release work, update a balance
  }
  return res.status(200).end();
});

The verifier rejects deliveries more than five minutes old, which kills replay attempts, so you do not have to dedupe by timestamp yourself. payment.received is the inbound event; payment.sent is the one for payments the agent makes.

Charge callers for a service

When the agent sells something per call, gate its endpoint with the x402 server adapter. The adapter answers a 402 with your price and verifies payment on the retry, before your handler runs.

TYPESCRIPT
import Fastify from "fastify";
import { createClient } from "@blockchain0x/node";
import { createX402Plugin } from "@blockchain0x/x402/server/fastify";

const sdk = createClient({ apiKey: process.env.B0X_API_KEY! });
const app = Fastify();

await app.register(createX402Plugin, {
  sdk,
  defaultNetwork: "testnet",
  pricing: {
    "POST /agent/answer": {
      amountUsdc: "0.02",
      payToAddress: process.env.B0X_PAYTO_ADDRESS!, // the agent's wallet
      paymentRequestId: process.env.B0X_PRICE_REQUEST_ID!,
    },
  },
});

app.post("/agent/answer", async (req) => runAgentTask(req.body)); // only runs once paid
await app.listen({ port: 8080 });

Express works the same way with createX402Middleware. Pricing is per route, so put each priced service on its own path and leave anything free, like a health check or a capability listing, on an unpriced one.

Verify a payment server-side

The property that makes charging safe is that the adapter never trusts the caller's claim. On the retry it reads the X-Payment header and calls paymentRequests.settle to confirm the on-chain transfer matches the quoted requirement: right amount, right network, right payment request. Only a confirmed payment reaches your handler; a missing, malformed, or mismatched one is rejected with a fresh 402 and a reason you can log (header_missing, requirement_mismatch, settle_rejected, and a few others).

This is the same discipline a card processor's webhook verification gives you, and you get it without writing the verification yourself. Do not be tempted to trust a caller's "I paid" to save a round trip; that shortcut is how paid services leak revenue.

Reconcile what arrived

Webhooks tell you about payments as they happen, but you also want a way to look one up after the fact, for a support question, a refund decision, or a nightly reconciliation job. Read a single payment by its id:

TYPESCRIPT
const tx = await client.transactions.get("txn_...");
// tx carries the canonical record for that transaction: status, amount, and identifiers

Treat the webhook as the trigger and the transaction record as the source of truth. A dependable receive pipeline does both: it reacts to payment.received in real time for the fast path, and it reconciles against the transaction record on a schedule so a missed or delayed webhook never leaves your ledger wrong over the long run. The two together are what lets you answer "did this specific payment land, and for how much" with confidence weeks later, rather than trusting an event you may or may not have processed. Keep the transaction id from the webhook payload so the lookup is a direct fetch rather than a search.

Common pitfalls

Three traps on the receive side.

Verifying the parsed body instead of the raw bytes. The HMAC is over the exact bytes. If a JSON middleware parses the body before you read it, the signature will not match. Mount the raw-body parser on the webhook route.

Receiving on the wrong network. A sk_test_ agent's wallet is on Base Sepolia. USDC sent on the wrong chain does not arrive. Confirm the network before you share an address with a payer.

No identity on a public-facing agent. An agent receiving money from strangers with a bare address and no verification badges converts poorly. Earn the badges on the public profile before you promote the address.

What to ship today

Subscribe to payment.received, verify it with webhooks.verify, and send your test agent a dollar of test USDC to watch the event land. If the agent sells a service, gate one route with the adapter and confirm an unpaid call gets a 402. Then earn the verification badges before you put the address in front of real payers. Production pricing is on the pricing page.

FAQ

Frequently asked questions.

Does my agent need to hold crypto keys to get paid?

No. The wallet is provisioned and managed for the agent, so receiving is just funds arriving at the agent's address on Base. You watch for them with a webhook and read balances through the API. There is no seed phrase for your code to hold, and no signing involved on the receive side.

What is the difference between receiving and charging?

Receiving is passive: someone sends USDC to the agent's wallet and you find out via a payment.received event. Charging is active: you put the x402 server adapter in front of the agent's endpoint so callers must pay before they get a response. Use receiving for tips, payouts, and transfers; use charging when the agent sells a service per call.

Which webhook event fires when my agent is paid?

payment.received. Verify the delivery with webhooks.verify, check result.eventType, and then read the parsed body. The verifier also rejects replays older than five minutes, so a late or duplicated delivery does not double-count. payment.sent is the opposite direction, for payments the agent makes.

How do callers know what to pay?

When you gate an endpoint, the adapter answers a 402 with the exact requirement: the exact-usdc scheme, the network, your payToAddress, and amountWeiUsdc in 6-decimal base units. Any caller whose runtime speaks x402 reads that, pays, and retries with an X-Payment header. You set the price in the adapter's pricing table per route.

Can one agent both pay and get paid?

Yes, with one wallet. The same agent wallet that pays endpoints through createX402Client can receive USDC and can charge callers through the server adapter. You do not run separate wallets for the two directions; the agent is a full economic actor with a single balance and a single identity.

Create your free agent wallet in 5 minutes.

First payment confirmed in under ten minutes. Free to start.