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:
handle(required): the public address the credential lives at, made of lowercase letters, digits, and hyphens. The passport is published at/a/{handle}.agent_name(optional): a human-readable display name.disclose_wallet(optional): whentrue, the owner wallet is written into the credential as an accountable-owner fact. When omitted orfalse, the owner stays out of the public passport.
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
| Field | Meaning |
|---|---|
verified_runs | Agent runs whose hash chain verified. |
anchored_runs | Runs whose head hash was anchored on-chain. |
receipts | Signed receipts issued to the account. |
metered_events | Metered units of compute recorded. |
metered_spend_micro_usd | Total metered spend, in millionths of a dollar. |
active_mandates | Live spending mandates bounding the agent. |
operates_under_budget_caps | Whether the agent runs under budget caps. |
first_seen | First 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:
- It states facts drawn from the agent's own history. It is not a trust, safety, or quality score.
- Sable does not vouch that the agent is trustworthy or that its outputs are correct. Correctness of a specific execution is a separate guarantee, carried by the confidential tier and per-run attestation, not by a passport.
- Disclosing the owner wallet names who stands behind the agent. It is accountability, not endorsement.
For the underlying artifacts a passport summarizes, see Verifiable receipts, agent runs, and Spending mandates.