Skip to main content

pidgeon

M8ven Score

Pidgeon is the email inbox API for AI agents. It gives agents their own inboxes so they can work with emails just like a human. This is its Python client.

pip install pidgeon

Create an address, send, receive, reply

import os

from pidgeon import AuthenticatedClient
from pidgeon.api.identities import identities_create
from pidgeon.api.messages import messages_await, messages_reply, messages_send
from pidgeon.models import (
    Error,
    IdentitiesCreateBody,
    IdentitiesCreateBodyType,
    MessagesReplyBody,
    MessagesSendBody,
)

client = AuthenticatedClient(
    base_url="https://pidgeon.ai/api/v1",
    token=os.environ["PIDGEON_API_KEY"],
)

# 1. An address of its own. Any free name on pidgeon.email works with no DNS.
created = identities_create.sync(
    client=client,
    body=IdentitiesCreateBody(address="scout@pidgeon.email", type_=IdentitiesCreateBodyType.AGENT),
)
if isinstance(created, Error):
    raise RuntimeError(created.error.message)
address = created.data

# 2. Send from it.
messages_send.sync(
    client=client,
    body=MessagesSendBody(
        from_=address.email,
        to="ops@example.com",
        subject="Staging access",
        text="Could you send me the access code?",
    ),
)

# 3. Receive: one held-open request until the answer arrives, up to 60 seconds.
awaited = messages_await.sync(client=client, identity_id=address.id, timeout=60)

# 4. Reply into the same conversation. Recipients and subject come off the original.
if not isinstance(awaited, Error) and awaited.data.message:
    print(awaited.data.message.extracted.codes)
    messages_reply.sync(
        awaited.data.message.id,
        client=client,
        body=MessagesReplyBody(text="Thanks, that worked."),
    )

PIDGEON_API_KEY is a pgn_live_… key. Make one at pidgeon.ai/app/developers/keys, or let your agent sign itself up: pidgeon.ai/skill.md is two calls, and the only thing it needs from a person is a six-digit code.

In production, take a signed webhook rather than holding a request open. Documentation: pidgeon.ai/docs · OpenAPI.

Generated from openapi.json, the same document the TypeScript client is generated from, so an operation has the same name in both: messages_send here is messagesSend there. Every call takes the client; nothing is global.

Errors

Errors come back, they are not raised. Every call returns the success model or Error or None, so an isinstance check is the shape of a correct caller. Error.error carries the API's own code, a message written for a person and safe to show one, and a field when one input was at fault.

from_ and type_ carry a trailing underscore, because from and type are reserved in Python. The wire names are unchanged.

Every operation also has asyncio, and sync_detailed / asyncio_detailed variants that return the whole Response with its status and headers.

Receiving

Mail arriving at an address your code owns becomes an event, and your endpoint is called with a signed payload. Verify before you parse — an unverified payload is an unauthenticated POST that claims a message arrived.

from pidgeon.webhooks import verify_webhook

event = verify_webhook(
    raw_body=request.body,  # the exact bytes, before any json.loads
    headers=request.headers,
    secret=os.environ["PIDGEON_WEBHOOK_SECRET"],
)

raw_body must be the bytes we sent. Parse the JSON after verifying — re-serialising changes key order and the signature will not match. verify_webhook raises rather than returning a boolean, rejects a timestamp outside five minutes before it looks at the signature, and compares in constant time.

The event carries ids, never a body. Exchange one for the content with messages_get.

Creating an address

from pidgeon.api.identities import identities_create
from pidgeon.models import (
    IdentitiesCreateBody,
    IdentitiesCreateBodySendPolicy,
    IdentitiesCreateBodyType,
)

identities_create.sync(
    client=client,
    body=IdentitiesCreateBody(
        address="receipts@yourdomain.com",
        type_=IdentitiesCreateBodyType.AGENT,
        send_policy=IdentitiesCreateBodySendPolicy.REPLY_ONLY,
    ),
)

Say where with address, domain or domain_id — one of the three. Every address you already have carries its domain_id, which is what to use when you are on the shared domain and own nothing to list.

send_policy=IdentitiesCreateBodySendPolicy.REPLY_ONLY makes an address structurally unable to write to anybody who has not written to it first, which is the right default for software.

Pagination

A list returns a page, not an iterator — deliberately. An iterator that hides pagination also hides the rate limit pagination is subject to.

from pidgeon.api.events import events_list

cursor = None
while True:
    page = events_list.sync(client=client, cursor=cursor)
    for event in page.data:
        handle(event)

    cursor = page.next_cursor
    if cursor is None:
        break

What this deliberately does not do

No retry policy, no queue, no caching, no auto-paginating iterator. Those are decisions that belong to your application — an SDK that makes them for you is one you eventually work around.

Versioning

Versioned independently of the API. The API is /v1; this package is 1.x, and semver applies to its own surface.

Full reference: pidgeon.ai/docs.

Contributing

This client is generated from openapi.json, the contract the API validates against, and published from pidgeon-ai/pidgeon-python. A pull request against generated code cannot be merged as written — the fix belongs in the schema. Open an issue and say what is wrong, or email support@pidgeon.ai.

MIT licensed.

Metadata

Release files for pidgeon 1.16.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pidgeon 1.16.1
File Size Uploaded Provenance
pidgeon-1.16.1.tar.gz 157.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pidgeon 1.16.1
File Interpreter ABI Platform
pidgeon-1.16.1-py3-none-any.whl Python 3 none any Details

Total release size: 594.8 kB

Release files / pidgeon-1.16.1.tar.gz

Download URL pidgeon-1.16.1.tar.gz
Size 157.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5372ab2a2dc6e2e793a5dadfcb63ef4051995d9c6d228765b2c723d315bebc75
BLAKE2b-256 checksum
How to use checksums
a1a5299434eb922355e4547a7c828daf5f6d79ccf7a5f8b81592c683b57f240b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / pidgeon-1.16.1-py3-none-any.whl

Download URL pidgeon-1.16.1-py3-none-any.whl
Size 436.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a8d6846c9f5e64dd4005c311e4653ba34a3cc7e95801e5b7c60bbebc4a59b8dd
BLAKE2b-256 checksum
How to use checksums
69791b67ba38a96107315c81d7fa96d92b6f4171018af1ddbd82f09c73c68ccd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for pidgeon 1.16.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pidgeon-1.16.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page