# Agent Card Anatomy — A field-by-field walkthrough

> A field-by-field walkthrough of the v1.0 Agent Card schema with a complete worked example, JWS signing flow, and JWKS validation pattern. Companion to the main field guide. Last refresh: 2026-05-08.

## A complete worked example

A fully populated v1.0 Agent Card for a fictional KYC-review agent at `https://kyc.example.com`. This is what a calling agent would receive from `https://kyc.example.com/.well-known/agent-card.json`.

```json
{
  "name": "AcmeCorp KYC Review Agent",
  "description": "Reviews KYC document packages and returns a risk score with explanations.",
  "url": "https://kyc.example.com/a2a",
  "protocolVersion": "1.0",
  "provider": { "name": "AcmeCorp", "url": "https://acmecorp.example/" },
  "iconUrl": "https://kyc.example.com/icon.svg",
  "documentationUrl": "https://kyc.example.com/docs",
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "stateTransitionHistory": true
  },
  "defaultInputModes": ["text", "file", "structured"],
  "defaultOutputModes": ["text", "structured"],
  "skills": [
    {
      "id": "kyc.review.individual",
      "name": "Individual KYC review",
      "description": "Review a document package for an individual customer (passport, proof-of-address, selfie) and return a risk score.",
      "tags": ["kyc", "individual", "risk-scoring"],
      "examples": ["Review the attached passport + utility bill for John Doe."],
      "inputModes": ["file", "structured"],
      "outputModes": ["structured"]
    },
    {
      "id": "kyc.review.entity",
      "name": "Entity KYC review",
      "description": "Review a corporate KYC package (incorporation docs, UBO disclosures, sanctions screening) and return a risk score.",
      "tags": ["kyc", "entity", "ubo", "sanctions"],
      "examples": ["Review the corporate package for AcmeCo Ltd."],
      "inputModes": ["file", "structured"],
      "outputModes": ["structured"]
    }
  ],
  "securitySchemes": {
    "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" },
    "oauth2": {
      "type": "oauth2",
      "flows": {
        "clientCredentials": {
          "tokenUrl": "https://auth.acmecorp.example/oauth2/token",
          "scopes": {
            "kyc:read": "Read KYC review results",
            "kyc:write": "Submit KYC review tasks"
          }
        }
      }
    }
  },
  "security": [{ "bearerAuth": [] }, { "oauth2": ["kyc:read", "kyc:write"] }],
  "signatures": [
    {
      "protected": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDUta2V5LTAxIn0",
      "signature": "<base64url-encoded JWS signature over the canonicalised body>"
    }
  ]
}
```

## Field groups

### Identity
- `name` (required) — short human-readable name.
- `description` (required) — 1–2 sentence summary.
- `url` (required) — JSON-RPC endpoint. HTTPS in production.
- `protocolVersion` (required) — A2A version supported (`"1.0"` as of 2026).
- `provider` (recommended) — issuing organisation: `name` + `url`.
- `iconUrl`, `documentationUrl` (optional) — human-facing metadata.

### Capabilities flags
- `streaming` — server pushes partial task updates over Server-Sent Events.
- `pushNotifications` — server posts task results to a webhook.
- `stateTransitionHistory` — server retains and exposes a history of task state transitions for audit.

### Modalities
`defaultInputModes` and `defaultOutputModes` declare default content types. Each skill can override per-skill. Canonical values: `text`, `file`, `structured`.

### Skills
Each skill is `{id, name, description, tags, examples, inputModes, outputModes}`. The planner agent reads these to match user intent to skill.

### Security schemes
The `securitySchemes` map mirrors OpenAPI 3.x exactly — Bearer, OAuth 2.0, OIDC, mutual TLS, API-Key. The `security` array declares which schemes (or combinations) are required.

### Signatures (JWS)
Array of JWS-format signatures over the canonicalised JSON body. Each: `{protected, signature}`. Signing keys published at `/.well-known/jwks.json`.

## Verification flow (pseudocode)

```
card = http_get_json("https://kyc.example.com/.well-known/agent-card.json")
jwks = http_get_json("https://kyc.example.com/.well-known/jwks.json")

for sig in card.signatures:
    header = base64url_decode(sig.protected)
    key = jwks_lookup(jwks, header.kid)
    canonical_body = canonicalise(card_without_signatures_field)  // RFC 8785
    if not jws_verify(sig, canonical_body, key):
        reject("signature failed verification")
    if not key_bound_to_domain(key, "kyc.example.com"):
        reject("key not bound to domain")

accept(card)
```

## Common production failures

1. **Non-canonical JSON** — sign over RFC 8785 JCS, not arbitrary serialisation.
2. **Static JWKS** — automate key rotation on a calendar.
3. **Wrong `url`** — gate through environment-aware deployment.

## Companion documents

- Main field guide: `/index.md`
- Methodology & bibliography: `/pages/methodology.md`
- A2A spec: https://a2a-protocol.org/latest/specification/
- Reference implementation: https://github.com/a2aproject/A2A
- A2A pillar essay: https://agentsbooks.com/blog/a2a-protocol-explained

*Updated 2026-05-08.*
