Agent Card in A2A: Full JSON Example and Field Breakdown
An Agent Card is a JSON document that tells a client agent whom to call, where to send a task, and which skills are available. In the A2A (Agent2Agent) protocol the card is usually published at /.well-known/agent-card.json: without it an agent is hard to discover; with a vague description it is hard to route correctly.
- Agent Card - public contract of an agent's capabilities
- Discovery - finding the card via a well-known URL or a registry
- skills - concrete abilities, not a generic "I can do everything"
- capabilities - streaming, push notifications, extended card
- security - OpenAPI-style authentication schemes
Why You Need an Agent Card
A2A connects independent agents: one acts as a client, another as an executor. Before sending a task, the client reads the card and answers:
- Does this agent match the user's intent?
- Which endpoint accepts tasks?
- Which MIME types are supported on input and output?
- Is authentication required, and which kind?
- Are event streaming and webhook notifications supported?
The card is not marketing copy. Orchestrators and LLM routers parse it. The more precise description, skills, and examples are, the more stable executor selection becomes.
Full JSON Example
Below is a working card for an agent that searches products on a site, calculates pricing, and creates a lead after user confirmation. Fields use camelCase, as in typical A2A JSON cards.
{
"name": "Site Commerce Agent",
"description": "Searches the site catalog, calculates price and delivery time, and creates a lead after user confirmation. Works with catalog, draft cart, and order statuses. Does not process payments or change prices.",
"version": "1.2.0",
"protocolVersion": "0.3.0",
"url": "https://api.example.com/a2a",
"documentationUrl": "https://docs.example.com/a2a/commerce-agent",
"iconUrl": "https://example.com/icons/commerce-agent.svg",
"provider": {
"organization": "Example Shop",
"url": "https://example.com"
},
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitionHistory": true,
"extendedAgentCard": false
},
"defaultInputModes": [
"text/plain",
"application/json"
],
"defaultOutputModes": [
"text/plain",
"application/json"
],
"skills": [
{
"id": "search-products",
"name": "Product search",
"description": "Searches products by query, category, price, and availability. Returns candidates with id, title, price, and a short description.",
"tags": ["catalog", "search", "products"],
"examples": [
"Find laptops under 800 EUR with delivery this week",
"Show available plans for a team of 20 people"
],
"inputModes": ["text/plain", "application/json"],
"outputModes": ["application/json", "text/plain"]
},
{
"id": "calculate-quote",
"name": "Quote calculation",
"description": "Calculates price, taxes, shipping, and ETA for selected items and quantities. Does not create an order.",
"tags": ["pricing", "quote", "shipping"],
"examples": [
"Calculate the cost of 3 units of product_id=sku-1042 with delivery to Berlin",
"Compare Basic and Pro plans for 50 users"
],
"inputModes": ["application/json", "text/plain"],
"outputModes": ["application/json"]
},
{
"id": "create-lead",
"name": "Lead creation",
"description": "Creates a draft lead or request after explicit user confirmation. Requires contact details and consent for data processing.",
"tags": ["lead", "order-draft", "crm"],
"examples": [
"Create a Pro plan request for ACME, contact: ops@acme.example",
"Create an order draft from quote_id=q-7781"
],
"inputModes": ["application/json"],
"outputModes": ["application/json", "text/plain"]
},
{
"id": "get-order-status",
"name": "Order status",
"description": "Returns payment and delivery status by order_id for an authenticated user or a public tracking number.",
"tags": ["orders", "status", "tracking"],
"examples": [
"What is the status of order ORD-20441?",
"Where is the parcel with tracking number TRK-998877?"
]
}
],
"securitySchemes": {
"bearer": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
},
"oauth2": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.example.com/oauth/token",
"scopes": {
"catalog:read": "Read catalog and quotes",
"leads:write": "Create leads",
"orders:read": "Read order statuses"
}
}
}
}
},
"security": [
{
"oauth2": ["catalog:read"]
},
{
"bearer": []
}
]
}
In A2A v1.0 the endpoint is often described with a supportedInterfaces array instead of a single top-level url. The idea is the same: tell the client where to send tasks and which binding to use (JSONRPC, HTTP+JSON, GRPC, and so on).
v1.0 fragment example:
{
"supportedInterfaces": [
{
"url": "https://api.example.com/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
]
}
Top-Level Field Breakdown
| Field | Required | Purpose |
|---|---|---|
name |
Yes | Human-readable agent name |
description |
Yes | Concrete summary: what it does and what it does not |
version |
Yes | Agent implementation version (semver preferred) |
url / supportedInterfaces |
Yes* | Task endpoint(s), not the card URL |
skills |
Yes | At least one skill |
capabilities |
Recommended | Honest capability flags |
defaultInputModes / defaultOutputModes |
Recommended | Default MIME types |
provider |
No | Owning organization |
documentationUrl / iconUrl |
No | Docs and UI icon |
protocolVersion |
Depends on schema | Protocol version (often top-level in v0.3) |
securitySchemes / security |
No | How the client should authenticate |
* In v0.3 schemas url is usually required. In v1.0 supportedInterfaces takes over the endpoint role.
name and description
name is for people and logs. description is for routers. Bad: "A helpful site agent". Good: list operations, limits, and result shape.
version
This is the agent implementation version, not necessarily the protocol version. Bump major for breaking changes in skills or response contracts. Clients may cache the card and refresh it when the version changes.
url - a common mistake
url is where message/send / tasks go. It is not the path to /.well-known/agent-card.json.
Wrong:
"url": "https://example.com/.well-known/agent-card.json"
Right:
"url": "https://api.example.com/a2a"
capabilities
| Flag | Meaning |
|---|---|
streaming |
Supports streaming responses (SSE / stream) |
pushNotifications |
Webhook notifications for long-running tasks |
stateTransitionHistory |
History of task status transitions |
extendedAgentCard |
After auth, an extended/private card is available |
Set true only if the behavior is actually implemented. A client that opens a stream against a non-streaming agent will get an error.
defaultInputModes and defaultOutputModes
Default MIME types for the whole agent. A skill can override them. Typical values: text/plain, application/json, application/pdf, image/png.
skills Breakdown
A skill is a routing unit. One skill = one clear capability.
| Field | Required | Notes |
|---|---|---|
id |
Yes | Unique within the agent; kebab-case works well |
name |
Yes | Short UI label |
description |
Yes | Inputs, outputs, and limits |
tags |
No | Keywords for search and filtering |
examples |
No, but strongly recommended | 2-3 real prompts for orchestrators |
inputModes / outputModes |
No | MIME overrides for this skill |
Examples are not decoration. Without them an orchestrator model guesses inputs from the description alone and fails more often.
Bad skill:
{
"id": "website",
"name": "Website",
"description": "Works with the website"
}
A good skill looks like the ones in the full example: concrete id, clear boundaries, tags, and examples.
Authentication: securitySchemes and security
Schemes usually follow the OpenAPI approach:
apiKeyhttp(Basic / Bearer)oauth2openIdConnectmutualTLS
securitySchemes describes available methods. security sets the default requirement:
- multiple objects in the
securityarray = alternatives (OR); - multiple keys in one object = all required (AND).
Publish how to authenticate, not secrets. Do not put API keys, refresh tokens, or internal hostnames in the JSON.
Discovery: How Cards Are Found
Typical flow:
- The client knows the agent's base domain.
- It requests
https://agent.example.com/.well-known/agent-card.json. - It validates required fields.
- It picks a skill by description, tags, and examples.
- It authenticates using
security. - It sends the task to
url/supportedInterfaces.
Cards are also published in registries or agent directories. Discovery then goes through search, while well-known remains the owner's source of truth.
Local check:
curl -s https://api.example.com/.well-known/agent-card.json
What Not to Publish in an Agent Card
- API keys, passwords, private keys;
- unprotected internal admin or staging URLs;
- operations unavailable to external clients;
- inflated capabilities (
streaming: truewithout implementation); - vague skills like "does everything on the site".
A public card is both an attack surface and a routing surface. Keep it precise and minimally sufficient.
Common Mistakes
- Confusing
urlwith the card URL. - Empty
skillsarray. The agent becomes almost unroutable. - Description without boundaries. Missing what the agent does not do (payment, deletion, price changes).
- No
examples. Orchestrators understand valid input worse. - localhost in a production card. The endpoint must be reachable by clients.
- One skill for the whole product. Prefer several narrow skills with different rights and MIME types.
Mini Checklist Before Publishing
- The card is served over HTTPS with
Content-Type: application/json. - It has
name,description,version, an endpoint, and at least one skill. - Descriptions are concrete.
- Key skills have
examplesandtags. capabilitiesmatch the real server.- The JSON contains no secrets.
- The endpoint from the card answers a test task.
- Version bumps on breaking changes.
Takeaway
An Agent Card is the main discovery contract in A2A. A complete JSON with precise skills, honest capabilities, and explicit security gives client agents enough data to find the right executor and avoid calling the wrong one.
If you need help designing an Agent Card, an A2A server, or wiring an agent to a site API - contact me.
Frequently Asked Questions
Where should the Agent Card live?
The standard public path is /.well-known/agent-card.json on the agent domain. You can also register the card in a catalog or registry, but the well-known URL remains a convenient discovery point without a separate index.
How is url different from the card address?
The card address is for discovery; url (or supportedInterfaces) is for task execution. The client first reads the JSON card, then sends messages/tasks to the agent's working endpoint.
How many skills should a card have?
As many as you have truly distinct abilities with different inputs or permissions. Usually 3-7 narrow skills beat one generic "do everything". Clear boundaries, tags, and examples matter for routing.
Is authentication required in an Agent Card?
Not always. A public read-only agent may omit security. For writes, personal data, and paid operations, declare securitySchemes and security, and keep secrets outside the card.
Should I update the card on every deploy?
Update it when skills, endpoint, capabilities, auth, or the agent's meaning change. A technical patch without contract changes can be reflected in version; breaking changes deserve a major bump and explicit docs.