Quickstart
Put a price on an HTTP endpoint, then pay for it from an agent. Both sides use the standard x402 v2 packages pointed at Arcus.
Sell an endpoint
Install the x402 server packages, register the exact EVM scheme for Arc and point the facilitator client at Arcus. Arc has no SDK default asset yet, so price routes with an explicit USDC amount.
- 1Installterminalsh
npm i express @x402/express @x402/core @x402/evm - 2Wrap a route with the payment middlewareserver.tsts
import express from 'express'; import { paymentMiddleware } from '@x402/express'; import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server'; import { ExactEvmScheme } from '@x402/evm/exact/server'; const facilitator = new HTTPFacilitatorClient({ url: 'https://facilitator.arcusnetwork.co', }); const server = new x402ResourceServer(facilitator) .register('eip155:5042', new ExactEvmScheme()); const app = express(); app.use(paymentMiddleware({ 'GET /weather': { accepts: { scheme: 'exact', network: 'eip155:5042', // Arc mainnet payTo: '0xYourMerchantAddress', price: { amount: '10000', // 0.01 USDC (6 decimals) asset: '0x3600000000000000000000000000000000000000', extra: { name: 'USDC', version: '2' }, }, }, description: 'Current weather', }, }, server)); app.get('/weather', (_req, res) => res.json({ temp: 24 })); app.listen(4021); - 3Check the 402
An unpaid request returns 402 with the price encoded in the PAYMENT-REQUIRED header.
terminalshcurl -i http://localhost:4021/weather # HTTP/1.1 402 Payment Required # PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Mi...
Order of operations inside the middleware: verify the payment, run your handler, then settle. If the handler throws or returns an error, nothing is settled and the buyer keeps their USDC.
Pay for one
Any x402 v2 client works. Arc USDC is not yet one of the SDK's default assets, so allowlist it in spendControls. The wallet only signs; it needs USDC on Arc and no gas.
npm i @x402/fetch @x402/evm viemimport { privateKeyToAccount } from 'viem/accounts';
import { x402Client, wrapFetchWithPayment } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm/exact/client';
const account = privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`);
const USDC = '0x3600000000000000000000000000000000000000';
// Arc USDC isn't an SDK default asset yet — allowlist it explicitly.
const client = x402Client.fromConfig({
schemes: [{ network: 'eip155:5042', client: new ExactEvmScheme(account) }],
spendControls: {
allowedAssets: [
{ network: 'eip155:5042', asset: USDC, maxAmountPerPayment: '1000000' }, // ≤ 1 USDC
],
},
});
const pay = wrapFetchWithPayment(fetch, client);
const res = await pay('https://api.example.com/weather');Prefer a smaller surface? The Arcus client package wraps this with a per-payment cap and a hard budget in one call.
Test on Arc testnet
Swap eip155:5042 for eip155:5042002 on both sides. The USDC address and EIP-712 domain are identical on both networks. Testnet USDC comes from the official Arc testnet faucet.
Pricing in USDC
Amounts are raw USDC units with 6 decimals: 10000 is 0.01 USDC and 1000000 is 1 USDC. The asset is the native USDC predeploy at 0x3600000000000000000000000000000000000000 and the EIP-712 domain is name USDC, version 2. Full details are on the Networks page.