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.

Every check below reads the same public record and gives the same answer: pay, avoid or unknown, with one sentence of why and the numbers behind it. None needs a key or a payment. Proxy buy is the one way here that costs money.

What the verdict means

Counted calls are paid calls: purchases whose payment settled, then answered or failed on the seller's side. A seller's 5xx with no settled payment is not a paid call, and with no settled payment the verdict is unknown. Failures that may be vet402's or the facilitator's, or whose cause cannot be told, never count. A payTo vet402 never paid turns pay into unknown. avoid is said only after vet402 has told the seller; until then the verdict is unknown.

On Robinhood Chain and Arbitrum, a purchase whose result is held until the seller is told is never used: the verdict comes from the published purchases, and the answer adds heldPurchases and heldNote. A seller with nothing but held purchases is unknown. The rule in code

As of the 2026-09-30 run, all 63 Arbitrum One sellers are unknown and all 14 Robinhood Chain sellers are unknown: vet402 bought from them in one run, on one day, which is too little to say pay or avoid.

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 JSON starts with verdict and why; then tried, settled, counted, answered, days, the newest purchase and its tx, the newest signed records, and asOf. &format=html gives a page instead.

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"
}

Spec: packages/check/src/http.ts

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)

With the x402 Python client, register the example file's hook: x402HTTPClientSync(client).on_payment_required(vet402_on_payment_required) looks up the URL your code requested on every 402, before the client signs; on avoid the request raises PaymentError and the payment is never created. The file also sends the chain and payTo of each offer, and, like the fetch hook, goes on when the record cannot be read, saying so in one line.

Spec: examples/python/check_before_paying.py

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"

--data-urlencode sends the seller URL with its query string intact. If the check cannot be read (no network, or no answer in 10 seconds), pay does not run.

Spec: GET /v1/check

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);

Add onCheck: (e) => ... to see every answer, or to write your own rule.

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.

Spec: the fetch hook (packages/check README)

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

Spec: Proxy buy (README), with every refund rule and the order of a paid request

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

Spec: MCP tools (packages/check README)

Command line

npx -y @vet402/check https://api.xona-agent.com/token/pumpfun-trending

Node 22 or newer. --chain, --pay-to, --json and --verify (also check the newest signed record).

Spec: the command line (packages/check README)

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 clone, scripts/verify-receipt.ts runs the same checks. Where the records and roots are

Spec: scripts/verify-receipt.ts

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);

Program id, deployment status and the full example are in its README.

Spec: solana-program/README.md