j:jurat

Pre-flight: check an x402 endpoint before you pay it

Eighteen conformance checks on any x402 endpoint without settling anything: live 402 challenge, decoded payment terms, and whether the price it advertises matches the price it charges.

The problem

An agent about to buy from an x402 endpoint it has never used knows almost nothing about it. Is the endpoint live? Does the challenge decode? Is the price in its published spec the price it will actually take from your wallet? Directories publish uptime, and uptime tells you the server answered. It does not tell you the terms are honest or that the resource is configured in a way a client can pay.

GET /v1/preflight?url=<endpoint> ($0.005) answers that. jurat probes the endpoint unpaid, reads its published spec, and returns a verdict, the decoded payment terms and a fix for anything wrong. Nothing is settled against the endpoint being checked.

The headline check: does the advertised price match the charged price

x402 carries the price twice, in two different units. The spec surface (x-payment-info.price.amount in openapi.json) is decimal USD to six places, so a half-cent is "0.005000". The live 402 challenge carries atomic units, so on USDC that same half-cent is "5000". They are written by different code paths, and when they drift, nothing complains: a 1000x mispricing looks exactly like a correct one from the outside. Pre-flight decodes the live challenge, converts atomic to USD using the decimals of the settlement asset, and compares. If the asset is one it does not recognise, it reports the check as skipped rather than guessing at decimals.

What gets checked

checkwhat a failure means
reachablethe endpoint did not answer at all
challenge_402an unpaid request got something other than 402, so no client can start the payment flow
bare_probe_402the challenge only appears once parameters are supplied, so bare discovery probes see a 400 instead
challenge_decodesa 402 came back with no parseable x402 challenge in it
head_challengeHEAD does not return the challenge; discovery monitors probe with HEAD and silently drop resources that answer anything else
payto_presentno valid payTo address, so settlement is impossible
asset_knownunrecognised settlement asset, so the price cannot be independently checked
amount_parsesthe amount is not a number that converts to a price
scheme_exacta scheme most clients do not implement
resource_url_matchesthe challenge advertises a different URL than the one called, usually http:// behind a TLS terminator
openapi_presentno openapi.json, the canonical discovery surface
openapi_declares_paththe endpoint is missing from its own spec
openapi_output_schemano 200 response schema; AgentCash drops operations without one
openapi_input_declaredno declared parameters, so probers send bare requests and classify the endpoint as broken
openapi_payment_infopaid operation with no declared price
price_agreementthe spec price and the live 402 price disagree
x402_manifestno /.well-known/x402.json for fallback discovery
error_surface_jsonunknown paths return HTML, which a JSON client cannot parse

Response

{
  "target": "https://zaref.dev/v1/repo-prime",
  "origin": "https://zaref.dev",
  "checked_at": "2026-07-25T11:40:02.881Z",
  "verdict": "pass",
  "is_paid_resource": true,
  "safe_to_pay": true,
  "summary": { "checks": 18, "passed": 17, "warnings": 0, "failures": 0, "skipped": 1 },
  "live_terms": {
    "scheme": "exact",
    "network": "eip155:8453",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "pay_to": "0x...",
    "amount_atomic": "5000",
    "price_usd": "0.005000"
  },
  "checks": [
    { "check": "price_agreement", "status": "pass",
      "detail": "spec and live 402 both say $0.005000" }
  ]
}

Every check carries a status of pass, warn, fail or skip, and a failing or warning check carries a fix saying what to change. verdict is the worst thing seen: pass, warn, inconclusive when the terms could not be reached at all, or fail.

safe_to_pay is the field to branch on and it has three values. true means nothing found would stop a payment working or make the price wrong, so a warn is still payable. false means something would. null means pre-flight could not read the terms, so neither answer would be honest.

Endpoints that validate before the paywall

Some services check parameters before returning the challenge, so an agent never pays to learn it made a typo. A bare probe of one of those gets a free 400 and never sees a 402. Pre-flight does not call that broken. When the first probe is rejected, it reads the parameter examples out of the endpoint's own openapi.json, builds a valid request and probes again. Specs that declare no example but spell one out in the prose ("Example: /v1/id-validate?id=8001015009087") are read too, the way a human would. If the challenge appears, the endpoint passes, with bare_probe_402 raised as a warning because bare discovery probes still see the 400 and some indexes will drop a resource over it. If no valid request can be built at all, the verdict is inconclusive and safe_to_pay is null: the endpoint is probably payable, pre-flight just could not prove it.

Free endpoints

An operation that declares security: [] and no 402 response is a free endpoint. Pre-flight recognises it, reports is_paid_resource: false and skips every payment check, instead of calling a service broken for not charging.

What it does not claim

Pre-flight reports what jurat observed at checked_at. A pass says the endpoint's terms are coherent and its discovery surface is sound. It is not a promise the seller will deliver, not an audit of the data behind the endpoint, and not an affiliation with it. Checking is done over public HTTP with the same guardrails as every other jurat fetch: public addresses only, capped bodies, short timeouts, and juratbot in the user agent.