zunivo · the payment layer for ai agents on arc
x402 payments on Arc
Charge USDC per API call. Let AI agents pay for it autonomously — no card, no account, no human. Standard x402 on Arc's USDC-native chain.
server middlewareagent clientEIP-3009 facilitatorArc Testnet
What is this
x402 is the HTTP-native payment standard that revives the dormant 402 Payment Required status code. A server answers a request with 402 and a machine-readable price; a client attaches a signed payment and retries; the resource is served. It's governed by the Linux Foundation and backed by Coinbase, Circle, Visa, Stripe, and Google — tens of millions of agent payments already run on it.
But its facilitators cover Base, Polygon, Arbitrum, and Solana — not Arc. zunivo-x402-arc is that missing piece: it lets an x402-speaking agent pay for an API on Arc, using Arc's USDC-native gas and sub-second finality. Same standard the agent already knows; a new chain it can now pay on.
How x402 works
402 Payment Required with PaymentRequirements: price, token, recipient, network.X-PAYMENT header.X-PAYMENT-RESPONSE receipt header.Quickstart
# install
npm install zunivo-x402-arc
# run a paid API (needs a Zunivo API key from https://api.zunivo.io)
ZUNIVO_API=https://api.zunivo.io ZUNIVO_KEY=zk_… PAY_TO=you.zunivo npm run example:server
# in another terminal, an agent pays it — one command, one function
AGENT_PK=0x… npm run example:agent
Server — charge USDC per call
Three lines protect any Express route:
import express from "express";
import { paymentRequired } from "zunivo-x402-arc";
const app = express();
const pay = paymentRequired({
price: "0.05", // human USDC
payTo: "you.zunivo", // a .zunivo name or 0x address
zunivoApi: "https://api.zunivo.io",
zunivoKey: process.env.ZUNIVO_KEY,
});
app.get("/v1/data", pay, (req, res) => res.json({ premium: "…" }));
Unpaid requests receive a spec-compliant 402. Paid requests pass through with an X-PAYMENT-RESPONSE receipt header. Each payment is consumed exactly once.
The 402 a client sees
{
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "arc-testnet",
"maxAmountRequired": "50000", // 0.05 USDC in 6-decimal base units
"asset": "0x3600000000000000000000000000000000000000",
"payTo": "you.zunivo",
"maxTimeoutSeconds": 120,
"extra": { "name": "USDC", "decimals": 6, "chainId": 5042002 }
}]
}
Agent — pay automatically
The whole dance — discover price, pay on Arc, retry with proof — is one wrapped fetch:
import { createX402Fetch } from "zunivo-x402-arc/client";
const x402fetch = createX402Fetch({
privateKey: process.env.AGENT_PK,
maxPrice: "1", // refuse anything pricier (optional guard)
onEvent: (e) => console.log(e.type),
});
const res = await x402fetch("https://api.example.dev/v1/data");
const data = await res.json(); // paid for, on-chain, no human
Two settlement backends
The middleware's verify is pluggable. Two paths ship:
| Backend | How it settles | Status |
|---|---|---|
| Zunivo orders (default) | Payment settles through our verified Arc router 0x4210…Ea55. X-PAYMENT payload is { zunivoOrderId }. | works today |
| EIP-3009 facilitator | Agent signs a TransferWithAuthorization; the facilitator submits it to Arc's USDC. Fully standard, gasless. | reference |
EIP-3009 (gasless, advanced)
Arc's USDC is issued by Circle and supports EIP-3009 (TransferWithAuthorization) — the same mechanism x402 uses elsewhere. The agent signs off-chain; a facilitator submits on-chain; no prior approval, no gas for the agent.
import { signPayment, createFacilitator } from "zunivo-x402-arc/facilitator";
// agent side — sign, no gas, no transaction
const payload = await signPayment({ privateKey, to: "you.zunivo", price: "0.05" });
// facilitator side — verify signature, then submit to Arc USDC
const fac = createFacilitator({ submitterKey });
const { settled, txHash } = await fac.settle(payload);
0x3600…0000) exposes the transferWithAuthorization / receiveWithAuthorization selectors and its EIP-712 domain (name, version) on-chain. Until then, use the Zunivo-order backend as the tested path.Decimals on Arc (read this)
toUsdcBaseUnits() / fromUsdcBaseUnits().Arc Testnet constants
| Field | Value |
|---|---|
| Chain ID | 5042002 |
| RPC | https://rpc.testnet.arc.network |
| Explorer | https://testnet.arcscan.app |
| USDC (ERC-20, 6 dp) | 0x3600000000000000000000000000000000000000 |
| Zunivo router | 0x4210D40a9899e42b4946B9dC7E0C35d3cf14Ea55 |
| x402 network id | arc-testnet |
| Faucet | faucet.circle.com |