Skip to content

Invoices for AI agents (x402)

Every invoice comes with two links:

  • paymentPageUrl: the hosted payment page, for people.
  • x402Url: the same invoice for AI agents and any other x402 client. An agent pays it with one HTTP request and a signature. It needs no browser, no wallet pop-up and no ETH for gas.

An x402 payment is an ordinary invoice payment. The invoice moves through the same statuses, you get the same invoice.statusChanged webhooks, and the same commission applies. The invoice says how it was paid in paymentChannel (x402 or address).

  1. The agent sends POST (or GET) to x402Url without payment.
  2. Cryptonly answers 402 Payment Required. The PAYMENT-REQUIRED header (base64 JSON, x402 v2) lists the price in each accepted stablecoin, each paid to the invoice’s own address.
  3. The agent signs a transfer for one of them and repeats the request with a PAYMENT-SIGNATURE header.
  4. Cryptonly checks the signature against the price it quoted, opens the invoice’s deposit, broadcasts the transfer, and pays the network fee.
  5. Cryptonly answers 200 once the transfer is on chain (202 if it was sent but is not mined yet), with a PAYMENT-RESPONSE header holding the transaction.

The invoice then turns processing and paid like any other payment, after the confirmations of its network.

NetworkAssets
Base (eip155:8453)USDC, EURC

The sandbox uses Base Sepolia with the test assets of x402. Invoice x402 links are Base only; customers who pay in USDT or on Solana use the payment page.

The 402 lists one entry per asset, with the stablecoin that matches the invoice currency first: EURC for a EUR invoice, USDC for a USD one. Stock clients pay the first entry they accept.

The price includes the network fee of the invoice’s deposit, as on the hosted page. Each quote holds for 10 minutes; a request after that gets a fresh one.

Any x402 v2 client works. With @x402/fetch:

import { wrapFetchWithPaymentFromConfig } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm/exact/client';
import { toClientEvmSigner } from '@x402/evm';
const pay = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: 'eip155:8453', client: new ExactEvmScheme(toClientEvmSigner(account, publicClient)) }],
// Stock clients refuse more than $1 and pay only USDC unless told otherwise.
spendControls: { allowedAssets: true, maxAmountPerPayment: '$100' },
});
const response = await pay(invoice.x402Url, { method: 'POST' });

To make retries safe, the agent can send the x402 payment-identifier extension with its own id. A repeated id, or a repeated signature, returns the first payment’s outcome and never pays twice.

StatusMeaning
402Payment required. After a refused payment, error and PAYMENT-RESPONSE say why; nothing was paid.
200The transfer is on chain, or the invoice was already paid (a receipt, nothing charged).
202The transfer was sent and is not mined yet, or a payment is being confirmed. Do not pay again.
302A browser opened the link: it is redirected to the payment page.
409The customer is paying on the payment page in a currency x402 cannot pay. Retry-After says when that attempt expires.
410The invoice can no longer be paid: expired, cancelled, partially paid, failed or suspended.
404Unknown invoice, or x402 is off for it.

If the customer already picked USDC or EURC on Base on the payment page, the agent is offered exactly that deposit. Once an agent has paid, the customer cannot switch currency or cancel, and you cannot cancel the invoice until the payment settles.

Create the invoice with "x402Enabled": false, or untick Let AI agents pay over x402 under Advanced options in the dashboard. The invoice then has no x402Url, and the link answers 404.