Verifier API & integration contract

Verify a passport

GET /api/v1/verify/{passport_id}
Headers (optional for basic status; required for quota-counted verifier use):
  X-API-Key: apkey_…

Returns: status (unverified | active | suspended | revoked), operator_verified, operator name, domain, issued_at, band with its stated inputs and rule, the signed issuance credential, and a freshly signed status attestation (Ed25519). Verify signatures against /.well-known/passport-signing-key.json. Completed keyed calls count exactly once against the plan quota (Pro 5,000/mo · Team 25,000/mo); failed calls are free.

Look up by domain

GET /api/v1/lookup?domain=agent.example.com

Returns the most relevant passport for that domain in the same shape as verify.

File a behaviour report (paid verifier keys only)

POST /api/v1/reports   X-API-Key: apkey_…
{"passport_id":"AP-…","category":"abuse|fraud|impersonation|spam|policy_violation|good_behavior|other",
 "evidence_ref":"your-case-or-log-reference","note":"what happened"}

Rate-limited per key; each verifier's effect on a band is capped — see methodology.

Status history

GET /api/v1/passports/{passport_id}/history

Policy-condition contract (for AgentGate and other policy engines)

A policy condition consumes exactly one registry read — it never writes here:

CONDITION passport_admissible:
  GET /api/v1/verify/{passport_id}  (with the policy engine's verifier key)
  ADMIT only if: response.status == "active"
             AND response.operator_verified == true
             AND response.band != "flagged"        # if the policy requires it
  The verify response's signed status attestation is the evidence a
  condition may cite. This registry publishes status; it never publishes
  per-site access policy itself — policy stays with the policy engine.

MandateGuard already reads this contract in its authorize flow: a suspended or revoked passport denies, under a policy that requires it. The AgentGate-side condition hook follows this same contract.