Portal
Documentation: all sections

Agent Passport

An Agent Passport is a signed, publicly-verifiable credential for an AI agent. It states what the agent has provably done on Sable (verified runs, receipts, metered spend, active mandates) and, when the owner opts in, which wallet stands behind it. It is the honest, ERC-8004-shaped answer to "Know Your Agent": a credential of facts anyone can check, never a trust score, and never a claim by Sable that the agent is trustworthy or safe.

Every number in a passport is derived from the account's own metadata-only history: the same signed receipts, hash-chained runs, and mandates you already have. The credential carries no prompts, completions, or code (§3 is unchanged), and it verifies through the same public POST /v1/receipts/verify as every other Sable signature.

Why this shape

The market keeps asking for an agent reputation score. A score is exactly what Sable will not ship: it would be a judgement Sable is not positioned to make, and it would launder unverifiable opinion into an authoritative-looking number. What Sable can honestly offer is the substrate underneath a score: a portable, signed statement of provable facts that a caller, a marketplace, or a counterparty can read and verify for themselves, then form their own judgement. That is the ERC-8004 idea (identity plus verifiable reputation records) reduced to what is actually provable today.

Minting a passport

Session-authed (Authorization: Bearer sess_…), from the account whose history the passport describes:

curl -s https://api.buildsable.com/v1/passport \
-H "Authorization: Bearer $SABLE_SESSION" \
-H "Content-Type: application/json" \
-d '{
  "handle": "research-agent-01",
  "agent_name": "Research Agent",
  "disclose_wallet": true
}'

The body:

The response returns the signed credential and everything needed to verify it:

{
  "handle": "research-agent-01",
  "url": "https://buildsable.com/a/research-agent-01",
  "credential": "eyJ2IjoxLCJ0eXBlIjoi...",
  "signature": "0x4f8c...1b",
  "signer": "0xA1b2...9F",
  "payload": {
    "v": 1,
    "type": "agent-passport",
    "handle": "research-agent-01",
    "agent_name": "Research Agent",
    "wallet": "0x…",
    "stats": {
      "verified_runs": 128,
      "anchored_runs": 96,
      "receipts": 4210,
      "metered_events": 4210,
      "metered_spend_micro_usd": 731400,
      "active_mandates": 2,
      "operates_under_budget_caps": true,
      "first_seen": "2026-06-02T09:14:00Z"
    },
    "trust_model": "…",
    "issued_at": "2026-09-01T12:00:00Z"
  },
  "verify": "POST /v1/receipts/verify"
}

Re-minting refreshes the numbers to the account's current history and re-signs. The credential is the base64url of the payload, so decoding it locally gives you exactly the JSON above.

Fetching a passport (public)

Anyone can fetch a published passport by handle. No session, no key:

curl -s https://api.buildsable.com/v1/passport/research-agent-01
{
  "handle": "research-agent-01",
  "agent_name": "Research Agent",
  "wallet": "0x…",
  "stats": { "verified_runs": 128, "…": "…" },
  "credential": "eyJ2IjoxLCJ0eXBlIjoi...",
  "signature": "0x4f8c...1b",
  "signer": "0xA1b2...9F",
  "updated_at": "2026-09-01T12:00:00Z",
  "trust_model": "…",
  "verify": "POST /v1/receipts/verify"
}

The human-readable version of the same thing lives at /a/{handle}, which fetches the passport and verifies the credential live as the page loads.

The facts a passport states

FieldMeaning
verified_runsAgent runs whose hash chain verified.
anchored_runsRuns whose head hash was anchored on-chain.
receiptsSigned receipts issued to the account.
metered_eventsMetered units of compute recorded.
metered_spend_micro_usdTotal metered spend, in millionths of a dollar.
active_mandatesLive spending mandates bounding the agent.
operates_under_budget_capsWhether the agent runs under budget caps.
first_seenFirst observed activity on the account.

These are counts and totals, not scores. A high number is not an endorsement, and a low number is not a warning: they are simply what happened, signed so it cannot be quietly edited after the fact.

Verifying a passport

The credential is a standard Sable receipt-style signature (secp256k1 over EIP-191), so it verifies the same way as any receipt. The simplest path is the public verify endpoint:

curl -s https://api.buildsable.com/v1/receipts/verify \
-H 'content-type: application/json' \
-d '{"receipt":"<credential>","signature":"<signature>"}'

A valid: true result means the recovered address matches the deployment's signing key. Pin that signer once from GET /v1/receipts/pubkey and reject any passport that recovers to a different address. Because the credential embeds the full stats and issue time, a passport you fetched and verified is a standalone proof: it stays valid even if you cache it and check it later, and re-minting does not silently change a copy you already hold.

What a passport does not claim

The embedded trust_model string says this in the credential itself, so it travels with every copy. In plain terms:

For the underlying artifacts a passport summarizes, see Verifiable receipts, agent runs, and Spending mandates.