{"openapi":"3.1.0","info":{"title":"Agent Output Verifier by SarnAI","description":"Independent verification of AI agent output before you pay: check an AI agent's JSON against your JSON Schema and business rules (totals, unique IDs). Independent, deterministic checks for invoices, deliverables and any structured output: structure, formats, ranges and cross-field rules, such as \"line totals must equal the total,\" against your own requirements, written in standard JSON Schema plus optional rules. Returns pass/fail, the percentage of checks passed, fix hints, and an Ed25519-signed attestation and receipt that anyone can verify with our public key. Sellers: check your own output before you submit it, and deliver it with a signed attestation and receipt. No signup: pay per call with x402 v2, in USDC on Base or Solana. 1,000 free checks a day per caller, then $0.02 per check (x402, USDC on Base or Solana). AI Agent Scores: $0.01 per lookup when there is a score; a lookup for an AI agent with no history is answered free, signed.\n\n`POST /verify/schema` (also offered as `POST /verify/deliverable`: the same check, shape, signed attestation and receipt, price and networks) is $0.02 USDC per call and `GET /score/{agent_id}` is $0.01 USDC per call, both paid via x402 in USDC on Base or Solana (an unpaid request gets HTTP 402, which lists the options in the `Payment-Required` response header; a paid request's signed payment rides in the `Payment-Signature` request header, and a settled response's settlement receipt rides in the `Payment-Response` response header). A `fail` result is a complete, valid answer and is charged the same as a `pass`.\n\n**Payment errors:** every 402 body is a structured `payment_error` - a stable `error_code` (`no_payment`, `malformed_payment`, `unsupported_payment_version`, `no_matching_requirements`, `amount_mismatch`, `recipient_mismatch`, `invalid_signature`, `expired_authorization`, `payment_already_used`, `insufficient_funds`, `facilitator_unreachable`, `facilitator_error`), a clean `message`, `charged: false`, `retryable`/`retry_after`, the current `payment_terms`, and `next_actions` - identical on REST and in MCP's `structuredContent.payment_error`. See the 402 response below for what each code means.\n\n**Free verification:** 1,000 free checks a day per caller, then $0.02 per check (x402, USDC on Base or Solana). One counter is shared by the MCP tool `verify_schema` (`POST /mcp`) and the REST routes `POST /verify/schema` and `POST /verify/deliverable`, where a valid unpaid request is served free and says what is left in the `Free-Allowance-Remaining`, `Free-Allowance-Limit` and `Free-Allowance-Resets` response headers. An unpaid request that needs payment gets a 402 whose body reports this caller's own remaining free allowance.\n\n**AI Agent Scores:** `GET /score/{agent_id}` and the MCP tool `get_verification_record` are $0.01 per lookup when there is a score, with no free allowance; a lookup for an AI agent with no history (or a reserved `test-` id) is answered free, signed, with `reason: no_data`, on REST and through the MCP tool.\n\n**Errors:** every error other than a payment error has one shape (`code`, `message`, `status`, `retryable`, `charged`, `next_actions`; validation errors add a `fields` list naming each bad field and how to fix it), on REST and in MCP tool results, and the caller's input is never echoed. An invalid request is rejected with 422 before anything is verified or settled; an unpaid request to a paid route always gets the 402 challenge, an empty or invalid one with `request_problems`, and GET/HEAD on the verify routes get the same challenge. Every error response (4xx and 5xx, every route) carries a `guidance` block: what to do, a minimal valid example, the price and how to pay, the free-allowance note and the llms.txt link; a 5xx also says nothing was charged and when to retry. The live free-allowance numbers are stated in one place, the \"Free allowance\" section of `/llms.txt`.\n\n**Versions:** `verifier_version` (in every /verify/schema and /score response) names a signed attestation and receipt's own shape and behavior; this page's `version` above (and the agent-card's) names the service build as a whole, and the MCP Registry listing carries its own version for the listing itself. They move independently, by design.","version":"0.5.8"},"paths":{"/health":{"get":{"summary":"Health Check","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Check Health Get"}}}}}},"head":{"summary":"Health Check","operationId":"health_check_health_head","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Check Health Head"}}}}}}},"/verify/schema":{"post":{"summary":"Verify Schema","operationId":"verify_schema_verify_schema_post","parameters":[{"name":"client_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"}},{"name":"Payment-Signature","in":"header","required":false,"schema":{"type":"string"},"description":"The caller's signed x402 v2 payment (base64). Omit it to receive 402 with the price and requirements in the Payment-Required response header instead."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifySchemaRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VerifySchemaResponse"},{"$ref":"#/components/schemas/CompactVerifySchemaResponse"}],"title":"Response Verify Schema Verify Schema Post"}}},"headers":{"Payment-Response":{"description":"Settlement receipt (base64 JSON) once a paid call settles on-chain.","schema":{"type":"string"}}}},"422":{"description":"Invalid request: bad JSON, a missing field, a wrong type, an unknown rule type, an over-long id, with a payment attached (an UNPAID invalid request gets the 402 challenge instead, with `request_problems`); `fields` names each bad field and how to fix it. Nothing is verified or charged, and the input is never echoed.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"402":{"description":"Payment required (x402 v2) - see the Payment-Required response header for the price and requirements. The body is always a structured `payment_error` (stable `error_code`, a clean `message`, `charged: false`, `retryable`/`retry_after`, `payment_terms`, and `next_actions`), the same shape MCP returns in `structuredContent.payment_error`, merged with a `free_trial` note when the free trial is on.","headers":{"Payment-Required":{"description":"x402 v2 payment requirements (base64 JSON): price, network(s) and pay-to address.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"payment_error":{"type":"object","properties":{"error_code":{"type":"string","enum":["no_payment","malformed_payment","unsupported_payment_version","no_matching_requirements","amount_mismatch","recipient_mismatch","invalid_signature","expired_authorization","payment_already_used","insufficient_funds","facilitator_unreachable","facilitator_error"],"description":"- `no_payment`: No payment was attached to the request.\n- `malformed_payment`: The payment is unreadable as an x402 v2 payment: its header is invalid base64 or JSON (REST), its `x402/payment` meta is anything other than a JSON object (MCP), `x402Version` is absent, or a required member (`accepted` with its scheme, network, asset, amount, payTo and maxTimeoutSeconds; `payload`) is absent or has the wrong type. A payment the facilitator reports as unreadable is classed the same way. The message names the member, never its value.\n- `unsupported_payment_version`: The payment declares an x402 version other than 2 (for example 1); only v2 is accepted. A v2 payment that is merely incomplete is malformed_payment instead.\n- `no_matching_requirements`: The payment's declared scheme, network or asset differs from every one of this call's accepted payment options.\n- `amount_mismatch`: The signed payment authorization is for less than the required price.\n- `recipient_mismatch`: The signed payment authorization pays an address other than this service's own.\n- `invalid_signature`: The payment authorization's signature fails to verify.\n- `expired_authorization`: The payment authorization's validity window has already passed, or has yet to begin.\n- `payment_already_used`: This exact payment (the same nonce) has already been spent.\n- `insufficient_funds`: The paying wallet holds less balance than this payment requires to settle on-chain.\n- `facilitator_unreachable`: The payment facilitator was unreachable (network/timeout).\n- `facilitator_error`: The facilitator rejected the payment for a reason outside this service's known set, with nothing in particular singled out as the cause."},"message":{"type":"string","description":"A clean, human-readable sentence - never a raw exception or facilitator JSON."},"charged":{"type":"boolean","description":"Always false: none of these codes represent a settled payment."},"retryable":{"type":"boolean","description":"Whether resubmitting (the same payment, or a corrected one) can succeed."},"retry_after":{"type":["integer","null"],"description":"Seconds to wait before retrying, when retryable and the failure is transient (facilitator-side)."},"payment_terms":{"type":"object","description":"The same accepts[]/resource a fresh unpaid request to this route would receive."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next step(s), same pattern as a verification result's next_actions."},"free_trial_status":{"type":"string","description":"One-line free-trial status, present only when relevant."}},"required":["error_code","message","charged","retryable","retry_after","payment_terms","next_actions"]},"free_trial":{"type":"object","description":"Present when the free trial is on - see GET /llms.txt's Free trial section."}},"required":["payment_error"]}}}},"400":{"description":"`schema_invalid` (expected_schema is an invalid JSON Schema) or `validation_timeout` (the pair took too long to validate). Not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"413":{"description":"The request body is over the size limit (`limits.max_request_body_bytes`).","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"429":{"description":"Too many requests, or too many validations running for this client; see `retry_after`.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"503":{"description":"Every validation worker was busy; retry after `retry_after`. Not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}}}}},"/verify/deliverable":{"post":{"summary":"Verify Deliverable","description":"The same check as POST /verify/schema, offered under a name an AI agent shopping for\n\"check this deliverable\" finds more readily (2026-10-02 storefront test). Strictly a\nsecond entry point: same request model, same engine, same receipt (including its\nattestation context, so any /verify/schema verifier verifies these receipts unchanged),\nsame price - it differs from /verify/schema only in its catalog listing (its own payment\ndescription, tags and Bazaar example in app.core.payments).","operationId":"verify_deliverable_verify_deliverable_post","parameters":[{"name":"client_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"}},{"name":"Payment-Signature","in":"header","required":false,"schema":{"type":"string"},"description":"The caller's signed x402 v2 payment (base64). Omit it to receive 402 with the price and requirements in the Payment-Required response header instead."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifySchemaRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VerifySchemaResponse"},{"$ref":"#/components/schemas/CompactVerifySchemaResponse"}],"title":"Response Verify Deliverable Verify Deliverable Post"}}},"headers":{"Payment-Response":{"description":"Settlement receipt (base64 JSON) once a paid call settles on-chain.","schema":{"type":"string"}}}},"422":{"description":"Invalid request: bad JSON, a missing field, a wrong type, an unknown rule type, an over-long id, with a payment attached (an UNPAID invalid request gets the 402 challenge instead, with `request_problems`); `fields` names each bad field and how to fix it. Nothing is verified or charged, and the input is never echoed.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"402":{"description":"Payment required (x402 v2) - see the Payment-Required response header for the price and requirements. The body is always a structured `payment_error` (stable `error_code`, a clean `message`, `charged: false`, `retryable`/`retry_after`, `payment_terms`, and `next_actions`), the same shape MCP returns in `structuredContent.payment_error`, merged with a `free_trial` note when the free trial is on.","headers":{"Payment-Required":{"description":"x402 v2 payment requirements (base64 JSON): price, network(s) and pay-to address.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"payment_error":{"type":"object","properties":{"error_code":{"type":"string","enum":["no_payment","malformed_payment","unsupported_payment_version","no_matching_requirements","amount_mismatch","recipient_mismatch","invalid_signature","expired_authorization","payment_already_used","insufficient_funds","facilitator_unreachable","facilitator_error"],"description":"- `no_payment`: No payment was attached to the request.\n- `malformed_payment`: The payment is unreadable as an x402 v2 payment: its header is invalid base64 or JSON (REST), its `x402/payment` meta is anything other than a JSON object (MCP), `x402Version` is absent, or a required member (`accepted` with its scheme, network, asset, amount, payTo and maxTimeoutSeconds; `payload`) is absent or has the wrong type. A payment the facilitator reports as unreadable is classed the same way. The message names the member, never its value.\n- `unsupported_payment_version`: The payment declares an x402 version other than 2 (for example 1); only v2 is accepted. A v2 payment that is merely incomplete is malformed_payment instead.\n- `no_matching_requirements`: The payment's declared scheme, network or asset differs from every one of this call's accepted payment options.\n- `amount_mismatch`: The signed payment authorization is for less than the required price.\n- `recipient_mismatch`: The signed payment authorization pays an address other than this service's own.\n- `invalid_signature`: The payment authorization's signature fails to verify.\n- `expired_authorization`: The payment authorization's validity window has already passed, or has yet to begin.\n- `payment_already_used`: This exact payment (the same nonce) has already been spent.\n- `insufficient_funds`: The paying wallet holds less balance than this payment requires to settle on-chain.\n- `facilitator_unreachable`: The payment facilitator was unreachable (network/timeout).\n- `facilitator_error`: The facilitator rejected the payment for a reason outside this service's known set, with nothing in particular singled out as the cause."},"message":{"type":"string","description":"A clean, human-readable sentence - never a raw exception or facilitator JSON."},"charged":{"type":"boolean","description":"Always false: none of these codes represent a settled payment."},"retryable":{"type":"boolean","description":"Whether resubmitting (the same payment, or a corrected one) can succeed."},"retry_after":{"type":["integer","null"],"description":"Seconds to wait before retrying, when retryable and the failure is transient (facilitator-side)."},"payment_terms":{"type":"object","description":"The same accepts[]/resource a fresh unpaid request to this route would receive."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next step(s), same pattern as a verification result's next_actions."},"free_trial_status":{"type":"string","description":"One-line free-trial status, present only when relevant."}},"required":["error_code","message","charged","retryable","retry_after","payment_terms","next_actions"]},"free_trial":{"type":"object","description":"Present when the free trial is on - see GET /llms.txt's Free trial section."}},"required":["payment_error"]}}}},"400":{"description":"`schema_invalid` (expected_schema is an invalid JSON Schema) or `validation_timeout` (the pair took too long to validate). Not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"413":{"description":"The request body is over the size limit (`limits.max_request_body_bytes`).","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"429":{"description":"Too many requests, or too many validations running for this client; see `retry_after`.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"503":{"description":"Every validation worker was busy; retry after `retry_after`. Not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}}}}},"/.well-known/agent-card":{"get":{"summary":"Agent Card","operationId":"agent_card__well_known_agent_card_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Agent Card  Well Known Agent Card Get"}}}}}}},"/.well-known/agent-card.json":{"get":{"summary":"Agent Card","operationId":"agent_card__well_known_agent_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Agent Card  Well Known Agent Card Json Get"}}}}}}},"/.well-known/x402":{"get":{"summary":"X402 Discovery Manifest","operationId":"x402_discovery_manifest__well_known_x402_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response X402 Discovery Manifest  Well Known X402 Get"}}}}}}},"/reputation/{agent_id}":{"get":{"summary":"Get Reputation","operationId":"get_reputation_reputation__agent_id__get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","title":"Agent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/score/{agent_id}":{"get":{"summary":"Get Trust Score","operationId":"get_trust_score_score__agent_id__get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\x00-\\x1f\\x7f]+$","description":"The agent_id whose verification history to score (as passed to /verify/schema): the AI agent that produced the output checked by those calls (for example, the seller). agent_ids starting with 'test-' are reserved for testing and never have a history.","title":"Agent Id"},"description":"The agent_id whose verification history to score (as passed to /verify/schema): the AI agent that produced the output checked by those calls (for example, the seller). agent_ids starting with 'test-' are reserved for testing and never have a history."},{"name":"Payment-Signature","in":"header","required":false,"schema":{"type":"string"},"description":"The caller's signed x402 v2 payment (base64). Omit it to receive 402 with the price and requirements in the Payment-Required response header instead."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrustScoreResponse"}}},"headers":{"Payment-Response":{"description":"Settlement receipt (base64 JSON) once a paid call settles on-chain.","schema":{"type":"string"}}}},"422":{"description":"Invalid request: bad JSON, a missing field, a wrong type, an unknown rule type, an over-long id, with a payment attached (an UNPAID invalid request gets the 402 challenge instead, with `request_problems`); `fields` names each bad field and how to fix it. Nothing is verified or charged, and the input is never echoed.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}},"402":{"description":"Payment required (x402 v2) - see the Payment-Required response header for the price and requirements. The body is always a structured `payment_error` (stable `error_code`, a clean `message`, `charged: false`, `retryable`/`retry_after`, `payment_terms`, and `next_actions`), the same shape MCP returns in `structuredContent.payment_error`, merged with a `free_trial` note when the free trial is on.","headers":{"Payment-Required":{"description":"x402 v2 payment requirements (base64 JSON): price, network(s) and pay-to address.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"payment_error":{"type":"object","properties":{"error_code":{"type":"string","enum":["no_payment","malformed_payment","unsupported_payment_version","no_matching_requirements","amount_mismatch","recipient_mismatch","invalid_signature","expired_authorization","payment_already_used","insufficient_funds","facilitator_unreachable","facilitator_error"],"description":"- `no_payment`: No payment was attached to the request.\n- `malformed_payment`: The payment is unreadable as an x402 v2 payment: its header is invalid base64 or JSON (REST), its `x402/payment` meta is anything other than a JSON object (MCP), `x402Version` is absent, or a required member (`accepted` with its scheme, network, asset, amount, payTo and maxTimeoutSeconds; `payload`) is absent or has the wrong type. A payment the facilitator reports as unreadable is classed the same way. The message names the member, never its value.\n- `unsupported_payment_version`: The payment declares an x402 version other than 2 (for example 1); only v2 is accepted. A v2 payment that is merely incomplete is malformed_payment instead.\n- `no_matching_requirements`: The payment's declared scheme, network or asset differs from every one of this call's accepted payment options.\n- `amount_mismatch`: The signed payment authorization is for less than the required price.\n- `recipient_mismatch`: The signed payment authorization pays an address other than this service's own.\n- `invalid_signature`: The payment authorization's signature fails to verify.\n- `expired_authorization`: The payment authorization's validity window has already passed, or has yet to begin.\n- `payment_already_used`: This exact payment (the same nonce) has already been spent.\n- `insufficient_funds`: The paying wallet holds less balance than this payment requires to settle on-chain.\n- `facilitator_unreachable`: The payment facilitator was unreachable (network/timeout).\n- `facilitator_error`: The facilitator rejected the payment for a reason outside this service's known set, with nothing in particular singled out as the cause."},"message":{"type":"string","description":"A clean, human-readable sentence - never a raw exception or facilitator JSON."},"charged":{"type":"boolean","description":"Always false: none of these codes represent a settled payment."},"retryable":{"type":"boolean","description":"Whether resubmitting (the same payment, or a corrected one) can succeed."},"retry_after":{"type":["integer","null"],"description":"Seconds to wait before retrying, when retryable and the failure is transient (facilitator-side)."},"payment_terms":{"type":"object","description":"The same accepts[]/resource a fresh unpaid request to this route would receive."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next step(s), same pattern as a verification result's next_actions."},"free_trial_status":{"type":"string","description":"One-line free-trial status, present only when relevant."}},"required":["error_code","message","charged","retryable","retry_after","payment_terms","next_actions"]},"free_trial":{"type":"object","description":"Present when the free trial is on - see GET /llms.txt's Free trial section."}},"required":["payment_error"]}}}},"429":{"description":"Too many requests, or too many validations running for this client; see `retry_after`.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","schema_invalid","validation_timeout","unencodable_content","request_too_large","invalid_content_type","not_found","method_not_allowed","rate_limited","too_many_concurrent_validations","service_busy","internal_error","unknown_tool"],"description":"- `invalid_request`: A field is missing, has the wrong type, is outside its limits or holds a value outside the allowed set. `fields` lists each one with how to fix it.\n- `invalid_json`: The body is malformed JSON, or is something other than a single JSON object.\n- `schema_invalid`: `expected_schema` is an invalid JSON Schema.\n- `validation_timeout`: The schema/output pair took too long to validate (too complex).\n- `unencodable_content`: The request contains a lone (unpaired) Unicode surrogate, which the signature format rejects.\n- `request_too_large`: The request body is over the size limit. `limits` gives it.\n- `invalid_content_type`: The request's Content-Type names a type other than JSON. Send the same JSON body with Content-Type: application/json.\n- `not_found`: No such route.\n- `method_not_allowed`: The route exists for other HTTP methods only. `limits.allowed_methods` lists them.\n- `rate_limited`: Too many requests from this client (or a daily cap); retry after the `Retry-After` seconds.\n- `too_many_concurrent_validations`: Too many validations already running for this client; retry shortly.\n- `service_busy`: Every validation worker was busy; retry shortly.\n- `internal_error`: The service failed while handling the request. Nothing was charged; retry after `retry_after` seconds.\n- `unknown_tool`: MCP: no tool with that name. `limits.tools` lists the tools."},"message":{"type":"string","description":"One sentence a person can act on. Never repeats the caller's input."},"status":{"type":"integer","description":"The HTTP status (also present in MCP tool errors)."},"retryable":{"type":"boolean","description":"Whether sending the same request again can succeed."},"retry_after":{"type":["integer","null"],"description":"Present on a retryable error: seconds to wait, or null."},"charged":{"type":"boolean","description":"Always false: an error is never charged."},"next_actions":{"type":"array","items":{"type":"object"},"description":"Machine-readable next steps."},"fields":{"type":"array","description":"Validation errors (422): one entry per bad field, at most ten.","items":{"type":"object","properties":{"field":{"type":"string","description":"Where, as a path: `rules[0].type`."},"problem":{"type":"string"},"fix":{"type":"string"}},"required":["field","problem","fix"]}},"fields_total":{"type":"integer","description":"Present when more fields were bad than are listed."},"limits":{"type":"object","description":"The numbers that apply (a size limit, the allowed methods, the tool list)."},"detail":{"description":"Kept for older clients: FastAPI's former `detail` (never the caller's input)."}},"required":["code","message","status","retryable","charged","next_actions"]}}}}}}},"/robots.txt":{"get":{"summary":"Robots Txt","description":"Everything is allowed; the sitemap line names the host the crawler asked (app.api.routes.discovery_files).","operationId":"robots_txt_robots_txt_head","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}},"head":{"summary":"Robots Txt","description":"Everything is allowed; the sitemap line names the host the crawler asked (app.api.routes.discovery_files).","operationId":"robots_txt_robots_txt_head","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/.well-known/security.txt":{"get":{"summary":"Security Txt","operationId":"security_txt__well_known_security_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/mcp":{"post":{"summary":"MCP (Streamable HTTP)","description":"Exposes verify_schema (POST /verify/schema) and get_verification_record (GET /score/{agent_id}) as Model Context Protocol tools, over Streamable HTTP (JSON-RPC 2.0) rather than this page's plain REST shape - see the mcp extension in /.well-known/agent-card.json for the full tool list, schemas and free-trial terms. Its JSON-RPC envelope is not expressed as request/response schema here.","tags":["mcp"],"responses":{"200":{"description":"A JSON-RPC 2.0 response."}}}}},"components":{"schemas":{"Attestation":{"properties":{"algorithm":{"type":"string","const":"Ed25519","title":"Algorithm"},"key_version":{"type":"string","title":"Key Version"},"timestamp":{"type":"string","title":"Timestamp"},"signature":{"type":"string","title":"Signature"}},"type":"object","required":["algorithm","key_version","timestamp","signature"],"title":"Attestation"},"Bound":{"properties":{"min":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Min"},"max":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Max"},"if_present":{"type":"boolean","title":"If Present","description":"Optional. When true, the check is skipped where this field is absent (the whole path, or an element of an array it applies to) instead of being reported as unable to run: no flag, and enforce_rules does not fail on it. When false (default) an absent field is a flag, and a failure under enforce_rules.","default":false}},"type":"object","title":"Bound","description":"Optional inclusive min/max for one field. Numbers, or ISO-8601 date /\ndatetime strings (compared as datetimes; naive values are treated as UTC)."},"CompactVerifySchemaResponse":{"properties":{"summary":{"$ref":"#/components/schemas/Summary"},"next_actions":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Next Actions"},"result":{"type":"string","enum":["pass","fail"],"title":"Result"},"verification_id":{"type":"string","title":"Verification Id"},"task_id":{"type":"string","title":"Task Id"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Id"},"output_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Hash"},"schema_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schema Hash"},"rules_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rules Hash"},"verified_at":{"type":"string","title":"Verified At"},"verifier_version":{"type":"string","title":"Verifier Version"},"enforce_rules":{"type":"boolean","title":"Enforce Rules"},"strict_content_check":{"type":"boolean","title":"Strict Content Check"},"verify":{"$ref":"#/components/schemas/VerifySection"},"attestation":{"$ref":"#/components/schemas/Attestation"}},"additionalProperties":false,"type":"object","required":["summary","next_actions","result","verification_id","task_id","agent_id","output_hash","schema_hash","rules_hash","verified_at","verifier_version","enforce_rules","strict_content_check","verify","attestation"],"title":"CompactVerifySchemaResponse","description":"The `\"detail\": \"compact\"` response shape (verifier_version 0.4.0): the same summary,\nnext_actions, result, receipt fields, verify and attestation as VerifySchemaResponse -\nsame field order, same values - with errors, errors_detail, flags, hints and the scores\nleft out entirely (not emptied). Still fully signed: attest() runs on exactly this\nshape, not on a full response with fields hidden afterward.\n\n`extra=\"forbid\"` (unlike the pydantic default) is deliberate: FastAPI's\n`response_model=VerifySchemaResponse | CompactVerifySchemaResponse` picks whichever\nmember actually validates, and without this a \"full\" dict would also satisfy this\nmodel (pydantic's default is to silently ignore fields a model doesn't declare),\nnon-deterministically returning a full response shaped as compact."},"ConsistencyRule":{"properties":{"type":{"type":"string","enum":["sum_equals","gte","lte","exists_in","unique"],"title":"Type"},"field":{"type":"string","title":"Field"},"equals_field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Equals Field"},"equals":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"null"}],"title":"Equals"},"other_field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Other Field"},"value":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"},{"type":"null"}],"title":"Value"},"in_field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"In Field"},"values":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Values"},"tolerance":{"type":"number","minimum":0.0,"title":"Tolerance","description":"Absolute tolerance for sum_equals and the near-match check gte/lte use. The default (1e-9) suits exact arithmetic but is usually too tight for money that passed through any floating-point math (e.g. percentage discounts, tax, unit-price * quantity): 0.1 + 0.2 != 0.3 in IEEE-754 floats by about 5.5e-17, and real pricing data regularly carries larger rounding drift than that. For a field in major currency units (dollars, euros), 0.01 (one cent) is a reasonable tolerance; for minor units (cents) already stored as integers, the default is fine. Too loose a tolerance can mask a genuine mismatch, so prefer the smallest value that tolerates your data's own rounding, not a large one 'to be safe.'","default":1e-09},"if_present":{"type":"boolean","title":"If Present","description":"Optional. When true, the check is skipped where this field is absent (the whole path, or an element of an array it applies to) instead of being reported as unable to run: no flag, and enforce_rules does not fail on it. When false (default) an absent field is a flag, and a failure under enforce_rules. Applies to this rule's own `field`; fields it refers to (equals_field, other_field, in_field) must still exist.","default":false}},"type":"object","required":["type","field"],"title":"ConsistencyRule","description":"One caller-supplied cross-field rule. Paths use dotted keys with '[]'\nas an array wildcard, e.g. 'items[].price' or 'order.total'.\n\n  sum_equals: sum of `field` values == `equals_field` value (or `equals`)\n  gte / lte:  `field` >= / <= `other_field` value (or `value`)\n  exists_in:  every `field` value is among `in_field` values (or `values`)\n  unique:     no duplicates among `field` values; if `field` names an\n              array itself, no duplicate elements in it"},"ErrorDetail":{"properties":{"check":{"type":"string","title":"Check","description":"Same meaning as Hint.check."},"path":{"type":"string","title":"Path","description":"Same meaning as Hint.path."},"expected":{"type":"string","title":"Expected","description":"Same meaning as Hint.expected."},"found":{"type":"string","title":"Found","description":"Same meaning as Hint.found."},"message":{"type":"string","title":"Message","description":"The matching entry in `errors`, verbatim."}},"type":"object","required":["check","path","expected","found","message"],"title":"ErrorDetail","description":"The structured form of one entry in `errors`, at the same index, so a caller can act\non a violation without parsing its text (verifier_version 0.4.0). Same shape as the\nmatching `Hint` (check, path, expected, found), plus the original text for compatibility.\nOnly the first errors_detail_total entries get one, same cap as hints (MAX_DETAILS /\nMAX_STRICT_ERRORS below) - a formatted string is far cheaper to keep than a structured\none; see errors_detail_total / errors_detail_omitted."},"Flag":{"properties":{"check":{"type":"string","title":"Check"},"field":{"type":"string","title":"Field"},"severity":{"type":"string","enum":["info","error"],"title":"Severity","description":"'error' when enforce_rules made this specific bound/rule finding fail the result (see VerifySchemaRequest.enforce_rules); 'info' otherwise. Never affects `result` itself - `result` is decided by `errors`, of which this finding is then also a member.","default":"info"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["check","field","detail"],"title":"Flag"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Hint":{"properties":{"source":{"type":"string","enum":["schema","integrity"],"title":"Source","description":"'schema': a JSON Schema validation failure (one per entry in `errors`, same order). 'integrity': a strict-content failure or an informational flag."},"check":{"type":"string","title":"Check","description":"The JSON Schema keyword that failed (type, required, minimum, ...), or the integrity check (strict_content_check, placeholder_content, truncation, bounds, consistency:*, unhashable_input)."},"path":{"type":"string","title":"Path","description":"Where, as a JSON path: '$.items[3].price'. For a missing required property, the path where it should be. Integrity hints use the flag's own field notation with a '$.' prefix."},"expected":{"type":"string","title":"Expected","description":"What the check wanted at that path, from a fixed template (e.g. 'number')."},"found":{"type":"string","title":"Found","description":"What was there instead, from a fixed template (e.g. 'string', 'missing', '-1'). Long values are shortened; whole values are never echoed."}},"type":"object","required":["source","check","path","expected","found"],"title":"Hint"},"ReputationResponse":{"properties":{"agent_id":{"type":"string","title":"Agent Id"},"found":{"type":"boolean","title":"Found"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"total_calls":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Calls"},"pass_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pass Count"},"fail_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fail Count"},"pass_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pass Rate"}},"type":"object","required":["agent_id","found"],"title":"ReputationResponse"},"ScoreFactor":{"properties":{"name":{"type":"string","title":"Name","description":"Stable identifier of this factor."},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value","description":"Factor value in [0, 1]; null when it cannot be computed (see the response's `reason`)."},"confidence_interval_95":{"anyOf":[{"items":{"type":"number"},"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Confidence Interval 95","description":"[lower, upper] 95% Wilson score interval; null when value is null."},"sample_size":{"type":"integer","title":"Sample Size","description":"Raw number of verification calls behind this factor, all history."},"effective_sample_size":{"type":"number","title":"Effective Sample Size","description":"Sum of the recency weights: how many 'recent-equivalent' observations the history is worth. This, not sample_size, is what the interval is computed from."},"parameters":{"additionalProperties":{"anyOf":[{"type":"number"},{"type":"integer"},{"type":"string"}]},"type":"object","title":"Parameters","description":"Parameters in force, so the value can be reproduced."}},"type":"object","required":["name","value","confidence_interval_95","sample_size","effective_sample_size","parameters"],"title":"ScoreFactor","description":"One input to the score. v1 has exactly one; later versions add entries here."},"SubScore":{"properties":{"ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ratio","description":"passed / total, a raw float in [0, 1]; null when total is 0 (nothing was checked). Informational only: never affects `result`."},"passed":{"type":"integer","title":"Passed"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["ratio","passed","total"],"title":"SubScore"},"Summary":{"properties":{"result":{"type":"string","enum":["pass","fail"],"title":"Result","description":"Same value as the top-level `result`."},"blocking_checks":{"items":{"type":"string"},"type":"array","title":"Blocking Checks","description":"Distinct check codes that caused 'fail' (the same codes used in `errors_detail[].check`, `flags[].check` and `hints[].check`), in first-seen order; empty on 'pass'."}},"type":"object","required":["result","blocking_checks"],"title":"Summary","description":"Compact digest of the verdict, for a caller that wants the headline without reading\n`errors`/`flags` (verifier_version 0.4.0)."},"TrustScoreResponse":{"properties":{"agent_id":{"type":"string","title":"Agent Id","description":"Identifies the AI agent that produced the output checked by the /verify/schema calls this score is built from (for example, the seller): this record belongs to that producer."},"identity_verified":{"type":"boolean","title":"Identity Verified","description":"Whether agent_id is bound to a proven identity. Currently always false: agent_id is an unauthenticated label chosen by whoever called /verify/schema, so this history may include calls made by anyone under that id, and the score says nothing about who the AI agent really is. It flips to true only if and when identity is actually authenticated."},"trust_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Trust Score","description":"Recency-weighted pass rate as a raw float in [0.0, 1.0]; null when there is nothing meaningful to report (see `reason`). A statistical summary of structural verification history, not a measure of overall trustworthiness and not a prediction of future behavior."},"sample_size":{"type":"integer","title":"Sample Size","description":"Total verification calls on record for this agent_id."},"confidence_interval_95":{"anyOf":[{"items":{"type":"number"},"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Confidence Interval 95","description":"[lower, upper] 95% Wilson score interval around trust_score, computed from the effective (recency-discounted) sample size. Wide = little recent evidence."},"basis":{"type":"string","title":"Basis","description":"Names the formula behind trust_score. Its meaning never changes under the same name; a different formula gets a different basis."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"null when scored. 'no_data': no verification history at all. 'insufficient_recent_data': history exists but has decayed to under 0.05 effective observations."},"factors":{"items":{"$ref":"#/components/schemas/ScoreFactor"},"type":"array","title":"Factors","description":"The inputs behind trust_score. v1 has one entry; consumers should ignore entries they don't recognize, so factors can be added without breaking them."},"verified_count":{"type":"integer","title":"Verified Count","description":"Raw number of /verify/schema calls on record for this agent_id (all history, no recency weighting). Equals sample_size."},"passed_count":{"type":"integer","title":"Passed Count","description":"How many of those calls returned result 'pass'."},"failed_count":{"type":"integer","title":"Failed Count","description":"How many of those calls returned result 'fail'."},"last_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen","description":"ISO-8601 UTC time of the most recent verification on record; null when there is none. Like agent_id itself, this reflects calls made under this label by anyone."},"computed_at":{"type":"string","title":"Computed At","description":"ISO-8601 UTC time the score was computed; ages are measured from here."},"verify":{"$ref":"#/components/schemas/VerifySection","description":"How to verify this attestation and receipt without any other lookup than this response and public_key_url: canonicalization and hash algorithm, this service's name, and its MCP endpoint."},"attestation":{"$ref":"#/components/schemas/Attestation","description":"Ed25519 signature over this response (every field above) with the same key as /verify/schema, under the context 'json-schema-verifier/trust-score-attestation/v1'. Verification steps: /.well-known/agent-card.json."}},"type":"object","required":["agent_id","identity_verified","trust_score","sample_size","confidence_interval_95","basis","reason","factors","verified_count","passed_count","failed_count","last_seen","computed_at","verify","attestation"],"title":"TrustScoreResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifySchemaRequest":{"properties":{"task_id":{"type":"string","maxLength":200,"minLength":1,"pattern":"^[^\\x00-\\x1f\\x7f]+$","title":"Task Id","description":"Your own identifier for this verification. 1-200 printable characters, no control characters and no lone Unicode surrogate; a request outside that range is rejected (422), not truncated."},"expected_schema":{"additionalProperties":true,"type":"object","title":"Expected Schema","description":"Required. The JSON Schema (draft-04 to 2020-12) that submitted_output must satisfy: your own requirements, as a JSON object."},"submitted_output":{"title":"Submitted Output","description":"Required. The output being checked: any JSON value (object, array, string, number, boolean or null), exactly as the AI agent produced it."},"agent_id":{"anyOf":[{"type":"string","maxLength":200,"minLength":1,"pattern":"^[^\\x00-\\x1f\\x7f]+$"},{"type":"null"}],"title":"Agent Id","description":"Optional label identifying the AI agent that produced submitted_output (for example, the seller), used for /reputation and the trust score: records and scores belong to the producer, not to whoever calls this endpoint. It is an unauthenticated label. agent_ids starting with 'test-' are reserved for testing: the verification runs normally but is never recorded, so it cannot affect any reputation or trust score. 1-200 printable characters (same rule as GET /score/{agent_id}); a longer or malformed value is rejected (422), not truncated."},"strict_content_check":{"type":"boolean","title":"Strict Content Check","description":"Opt-in. When true, any string in submitted_output containing control characters (e.g. null bytes) or embedded HTML/script markup makes the result 'fail'. When false (default) this is not checked at all.","default":false},"bounds":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/Bound"},"type":"object","maxProperties":50},{"type":"null"}],"title":"Bounds","description":"Optional per-field min/max, keyed by dotted path with '[]' array wildcard (e.g. 'items[].price'). Numbers or ISO-8601 dates. Violations are reported as informational flags unless enforce_rules is true."},"rules":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConsistencyRule"},"type":"array","maxItems":50},{"type":"null"}],"title":"Rules","description":"Optional cross-field rules: sum_equals, gte, lte, exists_in, unique (duplicate detection). Violations are reported as informational flags unless enforce_rules is true."},"enforce_rules":{"type":"boolean","title":"Enforce Rules","description":"Opt-in. When true, every configured bound and consistency rule must hold, or the result is 'fail' (like strict_content_check), with an 'enforce_rules: ...' entry in errors. That includes a rule or bound that cannot run (its path is missing, a value is not comparable, a value has nothing to be compared against): it fails rather than passing silently, so omitting a field, in the whole path or in any array element the rule applies to, cannot skip a binding rule. A rule or bound with if_present: true is skipped where its field is absent instead. When false (default) nothing changes: violations and unrunnable rules stay informational flags. Echoed back in the signed response.","default":false},"detail":{"type":"string","enum":["full","compact"],"title":"Detail","description":"'full' (default) returns everything; 'compact' returns only the summary, next actions, receipt and signature. Use compact inside verify-repair loops to save tokens. 'compact' fields: summary, next_actions, result, the receipt fields (verification_id, task_id, agent_id, output_hash, schema_hash, rules_hash, verified_at, verifier_version, enforce_rules, strict_content_check), verify and attestation - errors, errors_detail, flags, hints and the scores are left out entirely, not just emptied. Both shapes are fully signed.","default":"full"}},"type":"object","required":["task_id","expected_schema","submitted_output"],"title":"VerifySchemaRequest"},"VerifySchemaResponse":{"properties":{"summary":{"$ref":"#/components/schemas/Summary","description":"Compact digest of the verdict: the same `result`, and `blocking_checks` (the distinct check codes that caused a 'fail', empty on 'pass') - for a caller that wants the headline without reading `errors`/`flags`."},"next_actions":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Next Actions","description":"What to do next, machine-readable. On 'fail': [{\"action\": \"repair_and_reverify\", \"using\": \"hints\"}, {\"action\": \"withhold_payment\", \"for\": \"buyer\"}]. On 'pass': [{\"action\": \"attach_receipt\", \"for\": \"seller\"}, {\"action\": \"proceed_to_payment\", \"for\": \"buyer\"}], plus a {\"action\": \"consider_enforce_rules\", \"note\": ...} entry when enforce_rules is false (only the JSON Schema was checked). A plain list of string-keyed objects (not a stricter per-action model): the two shapes share only `action`, and a `for` field could not be a Python attribute name without an alias that REST and MCP risk serializing differently."},"result":{"type":"string","enum":["pass","fail"],"title":"Result"},"verification_id":{"type":"string","title":"Verification Id","description":"Unique UUID (v4) for this verification. Part of the signed attestation and receipt."},"task_id":{"type":"string","title":"Task Id"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Id","description":"Echo of the agent_id label supplied in the request; null if none. Identifies the AI agent that produced submitted_output (for example, the seller): this attestation and receipt, and any reputation or trust score it feeds, belongs to that producer. It is an unauthenticated label chosen by the caller, not a proven identity, and not the identity of whoever called this endpoint."},"output_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Hash","description":"SHA-256 (64 lowercase hex chars = 32 bytes; add 0x to use it as a bytes32) of the JCS canonical JSON of submitted_output, the data that was verified. Key order and whitespace in what you sent do not change it. null only if it has no JCS form (NaN/Infinity, a lone surrogate)."},"schema_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schema Hash","description":"SHA-256 (64 lowercase hex chars) of the JCS canonical JSON of expected_schema. null only if it has no JCS form."},"rules_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rules Hash","description":"SHA-256 (64 lowercase hex chars) of the RFC 8785 (JCS) canonical JSON of {\"bounds\": <the bounds you supplied or null>, \"rules\": <the rules you supplied or null>}, containing exactly the fields you supplied (fields left at their defaults are not included), so you can hash your own rules JSON in that shape and compare. It lets a buyer confirm which rules were applied. null when no bounds or rules were supplied (or they contain NaN/Infinity)."},"request_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Hash","description":"SHA-256 (64 lowercase hex chars, no 0x prefix) of the RFC 8785 (JCS) canonical JSON of the request as parsed: task_id, agent_id, expected_schema, submitted_output, strict_content_check, bounds, rules, enforce_rules, with defaults filled in (agent_id/bounds/rules null, strict_content_check and enforce_rules false). Inside bounds and rules, every PER-RULE field is also filled to its own default, not just the ones you supplied: an omitted consistency-rule field hashes as equals_field/equals/other_field/value/in_field/values: null, tolerance: 1e-9, if_present: false, and an omitted bound field hashes as if_present: false - so two requests whose rules/bounds differ only by which optional fields were typed out still hash identically here. This is the opposite convention from rules_hash (below), which hashes exactly and only the fields you supplied, with nothing defaulted in - hash your own rules JSON in rules_hash's documented shape if you need to confirm which rules were applied without re-deriving every default. null only if the request contains data with no JCS form (NaN/Infinity, a lone surrogate). Not part of the 'compact' detail level."},"verified_at":{"type":"string","title":"Verified At","description":"ISO-8601 UTC time this service ran the verification. Identical to attestation.timestamp (the same value, read once); this service's own clock, not an externally verified time."},"verifier_version":{"type":"string","title":"Verifier Version"},"enforce_rules":{"type":"boolean","title":"Enforce Rules","description":"Whether the request had enforce_rules on: true means every rule and bound had to hold (violations and unrunnable rules fail the result); false means they were only flags."},"strict_content_check":{"type":"boolean","title":"Strict Content Check","description":"Whether the request had strict_content_check on: true means control characters and embedded HTML/script markup in submitted_output failed the result; false means that check did not run."},"errors":{"items":{"type":"string"},"type":"array","title":"Errors","description":"Every violation (schema, then strict-content, then enforce_rules), capped at the first 100 schema-validation errors; see errors_total / errors_omitted. Non-schema errors (strict-content, enforce_rules) are never capped. Not part of the 'compact' detail level."},"errors_total":{"type":"integer","title":"Errors Total","description":"How many errors exist in total. Equal to len(errors) unless the 100-error schema cap above was hit."},"errors_omitted":{"type":"integer","title":"Errors Omitted","description":"errors_total minus len(errors); 0 when nothing was cut off."},"errors_detail":{"items":{"$ref":"#/components/schemas/ErrorDetail"},"type":"array","title":"Errors Detail","description":"The structured form of the leading entries in `errors`, same order, so a caller can act (check, path, expected, found) without parsing text; `errors` itself is unchanged, for compatibility. See errors_detail_total / errors_detail_omitted for how many entries in `errors` this covers."},"errors_detail_total":{"type":"integer","title":"Errors Detail Total","description":"How many entries in `errors` have a structured form available. Same cap as `hints` (a structured form costs more to build than the text alone)."},"errors_detail_omitted":{"type":"integer","title":"Errors Detail Omitted","description":"errors_total minus errors_detail_total; 0 when every error has a structured form."},"flags":{"items":{"$ref":"#/components/schemas/Flag"},"type":"array","title":"Flags","description":"Integrity findings (placeholder text, possible truncation, bounds and consistency-rule violations). severity is 'error' for a finding that enforce_rules made fail the result, 'info' otherwise; either way, a flag never itself changes 'result' - it is `errors` that does. Not part of the 'compact' detail level."},"flags_total":{"type":"integer","title":"Flags Total","description":"How many flags exist in total (flags holds at most the first 100, plus a flags_truncated marker when there are more), counting an unhashable_input flag if present."},"flags_omitted":{"type":"integer","title":"Flags Omitted","description":"Integrity flags beyond the 100 returned; 0 when nothing was cut off."},"hints":{"items":{"$ref":"#/components/schemas/Hint"},"type":"array","title":"Hints","description":"Machine-actionable, template-based fix hints: one per schema validation failure (first, in the same order as `errors`), then per strict-content failure and integrity flag. At most 20; see hints_total / hints_omitted. Where, what was expected, what was found. Never a guessed corrected value. Not part of the 'compact' detail level."},"hints_total":{"type":"integer","title":"Hints Total","description":"How many hints exist in total (hints holds at most the first 20)."},"hints_omitted":{"type":"integer","title":"Hints Omitted","description":"hints_total minus len(hints)."},"schema_compliance":{"$ref":"#/components/schemas/SubScore","description":"JSON Schema assertions that passed out of those evaluated (each keyword such as type/required/minimum, at each place it applies; anyOf/oneOf/not/if count once, applicators like properties and items are not counted themselves). A separate figure from integrity_checks: the two ratios are never averaged (see `overall` for the pooled count). Informational: `result` is decided by errors, not by this. Not part of the 'compact' detail level."},"integrity_checks":{"$ref":"#/components/schemas/SubScore","description":"Integrity checks that passed out of those evaluated (per string: placeholder and truncation, plus strict content when enabled; per schema-described object: completeness; per configured bound and consistency-rule comparison). Informational: only strict_content_check failures (and enforce_rules violations, if enabled) can change `result`. Not part of the 'compact' detail level."},"overall":{"$ref":"#/components/schemas/SubScore","description":"A pooled count across both groups: (schema_compliance.passed + integrity_checks.passed) / (schema_compliance.total + integrity_checks.total), with those two sums as passed and total. It is NOT an average of the two ratios (the larger group weighs more), and it says nothing about whether the content is right. null ratio when the total is 0. Informational only: never changes `result`. Not part of the 'compact' detail level."},"verify":{"$ref":"#/components/schemas/VerifySection","description":"How to verify this attestation and receipt without any other lookup than this response and public_key_url: canonicalization and hash algorithm behind every hash and the signature itself, this service's name, and its MCP endpoint."},"attestation":{"$ref":"#/components/schemas/Attestation","description":"Ed25519 signature over this response (every field above, including the receipt fields) plus the timestamp and key_version. The timestamp is this service's own clock, not an externally verified one. Public key and verification steps: /.well-known/agent-card.json, capabilities.extensions (attestation entry)."}},"type":"object","required":["summary","next_actions","result","verification_id","task_id","agent_id","output_hash","schema_hash","rules_hash","request_hash","verified_at","verifier_version","enforce_rules","strict_content_check","errors","errors_total","errors_omitted","errors_detail_total","errors_detail_omitted","flags_total","flags_omitted","hints","hints_total","hints_omitted","schema_compliance","integrity_checks","overall","verify","attestation"],"title":"VerifySchemaResponse"},"VerifySection":{"properties":{"public_key_url":{"type":"string","title":"Public Key Url","description":"Agent-card URL listing the public key for key_version below, and every key this service has ever signed with."},"key_version":{"type":"string","title":"Key Version","description":"Matches attestation.key_version."},"canonicalization":{"type":"string","title":"Canonicalization","description":"How every hash below, and the signed bytes themselves, are computed."},"hash_algorithm":{"type":"string","title":"Hash Algorithm","description":"Algorithm behind every *_hash field in this response."},"service":{"type":"string","title":"Service","description":"This service's name."},"mcp":{"type":"string","title":"Mcp","description":"This service's MCP (Model Context Protocol) endpoint."}},"type":"object","required":["public_key_url","key_version","canonicalization","hash_algorithm","service","mcp"],"title":"VerifySection","description":"Compact, self-describing block every signed attestation and receipt carries (2026-09-30,\nverifier_version 0.4.0) - inside the signature, alongside `attestation` itself - so a\nverifier needs nothing but this response and the URL below, not a separate lookup or\nprior knowledge of this service's conventions."}}}}