Search the docs

Find a page, a section, or an endpoint.

Allow and block lists

Who may write to an address, and who it may write to.

Two lists, one per direction. Who may write to an address, and who that address may write to. They are separate endpoints because they answer different questions and have different consequences — one decides what you are charged for storing, the other decides what leaves.

Both are scoped to a single address. There is no list that silences a sender for a whole account over the API, deliberately: a key that administers one address must not be able to change what fourteen other addresses receive.

Who may write to you

GET    /v1/identities/idn_4f2a/receive-rules
POST   /v1/identities/idn_4f2a/receive-rules   { "action": …, "value": … }
DELETE /v1/identities/idn_4f2a/receive-rules?rule_id=…

value is an address or a domain and the string says which: billing@acme.com matches one person, acme.com matches everybody there. You are not asked to classify it, because a caller asked to classify it will eventually classify it wrong.

action is one of five:

actionWhat happens
rejectThe message is refused before it is stored. No row, no thread, nothing.
spamStored, and filed as spam.
trashStored, and filed as deleted.
archiveStored, and skips the inbox.
inboxNever classify this sender as spam. The rescue, not a block.
curl -X POST https://pidgeon.ai/api/v1/identities/idn_4f2a/receive-rules \
-H "Authorization: Bearer $PIDGEON_API_KEY" \
-d '{ "action": "reject", "value": "noreply@spam.example" }'

reject is the one worth understanding

The other four decide where a message goes. reject decides whether there is one at all — it refuses before the insert, so nothing is stored, nothing is threaded, no storage is charged and no webhook fires.

That last part is the reason it exists. message.spam is a deliverable event, so before this an address under sustained abuse was paying storage and webhook deliveries for every message its owner had already said they did not want. For a mailbox a person reads, spam is right — you want to be able to look. For an address no human will ever open, reject is.

It is not a security control. The From: header is written by the sender, and anybody blocked can change it for the price of a new address. What reject buys is not paying for mail from senders who have not bothered, which is most of them. If you need to be certain who sent something, read the authentication results on the message rather than its From:.

The more specific rule wins

A rule naming an address beats a rule naming its domain, so blocking a whole domain and letting one person through does what it looks like:

reject  acme.com              — everybody at acme.com
inbox   billing@acme.com      — except billing@, which is never spam

And an address's own rule beats an account-wide one. Rules made in the dashboard apply to every address; rules made through this endpoint apply to one, and the one wins. That ordering is what makes this address receives verification codes from one service and nothing else expressible without touching anything else you own.

Who you may write to

GET    /v1/identities/idn_4f2a/send-rules
POST   /v1/identities/idn_4f2a/send-rules   { "effect": "allow" | "block", "value": … }
DELETE /v1/identities/idn_4f2a/send-rules?rule_id=…

effect rather than action, because the outbound side has a verdict rather than a destination. The same matching applies — address beats domain, adding replaces.

These rules hang off the address's send policy, which GET returns beside them and which is set with PATCH /v1/identities/{id}:

send_policyWho it may write to
openAnyone.
reply_onlyAnyone who has written to it first, plus its allow list.
listOnly its allow list.

A block rule refuses under every policy, including open. A block list that a setting could switch off is not a block list.

A refusal tells you which kind it was: blocked means a rule said no, not_permitted means the policy did. They are different things to be told, and an agent debugging a send needs to know which.

Reply is not a third list

An address that may receive from somebody and must not answer them is one block rule on the send side. There is no separate reply list, because it would be a second way to express a rule that already exists.

reply_only is the opposite case — may write, but only to people who wrote first — and it is a policy rather than a list.

Reading the rules from an agent

The MCP server exposes both as read-only tools — list_receive_rules and list_send_rules — so an agent asking why did nothing arrive or why was that refused can answer it. Writing a rule is deliberately not a tool: an agent that can edit its own lists can quietly stop its own mail.