00 · operator's manual · revision 1

The complete API reference.

Everything an integrator needs on one page: how payment works, every endpoint, all six check types, how anyone verifies a signed document offline, and the exact recipe for payment verified feedback. The same text your agent should read lives at /llms-full.txt.

base url https://umpire.vimabrosta.com auth none; no accounts, no keys payment x402 per document

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.

Nothing to set up

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.

Key reuse rules

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.

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"}}}
Try before you pay

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.

  1. Remove the signature field.
  2. Serialize the rest as JSON with object keys sorted at every depth, no whitespace, UTF-8, non ASCII characters left unescaped.
  3. Check the sha256 of those bytes against signature.payload_sha256. A mismatch means your serialization differs, not that the document is forged.
  4. Verify the Ed25519 signature sig_base64 over those bytes with the published key.
pythoncanonical bytes
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.

ERC-8183

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

endpointwhat it does
POST /v1/feedbackSubmit 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/validatePre-flight a tier, spec, deliverable, and webhook: problems list, URL policy verdicts, spec_hash. No target is fetched.
GET /v1/quoteThe pricing manifest.
GET /healthzHealth as JSON. The human twin is /status.

07Feedback recipe

Feedback is accepted only with proof you paid the merchant. Two proofs, both checked.

  1. tx_hash must 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.
  2. signature must be an EIP-191 personal_sign of this exact message by the payer wallet. Lines joined with \n, no trailing newline; optional fields left empty when omitted.
message to signtext
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.
What a row proves, and what it does not

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.

nodeverify
// 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

ruledetail
scheme and portshttp(s) only; ports 80, 443, 8080, 8443; no embedded credentials.
hostsPublic 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).
fetchGET 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.
conductUmpire never purchases, logs in, or bypasses any control. Site owners: see the probe policy.

Rate limits, per IP, per minute

routelimit
feedback30 (HTTP and MCP share the bucket)
validate30
find20
status, quote120
mcp120
idempotent replays120

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"}}
codestatusmeaning
invalid_request, invalid_spec, invalid_webhook422The body or spec is malformed. Not charged.
unknown_tier404Tier must be witness, basic, probe, or sworn.
blocked_host, blocked_port, invalid_scheme, credentials_in_url, dns_failure422URL policy, decided before payment.
invalid_idempotency_key422Key shorter than 16 characters.
idempotency_key_reuse, in_flight, already_created409Key already used for a different body, or the original is still settling.
bad_signature401Feedback signature does not recover to the payer.
payment_not_found, payer_mismatch, receipt_too_old, self_feedback, amount_too_small422The receipt does not prove what feedback requires.
duplicate_feedback409One feedback per transaction.
receipts_off503Receipt verification is disabled on this deployment.
chain_unavailable502The RPC could not be reached; retry shortly.
rate_limited429See Retry-After.
not_found404Unknown route or id, or a wrong secret (uniform by design).
invalid_json400The body did not parse.
internal500Safe 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.

Terms, in one paragraph

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.