# Agent-to-agent cards

An **agent card** is metadata a service publishes to let other agents discover its authentication requirements and capabilities. Instead of a human reading a documentation page and configuring their client, an agent reads the card, sees what's needed, and acts — no human in the loop.

By the A2A convention, a resource publishes its card at `/.well-known/agent.json`, relative to its own base URL — the same well-known-path pattern RFC 9728 and Grantor's own discovery document use. Publish yours there so a consuming agent (or an off-the-shelf A2A client) can find it without being told the URL out of band; a consuming agent's first step is fetching `https://<resource-host>/.well-known/agent.json`.

When a Grantor-gated resource refuses a caller with a 401, the response funnel includes `discovery` — the URL where that specific resource publishes its deed requirements. An agent card is the inverse: a pre-flight contract, published before authentication is attempted, that tells an agent "if you want to call me, here is what I require." A card that declares `securitySchemes` with a Grantor deed requirement means: *this resource authenticates with deeds; fetch this URL to learn what deed mode to mint, what the challenge endpoint is, and which chain and tenant gate this resource uses*.

This is how off-the-shelf agents (Claude et al.) discover Grantor-gated resources without a human hand-wiring each one.

## Fragment 1: Agent card deed declaration

An agent card's `securitySchemes` field names the deed scheme and links to the resource's discovery document:

```json
{
  "name": "Acme API",
  "description": "An example resource gated with Grantor deeds",
  "version": "1.0.0",
  "baseUrl": "https://api.example.com",
  "securitySchemes": {
    "grantor-deed": {
      "type": "http",
      "scheme": "Grantor-Deed",
      "description": "Grantor deed (zero-knowledge or wallet-signed)",
      "discovery": "/.well-known/grantor-deed",
      "learn": "https://chaingrantor.com/.well-known/grantor-onboard.json"
    }
  },
  "security": [
    { "grantor-deed": [] }
  ]
}
```

The `discovery` path is **relative to this resource's baseUrl** (so `https://api.example.com/.well-known/grantor-deed` in this example). The `learn` URL is **stable and global** — the same for every Grantor-gated resource anywhere, pointing at the onboarding manifest and its narrative twin, so an agent that has never interacted with Grantor before knows where to start.

## Fragment 2: Consuming-agent recipe

An agent fetches the card from `/.well-known/agent.json`, sees the `grantor-deed` scheme, and follows this recipe:

```
0. Fetch the agent card (if not already fetched):
   GET https://api.example.com/.well-known/agent.json
   → { "securitySchemes": { "grantor-deed": { "discovery": "/.well-known/grantor-deed", … } }, … }

1. Fetch the discovery document:
   GET https://api.example.com/.well-known/grantor-deed
   → { "tenant": 1, "audience": "api.example.com", "challenge_endpoint": "/auth/challenge", "modes": ["user-sig", "agent-zk"], "chain": { "id": 8453, "registry": "0x…" }, "origin_vouch": { … } }

2. Fetch a challenge from the endpoint named in the discovery document:
   GET https://api.example.com/auth/challenge
   → { "challenge": "abc123def…" }

3. Mint a deed. For agent-zk (fleet membership):
   - Verify the origin vouch against the origin you are talking to (https://api.example.com).
   - Build a Semaphore membership proof of this tenant's on-chain agent tree.
   - Mint the deed with the proof and the challenge.
   Result: { "mode": "agent-zk", "proof": "…", "challenge": "…", … }

4. Present the deed and challenge in separate headers:
   POST https://api.example.com/auth/token
   X-Grantor-Deed: <base64url-encoded deed JSON>
   X-Grantor-Challenge: abc123def…
   → { "access_token": "…" } (the resource's own session bearer)
```

The deed (`X-Grantor-Deed` header) and challenge are always separate — never read the challenge from inside the deed, which would let an attacker pick its own nonce and break the single-use property.

The `learn` URL (from the card) points an agent to the onboarding flow if it is not yet a tenant: it names the chain, funding, tier fees, and contract calls to become a tenant and enroll an agent key.

## Bridge to RFC 9728

This agent-card scheme serves the same discovery purpose as [RFC 9728 OAuth 2.0 Protected Resource Metadata](https://www.rfc-editor.org/rfc/rfc9728), which a resource also publishes at a well-known path (`/.well-known/oauth-protected-resource`) for off-the-shelf OAuth clients to discover. In that case, the client is shaped by the OAuth 2.0 spec and reads the metadata there. Here, the agent is shaped by the agent card and reads the discovery document — which is identical in both cases (same `tenant`, `audience`, `challenge_endpoint`, `modes`, `chain`, `origin_vouch`). An MCP-spec client that speaks OAuth 2.0 can use the RFC 9728 path; an agent following this pattern uses the agent card. Both point at the same document.

## See also

- [Agent onboarding](../agents/onboarding.md) — once enrolled, the full `agent-zk` recipe.
- [MCP server auth](mcp-server.md) — deed-gated MCP servers, which publish both a discovery document and an agent-facing card.
- [Verify a deed](verify-tokens.md) — the RP-side verification path.
- [Self-onboarding](../ONBOARD.md) — becoming a tenant and enrolling an agent key.
