Skip to content

x402

x402 lets an HTTP API ask for payment with a 402 response. The client pays with a signed stablecoin transfer and retries. HalvorAI records both sides: the agent paying, and the server being paid.

HalvorAI works with the x402 Foundation packages for protocol version 2:

RolePackage
Client fetch wrapper@x402/fetch
Client core and EVM scheme@x402/core, @x402/evm
Hono resource server@x402/hono
Express resource server@x402/express

The three headers carry base64-encoded JSON:

HeaderDirectionContains
PAYMENT-REQUIREDserver to clientWhat the server wants, the PaymentRequired object
PAYMENT-SIGNATUREclient to serverThe signed PaymentPayload
PAYMENT-RESPONSEserver to clientThe SettlementResponse

Wrap the inner fetch, so the retry that carries PAYMENT-SIGNATURE is seen:

import { wrapFetchWithPayment } from '@x402/fetch';
import { HalvorClient, withAgentContext } from '@halvorai/ingest';
import { withHalvor } from '@halvorai/ingest/x402';
const halvor = new HalvorClient();
const fetchPaid = wrapFetchWithPayment(withHalvor(fetch, halvor), x402Client);
await withAgentContext(
{
agent: { id: 'agt_research_07' },
owner: { id: 'own_acme_ltd', type: 'business' },
instruction: { id: 'ins_5521', text: 'Pull the latest EU power prices' },
},
async () => {
const res = await fetchPaid('https://api.example.com/premium-data');
},
);

withHalvor observes each request and emits:

It seesIt emits
A 402 with PAYMENT-REQUIREDpayment.requested
A request carrying PAYMENT-SIGNATUREpayment.authorized, with the decoded payload as x402.payment_payload evidence
A response with PAYMENT-RESPONSE and successpayment.settled, with the x402.settlement evidence
A response with PAYMENT-RESPONSE and a failurepayment.failed, with failure_reason from the settlement’s error reason

A header it cannot decode is reported to onError and the request continues untouched.

If you sell an API to agents, observe the same headers on your side:

import { paymentMiddleware } from '@x402/hono';
import { halvorX402Hono } from '@halvorai/ingest/x402';
app.use('*', halvorX402Hono(halvor, {
payee: {
name: 'Example Market Data',
wallet: { network: 'eip155:8453', address: '0x209693Bc6afc0C5328bA36FaF03C514EF312287C' },
resource_url: 'https://api.example.com/premium-data',
},
}));
app.use('*', paymentMiddleware(/* your x402 configuration */));

halvorX402Express(halvor, options) does the same for Express. Events use the x402-server adapter and your options as the payee. The agent id is taken from Visa TAP or x402 extension data when the request carries it, and otherwise from the payer’s wallet address.

x402APE
resource.urlpayee.resource_url
payTopayee.wallet.address, with payee.type set to api_provider when a resource is named
network (a CAIP-2 id such as eip155:8453)payment.rail_ref.network, the asset network and the payee wallet network
assetthe asset address
amountpayment.amount.value, in atomic units
schemepayment.rail_ref.scheme
authorization.noncepayment.rail_ref.nonce
authorization.frominstrument.wallet.address
settlement transactionpayment.rail_ref.tx_hash

The payment id is x402:<network>:<nonce>, so the three events of one payment link together.

Amounts are integers in atomic units. For USDC, which has six decimals, "10000" is 0.01 USDC. HalvorAI converts pegged stablecoins to US dollars for reports.

On a test network such as Base Sepolia, make one payment and open Payments. You should see payment.requested, payment.authorized and payment.settled for the same payment id, and the settlement evidence in the drawer. A failed settlement shows as payment.failed with the facilitator’s reason.