01What Umpire does
Umpire is the neutral third party for agent commerce, operated by Vima Brosta LLC. It sells two things, each paid for once, per document, in a single HTTP round trip.
Signed verdicts. You hand over a deliverable and an acceptance spec; Umpire runs every check and returns an Ed25519 signed pass or fail document. An escrow contract, a counterparty, or a human auditor can verify it against the published key without trusting whoever carries it.
Payment verified reputation. Feedback about a merchant wallet is accepted only with on chain proof that the reviewer paid that merchant, plus a signature from the paying wallet. Writing is free. Reading the signed report costs $0.01.
No accounts, no API keys, no custody of funds. Every request is priced in the 402 it answers with, and a request that cannot run is refused before any money moves.
02Payment (x402)
Three steps, one retry. A request that cannot run is refused before settlement, so a rejection always costs nothing.
1. Send the request with no payment
You receive HTTP 402. The PAYMENT-REQUIRED response header (base64 JSON, mirrored in
the JSON body under requirements) carries an accepts array with every enabled
option. On this deployment:
- USDC on Base (default rail)
- USDC or native SOL on Solana (same endpoints; pick the Solana option in the 402 accepts list)
- Native ETH and BTC are not accepted: the x402 exact scheme settles token authorizations, so native ETH has no path, and Bitcoin has no x402 rail at all (BTC agent payments use L402, a different protocol).
Stablecoin amounts are fixed per product. Native SOL amounts are quoted per request from a cached spot rate plus a small buffer, rounded up, so payers in a volatile asset pay a known, slightly conservative premium.
2. Pay and retry the identical request
Produce payment and resend with the PAYMENT-SIGNATURE header (the older
X-PAYMENT name is accepted too). @x402/fetch (JS) wraps this in one call, and most
agent frameworks have x402 support. Send an Idempotency-Key of 16 or more characters on
every paid POST: a retry with the same key and body is answered in front of the paywall with the
original response and no new settlement.
3. The document you paid for returns immediately
Settlement happens on chain in the background. If it fails after the checks ran, the purchase is voided: nothing is delivered, nothing is retained, and the same key can be used again.
A different body under a used key is 409 idempotency_key_reuse. A retry while the
original is still settling is 409 in_flight; wait a few seconds. Keys are scoped to the
paying wallet when the payment header names one.
03Paid endpoints
Four verdict tiers share one request shape. The tier chooses how much the umpire is allowed to do: witness looks once, basic judges what you hand it, probe may also fetch, sworn does everything twice.
Exactly one url_probe check, answered synchronously. Priced to clear unattended
wallet caps. Use it when an agent claims it published, deployed, or updated something and you
need a stake free party to say whether the public state agrees: proof against false success.
{ "spec": {"checks": [{"type":"url_probe", "url":"https://api.example.com/health", "expect":{"status":200, "json_path":{"path":"ok","op":"eq","value":true}}}]}, "job_ref": "job-42" }
{ "verdict": { "tier": "witness", "passed": true, "checks": [{ …, "observations": [{ … }] }], "signature": {…} }, "receipt": {…} }
Every check that fetched a URL carries an observations array in the signed document,
one entry per pass: the requested and final URL, redirect hops, fetch time, HTTP status, the
address the response came from, TLS subject, issuer, validity and fingerprint (or null for plain
http), a capped set of standard headers, and the sha256 and size of the raw body. Anyone can
fetch the same URL and compare.
Deterministic checks on the deliverable you send: JSON Schema, JSON path, content hash, regex, length. Nothing is fetched. Answers synchronously with the signed document, a status link, and a one time secret.
{ "spec": {"checks": [ {"type":"json_schema", "schema":{"type":"object","required":["title"]}}, {"type":"length", "unit":"words", "min":500} ]}, "deliverable": {"text": "…", "json": {"title": "…"}}, "job_ref": "job-42" }
Everything basic does, plus up to three network checks: url_probe, or
content_hash with a URL target. Synchronous.
Every check runs twice, about 60 seconds apart, and the verdict passes only if
every check passes in both passes. Answers 202 with pass 1 results, a poll link, and a
secret. The final signed document arrives at your webhook_url, HMAC signed, and at
GET /v1/verdicts/{id}.
Pass 1 alone is never a verdict. If pass 2 keeps erroring it is retried three times and then the document is issued FAILED, never PASSED on one pass.
A signed reputation report for a merchant wallet: feedback count, unique payers, attested USDC volume, median amount, outcome counts, fulfillment rate by count and weighted by USDC amount, would-repeat rate, median latency, payer concentration (top payer share, single use payer share, cross merchant payer share), a 90 day window, first and last seen, the amount floor in force, and a caveat stating what a row proves.
A ledger farmed from fresh wallets shows a high single use payer share, a low cross merchant share, and thin volume. A merchant with no feedback returns a valid signed report with zeros: absence of data is not a judgment.
04Acceptance spec
A spec is {"checks":[…]} with 1 to 10 checks. Six types, each deterministic and
reproducible by anyone holding the same spec and deliverable. The deliverable is
{"text":"…","json":{…}}, either or both, text up to 200 KB. The verdict passes only if
every check passes (sworn: in both passes).
1 · json_schema
deliverable.json must conform to a JSON Schema (draft 2020-12). Any pattern inside the
schema passes the same backtracking guard as a regex check.
{"type":"json_schema", "schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"}}}}
2 · json_path
Assert on a value inside deliverable.json. Dot and bracket path. Ops: eq ne gt lt
gte lte exists not_exists contains.
{"type":"json_path", "path":"result.items[0].price", "op":"lte", "value":100}
3 · content_hash
sha256 of the UTF-8 bytes of deliverable.text, or (probe and sworn) of the raw response
bytes of a fetched URL, any content type, up to 2 MB.
{"type":"content_hash", "sha256":"<64 hex chars>", "target":"text"} {"type":"content_hash", "sha256":"<64 hex chars>", "target":"url", "url":"https://example.com/artifact.json"}
4 · regex
A pattern tested against deliverable.text (flags ims). Patterns that backtrack
catastrophically are refused before payment, and every regex and schema evaluates in an isolated
worker with a hard time limit, so a hostile pattern fails its check and nothing more.
{"type":"regex", "pattern":"## Conclusion", "expect":"match"}
5 · length
Character or word bounds on deliverable.text.
{"type":"length", "unit":"words", "min":500, "max":5000}
6 · url_probe
Witness, probe, and sworn tiers. Fetch a public URL and assert on the response. expect
may combine status, keyword, a CSS selector with an op and value, and
json_path. At most 3 network checks per verdict.
{"type":"url_probe", "url":"https://api.example.com/health", "expect":{"status":200, "selector":{"selector":"h1","op":"contains","value":"Status"}}}
POST /v1/validate is free: it returns the problems list, the URL policy verdicts, and
the spec_hash without fetching anything.
05Verifying a document
Every paid response is a document signed with the key published at
/.well-known/umpire-key.json. Anyone can verify it
offline: an escrow operator, a human auditor, another agent.
- Remove the
signaturefield. - Serialize the rest as JSON with object keys sorted at every depth, no whitespace, UTF-8, non ASCII characters left unescaped.
- Check the sha256 of those bytes against
signature.payload_sha256. A mismatch means your serialization differs, not that the document is forged. - Verify the Ed25519 signature
sig_base64over those bytes with the published key.
json.dumps(doc, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
A verdict embeds the normalized spec it was judged against, with defaults applied.
spec_hash is the sha256 of the stable JSON of that embedded spec, and
deliverable_hash is the sha256 of the stable JSON of {"json": …, "text": …}, both
spelled out in the document's hashing field.
Put your job id in job_ref when purchasing a verdict. The signed document echoes it,
giving an evaluator address verifiable evidence to attest completion with.
06Free endpoints
| endpoint | what it does |
|---|---|
| POST /v1/feedback | Submit payment verified feedback about a merchant. See the recipe. 201 on success. |
| GET /v1/verdicts/{id} | Status, pass 1 preview, or the final signed document. Bearer secret, or ?secret=. |
| GET /v1/find?spec_hash=&webhook= | Recover sworn verdict ids after a lost session. Exact match; never returns secrets. |
| POST /v1/validate | Pre-flight a tier, spec, deliverable, and webhook: problems list, URL policy verdicts, spec_hash. No target is fetched. |
| GET /v1/quote | The pricing manifest. |
| GET /healthz | Health as JSON. The human twin is /status. |
07Feedback recipe
Feedback is accepted only with proof you paid the merchant. Two proofs, both checked.
tx_hashmust be a settled transaction on Base containing a successful USDC transfer from your payer address to the merchant address of at least 0.01 USDC, settled within 90 days.signaturemust be an EIP-191personal_signof this exact message by the payer wallet. Lines joined with\n, no trailing newline; optional fields left empty when omitted.
umpire-feedback-v1 tx:<tx_hash lowercase> merchant:<merchant address lowercase> outcome:<fulfilled|partial|failed> would_repeat:<true|false, or empty> latency_ms:<integer, or empty>
In viem: await walletClient.signMessage({ message }). In ethers:
await signer.signMessage(message). Then POST /v1/feedback with
{"merchant","payer","tx_hash","outcome","would_repeat?","latency_ms?","signature"}.
- One feedback per transaction. Self reviews (payer equals merchant) are refused.
- No free text anywhere: scores only, so nothing needs moderation and no personal data exists.
- Smart wallets (Coinbase Smart Wallet, Safe): sign with that account; the signature is verified through ERC-1271 on chain, read only.
A settled payment to the merchant and a signature by the wallet that paid. It does not prove an independent counterparty; a merchant can pay itself from fresh wallets for the price of gas. The floor makes dust rows impossible and makes attacking a rival cost real money paid to that rival, and every report carries the independence signals and an amount weighted rate, so a farmed ledger looks farmed.
08Webhook delivery
Sworn verdicts deliver their final document by POSTing JSON to your webhook_url with the
header X-Umpire-Signature: sha256=<hex>: HMAC-SHA256 over the raw request body. The key
is the 64 character lowercase hex string of sha256 of your verdict secret, not raw bytes.
// key is a hex string, then used as the HMAC key as-is const key = crypto.createHash("sha256").update(secret).digest("hex"); const expected = "sha256=" + crypto.createHmac("sha256", key).update(rawBody).digest("hex");
Deliveries retry up to 5 times with backoff. The polling endpoint is always the fallback, and
/v1/find recovers ids if the session that bought the verdict is gone.
09URL policy and limits
Probe checks and webhooks
| rule | detail |
|---|---|
| scheme and ports | http(s) only; ports 80, 443, 8080, 8443; no embedded credentials. |
| hosts | Public hosts only. Private, loopback, link local, and *.internal or *.local names are refused at validation time and again at connect time (DNS rebinding is closed). |
| fetch | GET only, honest user agent UmpireProbe/1.0 (+https://umpire.vimabrosta.com/bot), per host politeness spacing, 4 redirect hops maximum, 2 MB read cap, 12 second timeout. |
| conduct | Umpire never purchases, logs in, or bypasses any control. Site owners: see the probe policy. |
Rate limits, per IP, per minute
| route | limit |
|---|---|
| feedback | 30 (HTTP and MCP share the bucket) |
| validate | 30 |
| find | 20 |
| status, quote | 120 |
| mcp | 120 |
| idempotent replays | 120 |
429 responses carry Retry-After. Paid routes are limited by payment itself.
10Errors
Every error body has the same shape, and every hint says how to correct the request.
{"error": {"code": "…", "message": "…", "hint": "…", "docs": "https://umpire.vimabrosta.com/llms-full.txt"}}
| code | status | meaning |
|---|---|---|
| invalid_request, invalid_spec, invalid_webhook | 422 | The body or spec is malformed. Not charged. |
| unknown_tier | 404 | Tier must be witness, basic, probe, or sworn. |
| blocked_host, blocked_port, invalid_scheme, credentials_in_url, dns_failure | 422 | URL policy, decided before payment. |
| invalid_idempotency_key | 422 | Key shorter than 16 characters. |
| idempotency_key_reuse, in_flight, already_created | 409 | Key already used for a different body, or the original is still settling. |
| bad_signature | 401 | Feedback signature does not recover to the payer. |
| payment_not_found, payer_mismatch, receipt_too_old, self_feedback, amount_too_small | 422 | The receipt does not prove what feedback requires. |
| duplicate_feedback | 409 | One feedback per transaction. |
| receipts_off | 503 | Receipt verification is disabled on this deployment. |
| chain_unavailable | 502 | The RPC could not be reached; retry shortly. |
| rate_limited | 429 | See Retry-After. |
| not_found | 404 | Unknown route or id, or a wrong secret (uniform by design). |
| invalid_json | 400 | The body did not parse. |
| internal | 500 | Safe to retry. |
11Retention
A deliverable is discarded the moment its verdict is issued (sworn: after pass 2, about a minute), and only its sha256 remains. Specs and signed documents are kept 90 days for re-reads, then deleted. Feedback rows are permanent, contain only addresses, hashes, enums, and numbers, and never free text. Do not submit personal data in deliverables.
12Machine surfaces
This manual, restated for machines. Fixed addresses, plain text or JSON, one fetch.
Pay per document, no refunds at micro prices. Umpire observes public pages politely, verifies payments by reading the chain, and holds neither funds nor keys. A verdict is an opinion about a deliverable against a spec you wrote; what you do with it is your responsibility. Operated by Vima Brosta LLC (contact@vimabrosta.com). Conduct and terms: https://umpire.vimabrosta.com/#conduct.