Governed payments
The short version
const res = await agent.payingFetch("https://some-service/premium/data");What actually happens
your agent
│ payingFetch(url)
▼
the resource ──402──▶ "pay me $0.01 to this address"
│
▼
POST /v1/pay ─────▶ Veyto: check the policy, RESERVE the budget,
│ issue a signed verdict bound to this exact payment
│
◀───────────────── approved_unsigned + EIP-3009 material
│
YOUR PROCESS signs it ← the key never leaves here
│
▼
retry the resource with the payment attached
│
▼
the resource settles it on Base Sepolia
│
▼
POST /v1/pay/:id/settle ──▶ ledger entry + SIGNED RECEIPTThe step that matters is the fifth: Veyto returns unsigned material. It has your public address and the amount it authorized; it does not have your key.
Doing it by hand
If you are not using payingFetch:
const pay = await fetch(`${baseUrl}/v1/pay`, {
method: "POST",
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
body: JSON.stringify({
agent_id: agentId,
rail: "eip155:84532",
currency: "USDC-6",
requirements_b64: challengeHeader, // the 402's payment-required header, verbatim
idempotency_key: crypto.randomUUID(),
purpose: "market data", // optional, and SIGNED into the receipt
}),
}).then((r) => r.json());
// pay.status === "approved_unsigned" → sign pay.eip3009 yourself
// pay.status === "denied" → pay.reason says which rule firedpurpose is the one accounting field that cannot be added afterwards — it is declared at
authorization time and signed into the receipt.
Idempotency
Send an idempotency_key on every payment. Retrying with the same key will not authorize a
second payment.