docs / guide

view as .md

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 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.

When a Grantor-gated resource refuses a caller with a 401, the response funnel includes discovery — the URL where that resource publishes its deed requirements. An agent card is the inverse: a pre-flight contract, published before authentication is attempted, telling an agent what it requires before it ever gets a 401. A card declaring securitySchemes with a Grantor deed requirement points at that same discovery URL, which names the deed mode, challenge endpoint, chain, and tenant.

Fragment 1: Agent card deed declaration#

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

{
  "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 (https://api.example.com/.well-known/grantor-deed here). The learn URL is stable and global — the same for every Grantor-gated resource, pointing at the onboarding manifest so an agent new to Grantor 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 points an agent that is not yet a tenant to the onboarding flow: 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, which a resource publishes at /.well-known/oauth-protected-resource for off-the-shelf OAuth clients. An MCP-spec client that speaks OAuth 2.0 uses the RFC 9728 path; an agent following this pattern uses the card. Both point at the same discovery document (same tenant, audience, challenge_endpoint, modes, chain, origin_vouch).

See also#

This page is also served as Markdown — agents should read that. The whole tree is indexed for machines in llms.txt.