Search the docs

Find a page, a section, or an endpoint.

Verify a sender

Every verify a sender endpoint, generated from the API's own schemas.

Check who sent a message

post/api/v1/verify

Public, with no key. Send a raw message, or its headers alone; the answer says whether an AI agent sent it, on whose behalf, and whether its signatures hold — the signed agent declaration (`Agent-of` under an aligned DKIM signature) and the `Post-Envelope` — for Pidgeon’s mail and any other signer using the same formats. Act on `verdict`. Pass `recipient`, the address it reached you at, to catch a signed message replayed to you. Or send `request` instead of `message`: an HTTP request an agent signed with HTTP Message Signatures (RFC 9421) in Web Bot Auth’s profile, which is also how an MCP call over HTTP is signed; the key is found by its `keyid` among domains proved with `pidgeon id`, or in the directory its `Signature-Agent` names. `grants` says what the sender may do: each grant it carried in `Post-Grant`, or that you send in `grants`, checked against the sender a signature verified — act on each one’s `valid`, and pass `subject` to have it checked against the customer, account or order you are about to act on. Nothing sent is stored. Limited per IP; a key may be sent and is not required.

Body

  • messagestring

    The raw message, or its headers. Send this or `request`.

  • requestobject

    An HTTP request an agent signed (HTTP Message Signatures, Web Bot Auth), as received. Send this or `message`.

  • recipientemail
  • grantsstring[]

    Grants sent beside the message or request rather than in a `Post-Grant` header, such as an MCP call’s `_meta["ai.pidgeon.post/grant"]`: compact JWS.

  • subjectstring

    The customer, account or order you are about to act on. A grant for another one answers `wrong_subject`.

Responses

  • 200The verdict.
  • 400The request is not valid. `error.field` names the input at fault when there is one.
  • 401No API key, or one that is not valid.
  • 403Refused. `error.code` says why: `forbidden` when this key may not do this or the account is on hold, `abuse_blocked` when a limit says no.
  • 404No such resource, or one this key cannot reach. The two answer the same, so treat a 404 as “not available to you” rather than “does not exist”.
  • 409It conflicts with what is there: it already exists, or the `etag` you sent is not the current one.
  • 429Rate limited. `X-RateLimit-Reset` says when to retry.
  • 500Something went wrong on our side. Retry; if it keeps happening, tell us.
  • 503Something this needs is not answering right now. Retry in a moment.
bash
curl https://pidgeon.ai/api/v1/verify \
  -X POST \
  -H "Authorization: Bearer $PIDGEON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Generated · public/openapi.json