Use vet402 in your agent
Every way to ask vet402 before an agent pays, and how to let vet402 buy for it: a minimal example for each, and a link to the full spec.
What the verdict means
- pay Most of vet402's paid calls to this seller were answered: the 95% interval of answered / counted is at or above 0.5 (the line for grade C), over 2 or more days.
- avoid vet402 paid, and most paid calls were not answered: the interval's upper bound is below 0.5 (the line for grade D), over 2 or more days.
- unknown Not enough to say pay or avoid: too little data, or vet402 never bought from this seller. With 1 to 3 counted calls the verdict is always unknown, and so it is for calls all made on one day.
HTTP: GET /v1/check
Any language, or a browser. Optional chain (solana, tempo, base, algorand, arbitrum, robinhood or a CAIP-2 id) and payTo (the recipient in the 402 you hold). CORS is open.
curl 'https://vet402-delivery.vercel.app/v1/check?url=https://api.xona-agent.com/token/pumpfun-trending'
The answer for that URL, built by the same code from the same data as the live endpoint (rank.json of 2026-10-06):
{
"verdict": "avoid",
"why": "vet402 paid this seller 16 times on Solana over 9 days; 0 of 16 paid calls answered (the newest failed one answered HTTP 500).",
"url": "https://api.xona-agent.com/token/pumpfun-trending",
"chain": null,
"payTo": null,
"seller": "api.xona-agent.com",
"chains": [
"solana"
],
"tried": 16,
"settled": 16,
"counted": 16,
"answered": 0,
"notCounted": 0,
"days": 9,
"heldPurchases": 0,
"heldNote": null,
"interval": {
"lower": 0,
"upper": 0.194
},
"newest": {
"at": "2026-10-06T14:29:58.990Z",
"chain": "solana",
"result": "settled_error_status",
"httpStatus": 500,
"tx": "635z8Scpkb9kxg99ESmKxQ4wT2NLfGgFgKTgmcqysX86aS2rGby9t4AuGc4xmzGi82x8uTzUZd2K6AYbUqk4qXtk",
"explorer": "https://solscan.io/tx/635z8Scpkb9kxg99ESmKxQ4wT2NLfGgFgKTgmcqysX86aS2rGby9t4AuGc4xmzGi82x8uTzUZd2K6AYbUqk4qXtk"
},
"sellerPage": "https://kzmttkc.github.io/vet402-delivery/seller/api.xona-agent.com.html",
"records": {
"published": 16,
"byVerdict": {
"NOT_DELIVERED": 16
},
"newest": [
{
"id": "obs_2026-10-06_001665",
"day": "2026-10-06",
"verdict": "NOT_DELIVERED",
"json": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-06_001665.json",
"page": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-06_001665.html",
"anchorTx": "5AaFJHisZ9UUQQr2XKUcUUsEy4QetNdp4BFkZ3wNP2FFJjVfosybtY49iPsBGkzv6q1GVm9rfUr6SSowFnBvwUXj"
},
{
"id": "obs_2026-10-06_001552",
"day": "2026-10-06",
"verdict": "NOT_DELIVERED",
"json": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-06_001552.json",
"page": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-06_001552.html",
"anchorTx": "5AaFJHisZ9UUQQr2XKUcUUsEy4QetNdp4BFkZ3wNP2FFJjVfosybtY49iPsBGkzv6q1GVm9rfUr6SSowFnBvwUXj"
},
{
"id": "obs_2026-10-05_001435",
"day": "2026-10-05",
"verdict": "NOT_DELIVERED",
"json": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-05_001435.json",
"page": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-05_001435.html",
"anchorTx": "36MTYdQMEX1LzKEtr7s9RfzRTkhNszovCwu826NcoiBjnv7pdh2nFgYRqG8LYSao2xj93PXDsJdf7bm66cZLLDqJ"
},
{
"id": "obs_2026-10-04_001349",
"day": "2026-10-04",
"verdict": "NOT_DELIVERED",
"json": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-04_001349.json",
"page": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-04_001349.html",
"anchorTx": "Pon87jab6vd8QPVJmYLTGNCRHi3z1KH1t9LZuR7ygr4f39E9rsPWxf8JmsuAn6Mj8YqTf7dNu9mViiWNzDWJreE"
},
{
"id": "obs_2026-10-04_001233",
"day": "2026-10-04",
"verdict": "NOT_DELIVERED",
"json": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-04_001233.json",
"page": "https://kzmttkc.github.io/vet402-delivery/records/obs_2026-10-04_001233.html",
"anchorTx": "Pon87jab6vd8QPVJmYLTGNCRHi3z1KH1t9LZuR7ygr4f39E9rsPWxf8JmsuAn6Mj8YqTf7dNu9mViiWNzDWJreE"
}
]
},
"payToRecorded": null,
"asOf": {
"rankDate": "2026-10-06",
"rankGeneratedAt": "2026-10-07T01:33:57.557Z",
"recordsPublished": 1595
},
"summary": "api.xona-agent.com (Solana, Tempo and Base page): vet402 tried 16 purchases on solana from 2026-09-28 to 2026-10-06; 16 settled, 0 came back with an answer. Failures counted against the seller: paid_not_delivered 16. Not counted against the seller: 0 (vet402 or facilitator 0, cause unknown 0). Grade: D, rank 84. Newest purchase: 2026-10-06T14:29:58.990Z on solana, settled_error_status (HTTP 500), tx 635z8Scpkb9kxg99ESmKxQ4wT2NLfGgFgKTgmcqysX86aS2rGby9t4AuGc4xmzGi82x8uTzUZd2K6AYbUqk4qXtk. Signed records published: 16 (NOT_DELIVERED 16), 16 for this exact URL; newest obs_2026-10-06_001665, its day's Merkle root is in Solana memo tx 5AaFJHisZ9UUQQr2XKUcUUsEy4QetNdp4BFkZ3wNP2FFJjVfosybtY49iPsBGkzv6q1GVm9rfUr6SSowFnBvwUXj.",
"notes": [],
"rule": "pay: the 95% interval of answered / counted is at or above 0.5 (grade C's line), on 2+ days. avoid: its upper bound is below 0.5 (grade D's line), on 2+ days. Otherwise unknown. Counted = paid calls: purchases whose payment settled, answered or failed on the seller's side; a seller's 5xx with no settled payment, failures on vet402's or the facilitator's side, and failures of unknown cause are left out. No settled payment: unknown. avoid is said only after vet402 has told the seller; until then the verdict is unknown.",
"method": "https://kzmttkc.github.io/vet402-delivery/method.html"
}
Python
Standard library only: ask before paying, and pay only when the verdict is not avoid.
import json, urllib.parse, urllib.request
def vet402_verdict(url):
q = urllib.parse.urlencode({"url": url})
with urllib.request.urlopen("https://vet402-delivery.vercel.app/v1/check?" + q, timeout=10) as r:
return json.load(r)["verdict"]
if vet402_verdict(seller_url) != "avoid":
pay(seller_url)
Shell: curl
One line before the command that pays. pay stands for that command: it runs only when vet402 answered and the verdict is not avoid.
URL='https://api.xona-agent.com/token/pumpfun-trending' # with jq curl -fsSG -m 10 https://vet402-delivery.vercel.app/v1/check --data-urlencode "url=$URL" | jq -e '.verdict != "avoid"' >/dev/null && pay "$URL" # without jq curl -fsSG -m 10 https://vet402-delivery.vercel.app/v1/check --data-urlencode "url=$URL" | grep -o '"verdict": *"[a-z]*"' | head -1 | grep -Eq 'pay|unknown' && pay "$URL"
At the payment: the x402 fetch hook
Wrap the fetch your x402 client pays through. Every 402 is looked up before the client signs; with block: "avoid" the payment is never created for a seller whose answer is avoid.
npm install @vet402/check
import { wrapFetchWithPayment } from "@x402/fetch";
import { wrapFetchWithCheck } from "@vet402/check";
const fetchWithPay = wrapFetchWithPayment(wrapFetchWithCheck(fetch, { block: "avoid" }), client);
Any chain: the hook reads the network and payTo of every way to pay a 402 offers (x402 accepts, from the body or the PAYMENT-REQUIRED header, and an MPP WWW-Authenticate: Payment challenge), so it works under any x402 client that pays through fetch. Solana, Base, Tempo, Algorand, Arbitrum and Robinhood Chain are looked up per chain; any other network by URL and payTo. The package is named vet402-solana after the repository's first chain; the hook is not Solana-only.
Let vet402 buy it for you: GET /v1/buy
Solana only for now. Tempo is switched off on the live deployment, so where a line below names Tempo or USDC.e, it does not apply yet. The lines below are the README's own words.
An agent asks vet402 to buy a seller's answer for it. vet402 pays the seller from its own wallet only after the agent's payment has settled, and returns the seller's answer together with both transactions and a public record of the purchase.
Status on 2026-10-01: it runs at https://vet402-delivery.vercel.app/v1/buy, for Solana only (Tempo is switched off on that deployment, so no Tempo price is offered and a Tempo payment is refused).
curl -i 'https://vet402-delivery.vercel.app/v1/buy?url=<seller endpoint>' # free: shows the price, charges nothing
- Price: the seller's price plus 0.005 (USDC on Solana, USDC.e on Tempo).
- Who vet402 buys from: only a seller host and payTo pair that vet402 already paid with a settled payment and that delivered at least once, read from
data/ - Refund: If the agent's payment settles and vet402 then does not pay the seller, vet402 refunds the full payment (seller price + fee) to the owner of the account whose balance paid (not a delegate that only signed), on the same chain in the same token.
- No refund: If vet402 paid the seller (its payment to the seller settled) and the seller did not deliver, there is no refund. The purchase is recorded against the seller, with vet402's payment to it. One exception, switched on on the live deployment on 2026-10-02 at 12:53 UTC (the free 402's
buy.refundsays which rule applies): the refund for an undelivered answer (Solana), when switched on, refunds the full payment for a seller-side failure (402 again, 5xx, a 1xx or 3xx status, a 2xx with an empty body, or a connection the seller refused or closed), at most once per paying address per UTC day and only while a cap per UTC day and per UTC month, shared by all agents, has room; a refund refused by these limits is not tried again. - Large answers: an answer above 1,000,000 bytes is not forwarded, and since the seller was paid there is no refund
- After a paid request: 200: the seller's answer byte for byte (content type kept), with
x-vet402-customer-tx,x-vet402-seller-status,x-vet402-recordandx-vet402-seller-settled - The record:
GET /v1/buy/records/<id>returns the record: the seller endpoint without its query string, seller payTo and price, fee, total, both transactions, the seller's HTTP status, the sha256 and size of the answer, the outcome and the refund.
MCP server
Two read-only tools for an agent: check_before_paying and verify_record.
claude mcp add vet402-check -- npx -y @vet402/check --mcp
Command line
npx -y @vet402/check https://api.xona-agent.com/token/pumpfun-trending
Verify a signed record
Check one record without trusting vet402: its signature, its Merkle proof to the day's root, the payment on chain, and the root written on chain.
npx -y @vet402/check verify obs_2026-09-28_000164
From a Solana program
observation-roots keeps each day's root in an account that programs can read, and checks one record against it, so an escrow or another program can ask by CPI whether a purchase came back.
require!(observation_roots::verify_cpi(cpi, day, fields, proof)?.verdict == Verdict::Delivered, MyError::NotDelivered);