Search the docs
Find a page, a section, or an endpoint.
Rate limits
What is counted, what is returned, and what to do about it.
Three things limit what an account can do, and the effective limit is always the lowest of them: the plan, the trust tier, and the per-minute rate limit.
Per plan
| Limit | Free | Developer | Startup | Enterprise |
|---|---|---|---|---|
| People in the workspace | 1 | 10 | 25 | Unlimited |
| Domains | 1 | 10 | 150 | Unlimited |
| Inboxes | 3 | 10 | 150 | Unlimited |
| Programmable addresses | 3 (1 to start) | 10 (1 to start) | 150 (10 to start) | Unlimited |
| Webhook endpoints | 3 | 25 | 100 | Unlimited |
| API keys | 10 | 10 | 50 | Unlimited |
| Requests per minute | 120 | 1,200 | 3,000 | 6,000 |
| Messages sent per day | 100 (6 to start) | 1,000 (66 to start) | 15,000 (1000 to start) | 50,000 (3333 to start) |
| Sent per day from pidgeon.email | 100 | 200 | 500 | 1,000 |
| Messages sent per month | 3,000 | 10,000 | 450,000 | 1,500,000 |
| Pods | 3 | 10 | 25 | Unlimited |
| Routing rules per domain | 25 | 200 | 1,000 | Unlimited |
| Storage, shared across the account | 3 GB | 10 GB | 500 GB | 1,000 GB |
| Inbound | Unlimited | Unlimited | Unlimited | Unlimited |
Receiving is free on every plan, because charging for the thing that makes an inbox valuable would be the wrong business.
Every number above is read, as this page renders, from the same module the API enforces them from — so this table cannot describe a limit the product does not apply. It used to claim that while being a hand-written table that did not.
Programmable addresses and daily sends are a ceiling, not an allowance. A trust tier grants a share of the number above. A new account starts with the share in the start column, which is a fifteenth, until it confirms its email address; then it gets all of it. A penalised account drops back to the start.
Trust, which is not the plan
A brand-new domain cannot be made trustworthy overnight. An account that has not confirmed its email starts well below its plan's daily allowance, and one whose mail bounces or draws complaints falls back there, rather than keeping a large limit it could burn its reputation with.
Confirming your email is the step that matters. Verifying a domain, time, and mail that arrives without being reported all raise the score further, which is what keeps an account at its full plan when something does go wrong.
Rate limits
Per minute, per account, across every key.
A refusal tells you when to come back. Being refused carries
Retry-After in seconds and the daily allowance alongside it, so a client
that has hit a limit never has to guess how long to wait:
Retry-After: 85783
X-RateLimit-Limit-Day: 6
X-RateLimit-Remaining-Day: 0
X-RateLimit-Reset-Day: 1792170122The send allowance is a rolling twenty-four hours, not a calendar day, so
X-RateLimit-Reset-Day is when your oldest send ages out of the window —
which is the only honest answer and is why it is a header rather than a rule
you could work out yourself.
Every authenticated success also carries X-RateLimit-Limit, -Remaining
and -Reset for the per-minute ceiling, so a client can pace itself rather
than find the limit by hitting it (the headers).
Minting and rotating keys
Each of these issues a new secret, so they share an hourly budget per account, separate from the per-minute one:
| Traffic | Mints and rotations an hour |
|---|---|
| Live | 20 |
| Test | 300 |
Test traffic is any call made with a test key, and any key minting or rotating a test key. It has a bucket of its own, so CI can never use up what a live admin key needs to connect or replace a key. Creating a pod with a key spends from the same budget.
The 429 says when the hour's window ends, in Retry-After, and carries
that budget's X-RateLimit-Limit, -Remaining and -Reset. The window is
fixed, not rolling: it resets on the hour boundary it names.
When you hit one
An entitlement refusal is a 402 with a sentence naming the limit and the
alternative — routing an extra address into an inbox you already have is free,
and is usually what somebody at the inbox limit actually wanted.