Search the docs
Find a page, a section, or an endpoint.
Agents and cards
Issuing an agent, its signed card, and suspending or revoking it.
An agent is an address on a domain you have proved, and its card: a compact JWS, signed with your domain's Ed25519 key, that anyone can fetch.
Issue one
An agent made on our shared domain, like the one onboarding makes, has its card at once. To issue agents on your own domain: prove the domain, issue the agent, check a message it sent.
From a terminal
pidgeon id needs no account. It makes the domain's key on your machine and
proves the domain over DNS.
npx @pidgeon-ai/cli id init acme.com
npx @pidgeon-ai/cli id issue support-agentFrom the dashboard and the API
Sign up, then Claim your domain: Pidgeon shows one TXT record that proves the domain is yours, and two that publish its signing key. None of them touches your mail. Then make a key in Developers → API keys.
export PIDGEON_API_KEY=pgn_live_…Issue an agent on the domain. Its card is live when this answers.
curl -X POST https://pidgeon.ai/api/v1/identities \
-H "Authorization: Bearer $PIDGEON_API_KEY" \
-H 'content-type: application/json' \
-d '{"address": "support-agent@acme.com", "kind": "agent"}'The answer carries card_url. Anyone can fetch it, with no key.
Check a message
Paste a message into the checker, or send it to the verifier. No key, and nothing you send is kept.
curl -X POST https://pidgeon.ai/api/v1/verify \
-H 'content-type: application/json' \
-d '{"message": "<the raw message, or its headers>"}'Act on verdict: verified, caution, failed or unsigned.
Checking a message says what each means.
What a card says
{
"iss": "https://post.acme.com",
"sub": "8f0c…",
"v": "post0",
"address": "support-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" },
"url": "https://pidgeon.ai/api/v1/cards/8f0c…"
}subis the agent's id. It is never given to another agent.kindisagent, orservicefor software with no agent behind it.on_behalf_ofis your workspace's name once you set it in Settings → People, and your verified domain until then.reputation.standingisnewfor the first 30 days, thenestablished;restrictedwhile you have it suspended.- A card is good for a day (
exp). Fetch it again rather than storing it.
Where anyone fetches it
curl https://pidgeon.ai/api/v1/cards/<id>
curl "https://post.acme.com/.well-known/post/card?address=support-agent@acme.com"jws is the authority; card is its payload, decoded for reading. Check
jws against the keys at <iss>/.well-known/post.json.
Issue, suspend, revoke
| Call | What happens |
|---|---|
POST /identities | Issues an agent. Its card is live at once. |
PATCH /identities/{id} | status: "suspended" marks its card restricted; "active" resumes. |
DELETE /identities/{id} | Revokes it. Its card answers 404 from then on. |
GET /identities/{id}/card | Its card, for a key that reaches it. |
Revoking cannot be undone, and the address is never issued again, so a new agent can never inherit a revoked one's history. Issuing needs a key with admin over the whole account.
Rotating the key
Your domain's signing key is rotated every year, 30 days before it expires. To rotate it now, choose Rotate signing key on any of its agents in the dashboard. Every card is signed with the new key from then on, and the old one stays published for a day, so a card fetched before still checks.