Blocked
A blocked payment is not an error. It is the product working.
When a guardrail stops a payment, Veyto did the thing you configured it to do, and no money moved. Nothing is reserved, nothing is signed, nothing reaches the chain.
import { VeytoDeniedError } from "@veyto/sdk";
try {
await agent.payingFetch(url);
} catch (e) {
if (e instanceof VeytoDeniedError) {
console.log(e.reason); // "exceeds per-payment cap"
} else {
throw e; // a real failure — network, service, something broke
}
}VeytoDeniedError and a thrown exception are different things, and your code should
treat them differently. A denial is an answer. An exception is a problem.
The reasons
| reason | what to do |
|---|---|
exceeds per-payment cap | ask for less, or raise cap_per_payment_minor |
exceeds daily cap | wait for the UTC day to roll, or raise cap_per_day_minor |
velocity limit | slow down, or raise velocity_max_per_hour |
agent frozen | unfreeze it, or leave it stopped |
Do not retry
A denial is terminal for that request. Retrying the identical payment produces the identical answer, and a retry loop against a cap is just a busier way of being refused. Change the request, or change the policy.
Reading them back
const { items } = await veyto.listIntents({ status: "denied", limit: 50 });
// each carries decision.reason and decision.reason_basis: "policy_evaluation"Most of what a governed payer does is refuse. Those refusals are recorded, not discarded — a blocked payment nobody can read leaves "why did my agent stop paying?" unanswerable.