MIZAN / Developers / The verdict / Codes
Every code, what it means, what fixes it.
Every code a verdict, a verifier, a payment binding or the API can return. A code is never renamed or given a new meaning; a change ships as a new version and the old codes keep theirs.
Reason codes.
claims.reason on a REFUSE verdict: exactly one code. Fixed for mizan.verdict/1.
| Code | Meaning | What would pass |
|---|---|---|
no_record | Nothing is on record for this subject that the rule can read. Not an accusation: unproven is not false. | a record for this subject that meets the rule; its owner proves it once and the next check returns ALLOW |
below_bar | A record exists, but it does not meet the rule. | a passing record in good standing that meets every part of the rule |
too_few_tries | The record has fewer counted tries than the rule requires. | a record with at least the number of counted tries the rule requires |
expired | Something the answer depends on has expired (a receipt, or the record's standing). | a fresh receipt or a renewed record, then check again |
revoked | The subject's record was revoked. | a new record in good standing; a revoked record never passes |
superseded | The subject's record was replaced by a later one; check that one. | check the record that replaced this one |
rule_unknown | The rule could not be found or understood, so nothing can be allowed under it. | a published rule (req_…@version) or a rule in plain words that compiles: POST /api/requirements/compile |
subject_unresolved | The subject could not be resolved to exactly one party. | one exact identifier for the party: a credential id, an agent id (ag_…), a wallet, a domain or an endpoint |
payee_mismatch | The payee named for the payment is not the subject that was checked. | check the party you will pay: subject and payee must name the same party |
Rule-specific codes.
A failed part of a rule that no reason code above describes. Never dropped silently.
| Code | Meaning | Fix |
|---|---|---|
receipt_invalid | A receipt supplied with the check did not verify or does not belong to this subject. | drop the receipt or supply one MIZAN issued for this subject, unexpired; then check again |
integrity_bundle_hash | The record's bundle hash is missing. | the record is incomplete; its owner re-publishes it; until then do not pay on it |
integrity_log_inclusion | The record is not included in the public ledger. | the record is not in the public ledger; its owner re-publishes it; until then do not pay on it |
check_unavailable | The check could not be completed; do not pay on this answer. | check again; if it persists, see the status page. Do not pay on this answer |
rule:<check> | Any other failed part of a rule keeps its own stable code, named after the check. | read details for that check, resolve it, then check again |
Verification codes.
What an offline verifier returns (verify_token / verifyToken, POST /api/verdict/verify). ok is true only for valid. Every reference verifier returns these; the conformance vectors pin them.
| Code | Meaning | Fix |
|---|---|---|
valid | The signature verified offline with a listed key, the token is unexpired, and every expectation you passed held. | Proceed only if claims.decision is ALLOW. |
malformed | Not a mzv1 token, not decodable, or typ is not mizan.verdict/1. | Pass the token exactly as served (mzv1.<claims>.<sig>). |
unknown_kid | The token's kid is not in your key set. | Refresh the key set once from /.well-known/mizan-keys.json; if the kid is still absent, refuse. |
bad_signature | The signature does not verify: the claims were changed or another key signed them. | Refuse. Ask MIZAN for a fresh verdict. |
expired | exp is at or before now. | Check again for a fresh verdict. |
payee_mismatch | The token is not bound to the payee you are paying (bound_to.payee; 0x addresses compare case-insensitively). | Check the party you will pay, with payee= set to it. |
rule_mismatch | The token was not issued under the rule you require (claims.rule hash or claims.rule_id). | Check again under your rule. |
revoked | Offline the token verifies, but its live status is revoked. | Refuse. Check again. |
superseded | Offline the token verifies, but its live status is superseded by a later verdict. | Check again. |
status_unknown | The live status you read was not one of good, revoked, superseded, expired. | Read the status again; fail closed meanwhile. |
Payment binding codes.
What a payment-side verifier returns for a verdict carried with x402, AP2, ACP or the HTTP header, in addition to the verification codes.
| Code | Meaning | Fix |
|---|---|---|
no_verdict | No MIZAN verdict was carried with the payment. | Payer: check first, then attach the token to the payment. |
no_payee | The payment names no payee (x402 payTo, AP2 payee, ACP merchant). | Name the payee in the payment. |
kid_mismatch | The kid carried beside the token is not the key that signed it. | Carry the kid from the token's claims. |
refused | The token verifies, but MIZAN's decision in it is REFUSE. | Do not pay. The reason code is in claims.reason. |
unresolved_constraint | AP2: the mandate's constraint is not a market.mizan.verdict constraint this verifier understands. | Use constraint {type: market.mizan.verdict, rule}. |
bad_token | Reference facilitators: the token did not decode or its signature did not verify (bad_signature or malformed). | Refuse. Ask MIZAN for a fresh verdict. |
Verdict status.
GET /api/verdict/status/<jti>. A guard reads status when online and honours expiry when not.
| State | Meaning |
|---|---|
good | The verdict stands until exp. |
revoked | MIZAN withdrew the verdict before exp; refuse. |
superseded | A later verdict replaced it; check again. |
expired | exp has passed. |
API errors.
A separate group from the reason codes. An error is not a decision: never pay on one. Every API error carries {"error": "<text>", "code", "message", "request_id", "next"}, where next is the call that fixes it; the verdict routes carry {"error": {"code", "message", "request_id"}}.
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
invalid_request | 400 | The request is not one MIZAN understands (bad id, missing or malformed body, bad parameter). | Fix the request as the message says; next names the right call. |
unauthorized | 401 | The route needs an API key or session and none (or an invalid one) was sent. | Send Authorization: Bearer <key>; claim one free with POST /api/agents/claim. Checks need no key. |
forbidden | 403 | The key or session is valid but lacks the role this route needs. | Use a public route, or the owner's key. |
not_found | 404 | No such verdict, record or route. | Check the id; an unknown route replies with the nearest routes in next. |
method_not_allowed | 405 | The route exists but not for this HTTP method. | Use the method next names (most reads are GET). |
rate_limited | 429 | Too many requests in the window. | Wait Retry-After seconds; X-RateLimit-* headers show the budget. |
internal_error | 500 | MIZAN failed to answer. | Retry; see the status page. Never pay on an error. |
internal | 500 | The same as internal_error, as the verdict routes spell it (mizan.verdict/1; kept, never renamed). | Retry; see the status page. Never pay on an error. |
SDK codes.
Codes the SDKs add when no verdict could be read.
| Code | Meaning | Fix |
|---|---|---|
mismatch | SDK check(): the token does not carry the decision the reply showed. | Treat as REFUSE; check again. |
unreachable | SDK: MIZAN could not be reached. | Do not pay on this answer; retry later. |
http_<status> | SDK: MIZAN answered with an HTTP error that carried no error body. | Do not pay on this answer; retry later. |
An error is not a decision. Never pay on one.