End-to-End: Paying an x402 API
A research agent needs data from an API that charges $0.50 per call using the x402 “402 Payment Required” standard. The agent must never pay unless your AgentOps policy allows it. Here is the whole flow.
Step 0 — Platform setup (once)
- Deploy the AgentOps server → it lives at your base URL.
- Install
@agops-labs/sdkin the agent project — it is published on npm.
Step 1 — Provision the agent (sk_)
const operator = createAgentOpsClient({
baseUrl: 'https://<your-agentops-host>',
apiKey: process.env.AGENTOPS_OPERATOR_KEY!,
});
const { agent, api_key } = await operator.createAgent({ name: 'Research Agent' });
// then set its policy in the console: spend cap, per-tx max $1, allowlist the data APIStep 2 — The agent hits the paywall
The agent calls the data API. It replies 402 Payment Required with an x402 body describing the amount and payee. The agent does not pay directly.
const res = await fetch('https://data.example/v1/report');
if (res.status === 402) {
const paymentRequired = await res.json(); // the x402 body — pass it verbatim
}Step 3 — Ask AgentOps to authorize (ag_)
const asAgent = createAgentOpsClient({
baseUrl: 'https://<your-agentops-host>',
apiKey: api_key, // ag_live_...
});
const decision = await asAgent.authorize({
kind: 'x402-payment',
agentId: agent.id,
idempotencyKey: 'report-2026-07-24',
paymentRequired,
});The server runs the full firewall. Two possible outcomes:
- DENY — e.g. over the spend cap or the API isn’t allowlisted. The agent stops. Nothing was paid.
- ALLOW — the response carries a signed
payment_headerthe agent can attach.
Step 4 — Complete the purchase
if (decision.outcome === 'DENY') {
throw new Error('blocked by policy: ' + decision.reason);
}
const paid = await fetch('https://data.example/v1/report', {
headers: { [decision.payment_header.name]: decision.payment_header.value },
});
const report = await paid.json(); // the agent got its data — because policy allowed itSteps 2–4, in one call
Those three steps are the same every time, so the SDK ships them as createGuardedFetch. It does exactly what you just read — 402, authorize, attach header, retry — behind a normal fetch signature:
import { createGuardedFetch, PaymentDeniedError } from '@agops-labs/sdk';
const guardedFetch = createGuardedFetch({
baseUrl: 'https://<your-agentops-host>',
apiKey: api_key, // ag_live_...
agentId: agent.id,
});
try {
const paid = await guardedFetch('https://data.example/v1/report');
const report = await paid.json(); // the agent got its data — because policy allowed it
} catch (err) {
if (err instanceof PaymentDeniedError) {
console.log('blocked by policy:', err.reason, '| decision:', err.decisionId);
}
}NOTE
Step 5 — Proof is anchored (automatic)
Your reconcile worker reads settlement from Casper and writes SHA-256(decision) into the GuardRegistry. There is now a tamper-proof, publicly verifiable record of exactly what this agent was authorized to pay — with no trust in you required.
NOTE
authorize(input, { async: true }) to get a decisionId, then poll operator.getDecision(decisionId). Same pipeline, same anchor.