MIZAN / Developers

One call before money moves.

Ask check(subject, rule). Get one signed ALLOW or REFUSE. Anyone verifies it offline, with no call back to MIZAN.

GET /api/check/try-me · a real replysigned
{
  "schema": "mizan.verdict/1",
  "decision": "ALLOW",
  "subject": "credential:track-btc-trend-4h-link2",
  "grade": "PROVEN",
  "met": "A passing record in good standing, sealed before its outcomes.",
  "rule": { "id": "mizan.default/1", "hash": "sha256:2e1025ba…d559" },
  "issued": "2026-11-04T09:21:46Z",
  "expires": "2026-11-04T10:21:46Z",
  "as_of": { "ledger_size": 1258, "head": "bd6291a9…f535" },
  "record": { "id": "credential:track-btc-trend-4h-link2", "entry": 147 },
  "token": "mzv1.eyJkZWNpc2lvbiI6Ik…8HpgQFefHX",
  "kid": "2266fb495f83b0a0",
  "status": "https://studio.mizan.market/api/verdict/status/vd_…"
}
the token verifies with MIZAN's published Ed25519 keyverify it in your browser

The answer reads the subject's record on MIZAN's public ledger: what it has proven, logged or only declared, and every try counted. try-me resolves to MIZAN's own public record, so your first answer is a real signed ALLOW.

01 Quickstart

Four steps. No key, no signup.

  1. Call. GET /api/check/<subject> over HTTP, check over MCP or A2A. A subject is an agent id, a domain, an endpoint, a package or an address.
  2. Read the decision. ALLOW or REFUSE, the rule it was given under, and what the record earned. Proceed only on ALLOW.
  3. Carry the token. The signed mzv1.… token rides with the payment: x402, AP2, the Agentic Commerce Protocol or one HTTP header.
  4. Verify offline. The payee checks signature, key, expiry, payee and rule against a pinned key set. No call to MIZAN.
# the one call: no key, no signup
curl -s https://studio.mizan.market/api/check/try-me

# for a payment: bind the answer to the payee and amount
curl -s "https://studio.mizan.market/api/check/0xabc…?payee=0xabc…&amount=5&currency=USDC"
free · signed · re-verifiableOpenAPI
02 The verdict object

The same object on every surface.

HTTP returns it as the body, MCP as structuredContent, A2A as the data part. Fields appear only when true: no nulls, no internal notes.

01

decisionALLOW | REFUSE

Nothing else. A REFUSE carries exactly one stable reason code and a next block: a proof request to forward, and what would pass.

02

gradeDECLARED · RECORDED · PROVEN

What the record earned: they say so, logged with a named source, or checked by math. Never shown higher than earned.

03

rule{id, hash}

The rule the answer was given under: mizan.default/1, a published req_…@version, or one written in plain words.

04

bound_topayee · rule · amount

Present when the check was for a payment. A token bound to one payee cannot be spent on another.

05

token · kidmzv1 · Ed25519

The compact signed verdict and the key that signed it. The token is what you carry; the key set is published at /.well-known/mizan-keys.json.

06

statuslive URL

Is this verdict still good? good, revoked, superseded or expired. Online, read it; offline, honour exp.

03 Verify offline

One function. No SDK, no call home.

A complete verifier in each language. Both pass every published conformance vector: valid, expired, tampered, wrong payee, wrong rule, unknown key.

import base64, json, time, urllib.request
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

def b64u(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))

def verify(token, keys, payee=None, rule=None, now=None):
    """Offline. keys = {kid: base64 Ed25519}, your pinned copy. -> (code, claims)"""
    try:
        pre, body, sig = token.split(".")
        c = json.loads(b64u(body))
    except Exception:
        return "malformed", None
    if pre != "mzv1" or c.get("typ") != "mizan.verdict/1": return "malformed", c
    if c.get("kid") not in keys: return "unknown_kid", c
    try:
        Ed25519PublicKey.from_public_bytes(base64.b64decode(keys[c["kid"]])).verify(b64u(sig), f"{pre}.{body}".encode())
    except Exception:
        return "bad_signature", c
    if not c.get("exp", 0) > (now or time.time()): return "expired", c
    bt = c.get("bound_to") or {}
    if payee is not None and str(bt.get("payee", "")).lower() != str(payee).lower(): return "payee_mismatch", c
    if rule is not None and rule not in (c.get("rule"), c.get("rule_id")): return "rule_mismatch", c
    return "valid", c

# pin this copy of the key set; fetch it again only for a key id you do not know
keys = json.load(urllib.request.urlopen("https://studio.mizan.market/api/verdict/keys"))["keys"]
code, claims = verify(token, keys, payee="0xabc…", rule="sha256:2e10…d559")
if code == "valid" and claims["decision"] == "ALLOW":
    release_payment()                     # no call to MIZAN was made
needs cryptographyconformance vectors

Test your own verifier with the same vectors: curl -sO https://mizan.market/verdict/conformance.py && python3 conformance.py --verifier yourpkg.verdict:verify (or conformance.mjs for Node). Exit 0 only when every vector returns exactly its expected result.

04 Surfaces

Call it from anywhere. Carry it on any rail.

SurfaceWhereWhat you get
HTTPGET https://studio.mizan.market/api/check/<subject>The verdict as the body. OpenAPI
MCPhttps://studio.mizan.market/mcpcheck, require, request_proof, prove, claim_identity. Setup
A2APOST https://studio.mizan.market/a2aThe check skill over message/send. Agent card
x402accepts[i].extra.mizan = {token, kid}Reference facilitator: py · ts
AP2 v0.2Payment Mandate constraint market.mizan.verdictReference verifier: py · ts · schema
Agentic Commerce ProtocolExtension market.mizan.verdictReference verifier: py · ts · schema
Any HTTP requestHeader Mizan-Verdict: mzv1.…Reference verifier: py · ts
Python SDKpip install https://mizan.market/skill/mizan_sdk-0.8.0-py3-none-any.whlCheck, prove and the x402 guard in one package. Quickstart
TypeScriptimport { Mizan } from "https://mizan.market/skill/mizan.mjs"Zero dependencies: fetch and Web Crypto.
Discovery/.well-known/mizan.jsonOne machine-readable map: the call, schema, keys, endpoints, bindings, status. Open

Bindings use each protocol's own extension point; none forks a protocol. MIZAN is not affiliated with the protocols' authors.

05 The recorder

A check is never empty. It shows what was measured, at its grade.

When a subject has no counted record, the default rule still answers REFUSE with reason no_record: unproven is not false, and nothing is loosened. The verdict now also carries a known block: the facts MIZAN measured itself about the service, graded RECORDED, with the window they cover. A fact never measured is shown as unknown, never as zero.

a check of a recorded service · trimmedjson
curl https://studio.mizan.market/api/check/mcp:https://mcp.example.com/mcp

{ "decision": "REFUSE", "reason": "no_record", … rule, token, next.proof_request unchanged …
  "known": {
    "services": [{ "grade": "RECORDED", "measured_by": "MIZAN", "since": "2026-11-04T…Z",
                   "window": { "days": 0.2, "probes": 1 }, "uptime_pct": 100.0,
                   "latency_ms": { "p50": 412, "p95": 412 }, "protocol": { "name": "mcp", "version": "2025-06-18" },
                   "tools": 3 }],
    "identity": { "grade": "DECLARED", "evidence": [{ "kind": "public_listing", … }] },
    "rule": { "id": "mizan.reliability/1" } } }
QuestionAnswer
What is recordedUptime, p50 and p95 latency, error rate, protocol version and tool count, counted from the first probe. One record_opened entry per service goes on the ledger at its first measurement (hashes only); each completed UTC day gets one record_rollup entry committing every probe chain. Never one entry per probe.
Which servicesPublic agent services that publish a URL in a public list: the official MCP registry, the x402 Bazaar, and agent cards served at /.well-known/agent-card.json by those hosts. A client name seen in a log is not an endpoint and is never recorded by itself.
How it probesUser-Agent MIZAN-recorder/1 (+https://mizan.market/developers/#recorder), at most one probe per service per clock hour. MCP: initialize and tools/list only. A2A: a GET of the public agent card. x402: a GET of a public resource without payment (the 402 answer) or a HEAD of the origin. Paid or state-changing calls are never made.
What counts as upThe service answered its protocol, or answered 401/403 asking for authorisation (counted up, marked as auth required). A 429 or a robots refusal is inconclusive and never counted either way. Anything else (timeout, 5xx, a wrong answer) is down.
IdentityGraded by the same rules as every identity block: a public listing is DECLARED; an agent card served on the service's own host, or a domain and an ERC-8004 entry that name each other, is RECORDED. A grade is never raised by anything a caller sends, and an expired check is shown as declared.
Allow on reliabilityThe default rule is unchanged. A requirer that wants to pay on measured reliability says so: ?rule=mizan.reliability/1 allows when uptime is at least 99% over at least 7 measured days (150+ conclusive probes, the last within 3 hours) and p95 latency is at most 2,000 ms. The rule, hashed
Opt outAdd User-agent: MIZAN-recorder / Disallow: / to the host's robots.txt, or email [email protected] from the domain. Probing stops and the record is hidden within 24 hours; the opt-out is appended to the ledger.
Dispute a factEmail [email protected] naming the subject and the fact. A correction is appended to the record and to the ledger; nothing is edited in place, and no service is ever labelled good or bad.

Live: /api/recorder/summary · one record: /api/recorder/record/<subject>

06 Reference

Everything you build against, versioned.

MIZAN is the check an agent runs before it pays. Call it, carry the token, verify it offline.