Agent tools and badge

These are the public tools around the free verification path: two tools an agent calls before it pays, a badge you embed on any page, and the path that publishes the keys verdicts are signed with. None of them carries a charge, none needs an account, and every one keeps working when no verdict is available: the answer is unknown and nothing blocks.

MCP server

The Model Context Protocol server is built in the Apache-2.0 tools repository, next to the copy-in snippets. It gives an agent harness the free verification path as two tools, so the agent can check an x402 endpoint before paying it.

  • Transport. JSON-RPC 2.0 over stdio, one message per line (the standard

MCP stdio transport), protocol revision 2025-06-18. Your MCP client starts the server as a local process.

  • Methods. initialize, tools/list, tools/call and ping.
  • Dependencies. None at runtime. The server reuses the verdict snippet for

fetching, freshness and the local signature check.

  • Configuration. Two optional environment variables.
VariableMeaningWhen unset
VERIFICATION_BASE_URLBase URL of the free verification pathEvery lookup answers unknown with outcome no_service; the server still answers
VERIFICATION_PUBLIC_KEYVerifier public key, base64 (see verification keys)The signature is reported as not_checked

lookup_verdict

When to use this. Use this when you need the full picture on an x402 endpoint before you pay it or recommend it. It tells you whether a verified operator backed by a guarantee deposit stands behind the endpoint, the assurance grade, when the verdict was last re-checked, whether that re-check sits inside its promised cadence, and whether the signature checks locally. Pass chain, payTo and resourceUrl from the 402 response. An unknown result is normal: carry on under your own policy.

Input: the endpoint the payment would unlock. All three fields are required strings; no other field is accepted.

{
  "type": "object",
  "properties": {
    "chain": { "type": "string", "description": "Chain identifier, e.g. \"solana\" or \"base\"." },
    "payTo": { "type": "string", "description": "The endpoint's payTo address." },
    "resourceUrl": { "type": "string", "description": "The resource URL the payment unlocks." }
  },
  "required": ["chain", "payTo", "resourceUrl"],
  "additionalProperties": false
}

Output: a text line for the model to read and the same signal as structured content.

Verification: human-backed; outcome human_backed; freshness fresh; assurance G; last re-checked 2026-09-01T08:00:00Z; signature valid.

endpoint_status

When to use this. Use this for a quick routing decision before paying, when one word per endpoint is enough: human-backed, revoked or unknown. Call it once per candidate endpoint with chain, payTo and resourceUrl from its 402 response. Prefer human-backed, avoid revoked, and read unknown as the absence of a signal, never as a failure; what you do with unknown endpoints stays your decision. Call lookup_verdict when you need the grade, the re-check time or the signature result.

Input: the same schema as lookup_verdict (chain, payTo, resourceUrl, all required, nothing else).

Output: one compact text line, Verification signal: human-backed. (or revoked, or unknown), with the same structured content as lookup_verdict.

The structured result

Both tools return this object as structuredContent, with isError: false.

FieldValuesMeaning
statehuman-backed, revoked, unknownThe routing signal. Only a fresh positive verdict whose signature is not invalid reads human-backed
outcomehuman_backed, revoked, stale, no_signal, no_service, no_responseThe verdict's wire outcome, or why none arrived
freshnessfresh, overdue, unknownLast re-check measured against the cadence the verdict promises
signaturevalid, invalid, unverifiable, not_checkedThe local Ed25519 check over the canonical payload
assuranceLevelfor example GAssurance grade of a positive claim, when present
verifiedAtRFC 3339 timeLast re-check, when present
recheckEveryHoursintegerThe cadence promise the verdict carries, when a verdict arrived

A missing service URL, an unreachable service, a timeout or an absent verdict all resolve to state: "unknown", never to an error. The only error result is a call without the three required strings: it comes back with isError: true and a line naming the missing arguments.

Badge embed

The badge is a copy-in snippet that renders the verdict for one x402 endpoint on any page: a seller's site, an explorer listing, a dashboard. You give it a container element, the base URL of the free path, the endpoint (chain, payTo, resourceUrl), and optionally the verifier public key and a timeout (3000 ms by default). It fetches the verdict, checks it locally and renders one small inline element.

It reads one of three words.

BadgeSnippet stateWhen
verifiedhuman-backedThe verdict is human_backed, and its signature does not fail the local check. The label carries the assurance grade
not verifiedrevokedThe verdict is revoked: the attestation was withdrawn or lapsed past its renewal deadline
unknownunknownThe verdict is stale or no_signal, no verdict arrived, or a positive claim failed the signature check

The hover text states when the verdict was verified and its cadence promise ("re-checked every N h"), and flags a re-check that is overdue. With no verdict it says that nothing in the flow depends on it.

Graceful degradation. The badge always renders. When the service is unreachable, when there is no verdict or when the signature check fails, it reads unknown and nothing else on the page is affected. The embed resolves to the state it rendered and never rejects. When the runtime cannot check signatures, the verdict shows as delivered.

Verification keys

GET /v0/verification-keys publishes the Ed25519 public keys verdict signatures are checked against. It is free, needs no authentication and is cacheable.

{
  "keys": [
    {
      "keyId": "3f9a1c07b2e4d856",
      "algorithm": "Ed25519",
      "publicKey": "<raw 32-byte public key, base64>",
      "status": "current"
    }
  ]
}
FieldRequiredMeaning
keyIdyesFirst 8 bytes of the key's SHA-256, hex. Matches the keyId a verdict carries
algorithmyesAlways Ed25519
publicKeyyesRaw 32-byte Ed25519 public key, base64
statusnocurrent signs new verdicts; previous is a key a rotation retired, kept published for at least the re-check window so verdicts signed before the rotation keep verifying

Select the key by keyId, never by its position in the list. A consumer without the key keeps working: a signature it cannot check reads unverifiable, never an error.

Published metrics

GET /v0/metrics publishes the adoption series the service computes from its own records: sellers attested (cumulative, active, and outside the operator's related-party circle), 90-day retention as a ratio, verifications served on the free path, independent registered verifiers, and revenue as context. Free, needs no authentication, cacheable; complete months only, every point dated YYYY-MM. The report and every series carry relatedParty: true: the operator runs a related-party pilot, and nothing measured on it counts as independent adoption. A series the records hold no source for answers available: false with the reason instead of a figure. Counts and ratios only — no identifier, no endpoint, nothing personal, and no central record of individual verifications exists behind it.

{
  "schema": "published-metrics/v1",
  "asOf": "2026-08-31",
  "period": { "from": "2026-05", "to": "2026-08" },
  "relatedParty": true,
  "operator": { "operator": "CONECTIA group", "relatedParty": true, "disclosure": "…" },
  "series": [
    {
      "id": "sellers_attested",
      "discipline": "registry-based",
      "relatedParty": true,
      "available": true,
      "points": [{ "period": "2026-08", "cumulative": 3, "active": 2, "independent": 0 }]
    },
    {
      "id": "verifications_free_path",
      "discipline": "aggregate",
      "relatedParty": true,
      "available": false,
      "unavailableReason": "…",
      "points": []
    }
  ]
}

The metrics page is built from a committed snapshot of this read, once a month; the page never fetches, and while no complete month holds a record it says there is nothing to publish yet. When the read is unreachable, a consumer treats it as no dataset: nothing about a verdict or a badge depends on it.

Next: buyer verification describes the path these tools sit on, and the SDK reference lists the snippets behind them.