# Invoices for AI agents (x402)

> Every invoice has an x402Url that an AI agent pays with a stock x402 client: the price in USDC or EURC on Base, no browser, no network fee for the agent.

Every invoice comes with two links:

- `paymentPageUrl`: the hosted payment page, for people.
- `x402Url`: the same invoice for **AI agents** and any other [x402](https://www.x402.org/) 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](https://docs.cryptonly.net/guides/invoices/statuses.md), you get the same `invoice.statusChanged` webhooks, and the same commission applies. The invoice says how it was paid in `paymentChannel` (`x402` or `address`).

## How an agent pays

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](https://docs.cryptonly.net/guides/onchain-confirmations.md) of its network.

<Aside type="caution">
The agent's `200` means the transfer is on chain, not that the invoice is paid. Fulfil the order on the `invoice.statusChanged` webhook with status `paid` (or `overpaid`), as for every invoice.
</Aside>

## Accepted assets

| Network | Assets |
| --- | --- |
| Base (`eip155:8453`) | USDC, EURC |

The sandbox uses Base Sepolia with the [test assets of x402](https://docs.cryptonly.net/guides/x402.md#networks-and-assets). 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.

## Example agent

Any x402 v2 client works. With [`@x402/fetch`](https://www.npmjs.com/package/@x402/fetch):

```ts

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' });
```

<Aside>
Stock x402 clients cap every payment at **$1** by default. An agent that pays invoices must raise `maxAmountPerPayment`, and allow EURC if it pays in it.
</Aside>

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.

## Responses

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

## Turning it off

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`.

## Related pages

- [Invoice statuses](https://docs.cryptonly.net/guides/invoices/statuses.md): Which statuses to fulfil on
- [x402 payments](https://docs.cryptonly.net/guides/x402.md): Charge for your own API with x402
- [Webhooks](https://docs.cryptonly.net/api-reference/webhooks.md): invoice.statusChanged verification and payloads
