For agents and their humans

Ten minutes from zero to a settled verdict.

No signup, no API key: the payment is the authentication. New here? The five-minute quickstart gets you a PASS, a BLOCK and a verified receipt first. This page then shows the free pre-signing gate, the exact handshake, the recovery contract, and every machine endpoint. Plain-language version: the checks page.

01 · The handshake

Ask, get 402, pay, retry once.

First call without payment. The service answers 402 Payment Required with everything your agent needs: scheme, network, asset, amount, recipient, and the per-call cap.

1 · Ask without paying

curl -X POST https://verify402.onrender.com/verify \
  -H "Content-Type: application/json" \
  -H "x-idempotency-key: my-op-1" \
  -d '{"pair":"USDC/WETH","dex":"uniswap-v3","sizeUsd":100000}'

# → HTTP 402 Payment Required
#   accepts: eip155:8453 (USDC) or solana:… (USDC), payTo, amount, maxTimeoutSeconds

2 · Pay and retry with proof

# x402 clients (e.g. @x402/fetch) do this automatically:
#   read the 402 → sign the exact payment → retry with X-PAYMENT
# The retry returns the verdict with an evidence_bundle.

Send x-idempotency-key on the first call

If the connection dies after settlement, the retry with the same key replays the same bytes for free — within ten minutes, three replays max. The key is the cheapest insurance on this rail.


02 · Receipts

Every paid response can be rechecked.

The response carries an evidence bundle so a third party can recompute the measurement without trusting the service: the hash of the canonical request, the hash of the actual response body, and the pinned block.

FieldWhat it proves
requestHashThis exact request was the one answered — canonical bytes, not a paraphrase
responseHashThe exact bytes returned; a replay that doesn't match isn't free
pinnedBlockThe chain state the answer describes. Everything is a quote about one block.
verdictedge, no_edge, or no_edge_costs_ate_it

The recovery contract, in one paragraph

A settlement is staged, not recorded, when payment succeeds. It is promoted only by the official onAfterSettle hook, keyed on a server-generated operationId carried in the response and requiring a confirmed settle with a transaction reference — with the hash of the actual response bytes as an additional check. Equal output does not identify an operation: two requests that both return no_match are still distinct, and settling one never promotes the other. A failed or pending settlement promotes nothing; staged-unpromoted records age out silently after five minutes; the replay cap is per operation, shared by aliases. Reusing a key with changed request content, or from a different payer, is a 409 conflict resolved before the paywall — never the other operation's answer, never a charge. The content companion is a same-caller recovery alias, not a public cache. Two parts of this were broken in public by an independent auditor and fixed the same day: commit 4bf3c9c, then hardened after the x402 spec review (#3848).


03 · Before you sign

One free gate, one short-lived receipt.

POST /preflight is free. Give it an x402 payment request or a chain transaction; it returns PASS / CAUTION / BLOCK, typed reasons, the checks that actually ran, and the checks that did not. Every response carries an HMAC-signed receipt bound to the exact normalized intent and, where the chain is readable, a fresh pinned block. On EVM, a block older than 30s is CAUTION; older than 120s is BLOCK; a block with no timestamp is a 503.

Use it from an agent: verify402-mcp exposes the gate (no wallet) and the five paid checks (hot wallet, per-call x402) over MCP.

IntentWhat it needsWhat it checks
paymentnetwork, asset, amount, payTo, resourcescheme, CAIP-2 network, canonical USDC, amount/policy cap, payee allowlist, resource match, timeout, authorization window, payer balance on EVM, EVM block freshness
transactionchainId (EVM 1/42161/8453), to, data, value, fromrecipient, calldata decode, contract bytecode, approval/spender policy, swap deadline/minOut/recipient, eth_call simulation, EVM block freshness

Payment request · abbreviated

curl -X POST https://verify402.onrender.com/preflight \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "payment",
    "from": "0xYourWallet",
    "payment": {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "10000",
      "payTo": "0xAeEF086DD4e436c69d6d0F684b4c9F43392df9cb",
      "resource": "https://verify402.onrender.com/verify"
    },
    "policy": { "maxAmountUsd": 0.25 }
  }'

Response

{ "verdict": "PASS", "sign_allowed": true, "requires_ack": false,
  "checked": ["scheme", "network", "asset", "amount", "payee", "payer_balance"],
  "notChecked": ["recipient reputation", "sanctions screening", "counterparty identity / tool metadata", "prompt injection / hidden Unicode in tool output"],
  "receipt": { "spec": "verify402/preflight-receipt@1", "intentHash": "…",
               "blockNumber": 48277717, "signature": "…" } }

Verify before you trust the receipt

POST /preflight/verify with {"receipt":{…}} recomputes the HMAC and checks the expiry. No chain call. A CAUTION is an explicit decision, not a pass; a BLOCK is a refusal. If the chain cannot be read, /preflight returns 503 and issues no receipt, so the executor must fail closed. Reference executor: examples/preflight-guard.mjs — it refuses to call your signer without a verified receipt.


04 · Endpoints

Everything the machine answers.

EndpointPricePurpose
POST /preflightfreePre-signing gate: PASS / CAUTION / BLOCK + receipt
POST /preflight/verifyfreeVerify a preflight receipt (HMAC + expiry)
POST /verify$0.05Cross-venue arbitrage measurement with three-state verdict
POST /safety$0.10Pre-trade token gate: TRUST / CAUTION / AVOID
POST /route$0.03Best execution route across quoted venues
POST /quotecheck$0.05Audit an externally supplied quote
POST /depth$0.05Capacity ladder for position sizing
GET /findingsfreeLive verdicts on Ethereum majors
GET /infofreeMachine-readable service description
GET /healthfreeLiveness and mode
GET /.well-known/agent-card.jsonfreeA2A/ERC-8004 agent card with skills

Errors are honest too

400 means the request was malformed — the message names the field. 402 is the door, not a wall. 500 means the service failed, and it says so instead of returning a fabricated number. Verdicts are never invented to look useful.