The short answer
An A2A Agent Card says what an agent can do and how to call it: its name, skills, interfaces and how to authenticate. A Post card says who the agent is: its address, which company runs it, who it acts for and its standing, signed so anyone can check it. The two fit together, because an A2A card can carry a Post identity as an ordinary A2A extension, https://pidgeon.ai/post/a2a/v0, signed with the same key that signs the agent's email and HTTP requests.
What an A2A Agent Card says
Google's A2A is how agents call each other: one agent publishes an Agent Card, conventionally at /.well-known/agent-card.json, and another reads it to learn what it can ask for. As A2A 1.0.0 specifies it (read 4 November 2026), the card carries:
- What the agent is called and does:
name,description, andskills. - How to reach it: its interfaces and transports.
- How to authenticate to it: its security schemes.
- What it supports:
capabilities, includingextensions, a list of named additions the card opts into. - Who provides it:
provider, an organisation name and URL. - Optionally, signatures:
signatures, a list of JWS signatures over the card.
That is a description of capabilities, written by the agent's operator. The provider field is the operator's own statement of who it is. A2A leaves the question of whether that statement is true to whoever reads the card.
What a Post card says
A Post card is the other half. It is a compact JWS (typ: agent-card+jwt, Ed25519), signed by its issuer and fetchable by anyone with no key:
{
"iss": "https://post.pidgeon.email",
"sub": "8f0c…",
"v": "post0",
"address": "research-agent@acme.com",
"kind": "agent",
"on_behalf_of": "Acme Ltd",
"operator": { "domain": "acme.com", "verified": true },
"keys": [{ "type": "post", "domain": "acme.com", "kid": "…" }],
"reputation": { "standing": "new", "since": "2026-11" }
}
operator.verified is true only when the domain's owner proved it, through a DNS record under _post. standing is new for 30 days, restricted while the agent is suspended, and established otherwise. The card is good for a day and is signed again each time it is read, so it is never stale and a revoked one stops answering at once. Every card issued, changed or revoked is also an entry in a public, append-only log.
The two cards answer different questions. Nothing in a Post card says what the agent can do, and nothing in an A2A card proves who is behind it.
A Post identity inside an A2A card
Post uses two mechanisms A2A already has, so an A2A client needs nothing new.
An extension. An entry in capabilities.extensions with uri set to https://pidgeon.ai/post/a2a/v0, required: false, and params carrying the Post card:
{
"uri": "https://pidgeon.ai/post/a2a/v0",
"description": "Post agent identity: a signed card for this agent’s address and operator.",
"required": false,
"params": {
"address": "research-agent@acme.com",
"kind": "agent",
"on_behalf_of": "Acme Ltd",
"operator": "acme.com",
"card_url": "https://pidgeon.ai/api/v1/cards/8f0c…",
"card_jws": "eyJhbGciOiJFZERTQSIs…"
}
}
card_jws is the authority. The other members are there to be read. Because required is false, a client that does not know Post ignores the extension and reads the rest of the card as before.
A signature. An entry in signatures: JWS JSON form with the payload left out, over the RFC 8785 canonical form of the A2A card without its signatures, by the operator's own key. The protected header has alg: EdDSA, kid the key's JWK thumbprint, and jku pointing at https://post.acme.com/.well-known/http-message-signatures-directory. That is the same key directory Web Bot Auth verifiers read for the agent's HTTP requests. So one key, published once, signs the agent's mail, its requests and its A2A card.
The fields map without overlap. The Post card's address and kind have no A2A counterpart and travel in the extension. Its operator corresponds to A2A's provider, which the Post card proves. The A2A card's name, description, skills and interfaces have no Post counterpart and stay where they are.
How a client checks it
A client that knows Post checks three things, in order:
- The A2A card's signature holds under the key at
jku, fetched only from the operator's ownpost.host. card_jwsholds under its issuer's published keys, at<iss>/.well-known/post.json.- The Post card's
addressis at the domain whose key signed the A2A card.
If all three hold, the A2A card was published by the domain the Post card names, and that domain runs this agent for the party in on_behalf_of. If the first fails, the A2A card may have been copied or edited. If the third fails, somebody has pasted another agent's identity into their own card.
Step 2 works today with no library: fetch card_url, or the card by address at https://post.acme.com/.well-known/post/card?address=research-agent@acme.com, and check its jws against the issuer's keys.
Building it today
pidgeon id makes the operator's key and issues the card with no account:
npm install -g @pidgeon-ai/cli
pidgeon id init acme.com
pidgeon id issue research-agent --on-behalf-of "Acme Ltd" --json
The --json output is the card document the extension is built from: url, jws and card. The open library, @pidgeon-ai/id, has signA2aCard, which adds the extension and the signature in one call, and verifyA2aCard for the other side. It is Apache-2.0 and coming soon to npm. Checking an A2A card in the checker is being built.
What stays out of the card
An A2A card is public and names no customer, so what an agent may do for one particular customer does not belong in it. Post's draft carries that, as a grant, in the A2A message's metadata under the same extension URI, with the task it applies to.
Two limits are worth knowing before you ship:
- Canonical form. The signature is over the card exactly as built. A library that re-serialises the card and drops default values, such as a
false, can change the bytes and break the signature. Publish the card as signed. - Proof is per domain. The A2A signature is the operator's key, so it proves the domain published the card. Which agent on the domain is speaking comes from the Post card's
address, and from the signedFromon each request.
Start
Agents shows the card in full and where anyone fetches it. The A2A mapping is section 3.5.6 of the draft, linked from the protocol page. Checking a message covers the verifier, which checks the same card on email and on signed HTTP requests.