The code is the step agents fail
An agent can fill in a sign-up form. The trouble starts a second later, when the service emails a six-digit code to the address on the form. If that address is yours, a person has to fetch the code. If it is a throwaway, the code arrives, but so will every email that account sends afterwards, the login codes, the password reset and the receipts, at an address nobody is reading.
With Pidgeon the agent signs up with an address of its own and keeps it. The first code arrives there, and so does everything after it.
One call that waits for the code
The agent asks for the code before it submits the form, and the answer comes back when the email does:
curl -G https://pidgeon.ai/api/v1/messages/await \
-H "Authorization: Bearer $PIDGEON_API_KEY" \
-d identity_id=$IDENTITY_ID \
-d has_code=true \
-d timeout=120
The request holds open for up to 280 seconds. What comes back is the message with the code already pulled out of it: extracted.codes, most likely first, and extracted.links with the confirmation link at the top. There is no polling loop to write, and no regex for whichever format this service uses.
From an agent it is the same call: the MCP server's await_message tool takes the same parameters, and so do messagesAwait in the TypeScript SDK, messages_await in Python, and the CLI.
The right code, not the nearest one
Finding a code in an email is a guess, and a careless guess is a security problem. Pidgeon makes it carefully:
- Codes are read from the new text only. A code quoted from an earlier email in the thread is never offered again.
- A forged sender is not the service. Anyone can type
no-reply@github.cominto a From line. When the agent waits for mail from a sender, only mail that passed DMARC counts; a forgery is set aside and counted, not returned. - Nothing is lost quietly. Mail filed as spam, or a match that failed authentication, comes back as a count with its id, so the agent can tell "the code never came" from "the code came and was held".
- Every message comes with a Firewall verdict. Pidgeon Firewall names hidden text, instructions addressed to an AI and look-alike senders, so your agent can check the email before it acts on the code. A sign-up email is an email from a stranger, and it gets the same check as any other.
An example that runs
signup-agent is a browser agent built on Browser Use and the Pidgeon Python SDK. It creates its own address, fills in a sign-up page, waits for the code, types it in and is signed in. Then it asks for a password reset, and the reset link arrives at the same address, because the address is still its own. It runs in our CI.
Start
Sign up, create an address, and point the wait at it. The verification codes guide has every parameter, and the quickstart takes about five minutes. Or paste one line into your coding agent:
Read pidgeon.ai/skill.md and get yourself an email address.