Search the docs
Find a page, a section, or an endpoint.
Test mode
A key whose mail never leaves Pidgeon, for CI.
A test key (pgn_test_…) does everything a live key does, and none of
its mail leaves Pidgeon. Use one in CI, in a staging environment, or
anywhere an agent is being built and should not be writing to real people.
What runs, and what does not
Everything runs: validation, the send checks (who may send as which address,
suppression, the address's send policy), threading, the stored message,
events and their webhooks, receipts, Idempotency-Key, and the Firewall on
mail that arrives.
What does not:
- Nothing is handed to the mail provider. Not for a send, a reply, a forward, a draft sent later, a scheduled send, or a calendar invitation. Whatever the recipient, whichever route or retry.
- Nothing counts. No daily sending allowance, no usage, no billing. The five-minute and per-minute limits still apply, at your plan's numbers, but in a bucket of their own. A test suite cannot use up what your production server needs.
- No person is notified by email or push about test mail.
Every message written in test mode has "test": true — on the message, on
the answer to a send, and on message.sent and message.received.
Making one
Pass test: true when you mint the key. A test key's own children are
always test keys.
curl https://pidgeon.ai/api/v1/api-keys \
-H "Authorization: Bearer $PIDGEON_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "CI", "identity_ids": ["identity-id"], "test": true }'A test key works on the addresses it was given. It cannot create or delete addresses, domains or pods, or issue IMAP and SMTP passwords: each of those counts against your plan, reaches the provider, or opens a way to send that test mode does not cover. Make the address with a live key, then mint a test key for it.
Where test mail goes
A test send to one of your own account's addresses is delivered there, marked test, so two of your agents can talk to each other in CI. A test send to anybody else, including an address in another Pidgeon account, is accepted, stored as sent, and goes nowhere.
A reply to a test message is a test message too, whoever sends it. If a person answers a simulated customer from the dashboard, that reply also stays inside.
Playing the other side
Nobody outside will ever answer a test send, so POST /v1/test/inbound
plays the other side. It delivers a message to one of the test key's
addresses through the real inbound pipeline, exactly as an email from
outside would arrive. Pass in_reply_to with a message id to have it arrive
as a reply in that thread.
curl https://pidgeon.ai/api/v1/test/inbound \
-H "Authorization: Bearer $PIDGEON_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "support@yourapp.pidgeon.email",
"from": "customer@example.com",
"subject": "Re: Your order",
"text": "It never arrived.",
"in_reply_to": "message-id"
}'{
"data": {
"status": "delivered",
"message_id": "…",
"thread_id": "…",
"identity_id": "…",
"spam": false
}
}- Test keys only. A live key gets
403: it would put a made-up sender into a real inbox. - An address the key reaches at
send. Anything else is404, the same as an address that does not exist. - The sender's rules, the spam filter and the Firewall all judge it. A
sender rule that rejects
fromrejects it here, withstatus: "rejected". - Up to 1,000 an hour per account. It takes an
Idempotency-Key, so a CI step that retries does not deliver twice.