Email identities for AI agents
Agent IDs give AI agents their own email address — a free, receive-only <handle>@agents.mailpipe.dev they can claim through the API, with a paid $14/mo upgrade that SEND-ENABLES the same address (send to anyone, instantly, no DNS). No human inbox to borrow, no disposable address to burn.
When an agent signs up for a service — WorkflowTV, a SaaS trial, a newsletter — the form demands an email. An Agent ID is that email: a real, readable inbox the agent owns and can poll over the API. The free tier is the agent identity layer; the paid tier gives the same address a voice — send to anyone, instantly.
| Tier 1 — Agent ID (free) | Tier 2 — Send-enabled ($14/mo) | |
|---|---|---|
| Address | <handle>@agents.mailpipe.dev | same <handle>@agents.mailpipe.dev |
| Direction | Receive-only (capability, not quota) | Send to anyone + receive (instant, no DNS) |
| Access | Read-only API key, mailbox-pinned | Full-send key on the same mailbox |
| Activation | Instant on operator verify | Instant on payment (shared domain already verified) |
| Operator | Approves by email | Receipt + dashboard login to audit sent mail |
| Caps | ~200 inbound/mo, 30-day retention, 50 MB | + ~100 sends/day, ~1,000/mo (shared-domain guard) |
| Billing | Free | Stripe Checkout, $14/mo (operator pays) |
Operators fund agents
Every economic and accountability edge touches the human operator. The verification email goes to the operator — they approve the agent's identity. The one-time API key goes to the agent. The upgrade checkout link is returned to the agent, for delivery to its operator. An agent cannot pay for itself. On payment the operator gets a receipt and a dashboard login to audit exactly what the agent sends and receives.A free Agent ID is receive-only as a capability, not a quota. An inbox that cannot send cannot spam, cannot burn domain reputation, and cannot be farmed for outbound infrastructure. That is why free signup stays friction-light (no card, no human account) without creating an abuse surface.
Free keys are minted with ['mail:read', 'mailbox:read'] only and pinned to the agent's single mailbox. There is no send credential to leak — paying mints a separate full-send key and revokes the read-only one.
The outbound send route returns an unconditional 403 for any from-address resolving to a FREE (un-paid) agent mailbox. A paid send-enabled agent is allowed, bounded by a per-agent send rate cap so it cannot burn the shared domain reputation.
Inbound volume
~200 messages / month
AGENT_INBOUND_MONTHLY_CAPRetention
30 days
AGENT_RETENTION_DAYSStorage
50 MB
AGENT_STORAGE_CAP_MBDormancy recycle
90 days (warned at 75)
AGENT_RECYCLE_DAYSAll caps are env-tunable (AGENT_* vars) and swept daily by the agent-lifecycle cron. Any inbound message resets the dormancy clock.
The default path for an agent with no credential. The agent requests a handle, the operator approves by email, and the agent polls for its one-time key. Nothing is provisioned until the operator clicks the verification link (24-hour window).
Pre-auth by design — an agent has no key yet. The response returns a poll URL and the address that will exist once the operator verifies.
/v1/agents/signupBody: { handle, agent_name?, operator_email, client_meta? }
curl -X POST "https://api.mailpipe.dev/v1/agents/signup" \
-H "Content-Type: application/json" \
-d '{
"handle": "scout-7",
"agent_name": "Scout",
"operator_email": "human@example.com"
}'{
"id": "b1f0c4e2-...",
"status": "pending_verification",
"address": "scout-7@agents.mailpipe.dev",
"receive_only": true,
"verification": "email_sent_to_operator",
"poll": "/api/v1/agents/signup/b1f0c4e2-...",
"note": "Nothing is provisioned until your operator clicks the verification link (24h window)."
}The operator clicks the link in their inbox, which hits GET /v1/agents/verify?token=…. That provisions the receive-only mailbox and mints the read-only key. The agent never sees the link — the operator approves, the agent holds the credential.
Poll the URL from step 1. While pending you get pending_verification. The first poll after verification carries api_key exactly once — store it immediately. Every later poll returns key_already_claimed: true.
/v1/agents/signup/{id}Per-IP rate-limited. The id is an unguessable capability URL — only the signing-up agent holds it.
{
"id": "b1f0c4e2-...",
"status": "active",
"handle": "scout-7",
"address": "scout-7@agents.mailpipe.dev",
"receive_only": true,
"api_key": "mp_live_...",
"api_key_note": "Shown exactly once — store it now. Scopes: mail:read, mailbox:read."
}The key is shown exactly once
The firstactive poll is the only time api_key appears. Persist it the moment you receive it — it is never displayed again. If it is lost, use key recovery.When the caller is already an authenticated operator — a logged-in dashboard session, or an operator API key — there is no need for the email round trip. The operator IS the approval. This path mints the Agent ID and returns the key immediately, in one call.
/v1/agents/provisionAuth: an operator session (cookie) or Authorization: Bearer <jwt>. Body: { handle, agent_name? }.
curl -X POST "https://api.mailpipe.dev/v1/agents/provision" \
-H "Authorization: Bearer <operator-jwt>" \
-H "Content-Type: application/json" \
-d '{ "handle": "scout-7", "agent_name": "Scout" }'{
"id": "b1f0c4e2-...",
"status": "active",
"handle": "scout-7",
"address": "scout-7@agents.mailpipe.dev",
"receive_only": true,
"api_key": "mp_live_...",
"api_key_note": "Shown exactly once — store it now. Scopes: mail:read, mailbox:read."
}Same invariants, no email
The provisioned Agent ID is identical to one created through the anonymous flow: a single receive-only mailbox, a read-only key pinned to it, and the same caps and abuse rails. The only difference is that the operator's existing authentication replaces the email verification step.Before signing up, check whether a handle is free. Handles are DNS-safe (2–32 chars, lowercase alphanumerics + inner hyphens) so a handle can also become a DNS label if the future per-agent-domain premium ships. Availability is checked across all namespaces: live free agents, any reserved <handle>.mailpipe.dev subdomain, and reserved labels.
/v1/agents/handle-available?handle=scout-7Pre-auth. No rate cost beyond the standard per-IP signup limiter.
curl "https://api.mailpipe.dev/v1/agents/handle-available?handle=scout-7"
{
"handle": "scout-7",
"available": true,
"address": "scout-7@agents.mailpipe.dev"
}{
"handle": "scout-7",
"available": false,
"reason": "That handle is taken."
}The read-only key is the agent's only credential. Rotate it on a schedule, or recover it through the operator if it is lost — both flows preserve the receive-only scopes and the mailbox pin. A rotation invalidates the previous key.
Authenticate with the agent's current key. The old key is revoked and a fresh receive-only key is returned exactly once.
/v1/agents/rotate-keyAuth: Authorization: Bearer <agent-api-key>.
curl -X POST "https://api.mailpipe.dev/v1/agents/rotate-key" \ -H "Authorization: Bearer mp_live_<current-agent-key>"
{
"id": "b1f0c4e2-...",
"rotated": true,
"api_key": "mp_live_...",
"api_key_note": "New read-only key — shown exactly once. The previous key is now revoked."
}When the key is lost and the agent can no longer authenticate, the operator recovers it. The recovery is gated on the operator that owns the Agent ID — either an operator session or a re-verification through the operator email.
/v1/agents/{id}/recoverAuth: the operator session / key that owns the Agent ID. Re-issues a read-only key once.
curl -X POST "https://api.mailpipe.dev/v1/agents/b1f0c4e2-.../recover" \ -H "Authorization: Bearer <operator-jwt>"
{
"id": "b1f0c4e2-...",
"recovered": true,
"api_key": "mp_live_...",
"api_key_note": "Re-issued read-only key — shown exactly once. Any prior key is revoked."
}Recovery still hands the key to the agent
Recovery is initiated by the operator but the new credential is the agent's. The operator authorizes; the agent holds and uses the key. Scopes never change —mail:read and mailbox:read, pinned to the same mailbox.When an agent needs to send — replies, outreach, receipts — paying $14/mo send-enables its existing <handle>@agents.mailpipe.dev address. There is no per-agent domain and no DNS: agents.mailpipe.dev is already a verified sending domain, so activation is instant. Sending is bounded by a per-agent rate cap (the shared-domain reputation guard). A dedicated per-agent domain is planned as a later premium.
/v1/agents/upgradeAuth: the agent's own API key. Starts (or resumes) the upgrade and returns a Stripe checkout URL charged at signup ($14/mo). The operator email must be on file.
curl -X POST "https://api.mailpipe.dev/v1/agents/upgrade" \ -H "Authorization: Bearer mp_live_<agent-key>"
{
"status": "pending_payment",
"address": "scout-7@agents.mailpipe.dev",
"price": "$14/month",
"checkout_url": "https://checkout.stripe.com/...",
"operator_email": "human@example.com",
"note": "Send the checkout_url to your operator — they complete payment. Sending is enabled INSTANTLY on payment (no DNS)."
}/v1/agents/upgradeAuth: the agent's API key. Track-2 is instant: pending_payment → ready. On ready the one-time full-send key is handed out, alongside send_org_id + send_endpoint — the address to POST sends to.
{
"status": "ready",
"address": "scout-7@agents.mailpipe.dev",
"send_ready": true,
"send_org_id": "fe34f29e-...",
"send_endpoint": "/api/v1/outbound/fe34f29e-.../send",
"api_key": "mp_live_...",
"api_key_note": "Full-send key for sending from your agents.mailpipe.dev address — shown exactly once, store it now. POST your sends to send_endpoint. Sending is live now."
}The checkout link goes to the operator
The agent receivescheckout_url and passes it to its human operator. Operators fund agents; an agent cannot pay for itself. On payment the operator is charged $14/mo, the address is send-enabled instantly, and the operator gets a receipt plus a dashboard login to audit what the agent sends and receives. The agent-tier charge is funnel-intrinsic — it does not depend on the global domain-billing kill switch.The full flow runs conversationally through the Mailpipe MCP server. Three tools cover signup, status, and upgrade — an agent can claim and check its own identity from inside a Claude Code session.
mailpipe_agent_signupClaim a free receive-only Agent ID. The operator gets a verification email and approves within 24 hours.
mailpipe_agent_statusWith a signup_id: poll the free-tier signup and collect the read-only key once. Without it (agent key configured): the paid upgrade status incl. pending DNS records.
mailpipe_agent_upgradeStart the $14/mo send-enable. Returns the Stripe checkout URL to hand to the operator; on payment the same agents.mailpipe.dev address can send to anyone, instantly.
A typical conversation:
> Claim me a free Agent ID with the handle "scout-7", operator human@example.com [mailpipe_agent_signup] → pending_verification, email sent to human@example.com > Did my operator approve it yet? [mailpipe_agent_status signup_id="b1f0c4e2-..."] → active api_key: mp_live_... (stored — shown only once) > I need to send mail now. Enable sending. [mailpipe_agent_upgrade] → pending_payment Send this to your operator: https://checkout.stripe.com/... (On payment, the same address can send to anyone — instantly, no DNS.)
The official SDK exposes the same flow under mailpipe.agents. signup() and signupStatus() are pre-auth (they work with any placeholder key — this is how an agent gets its first real one); upgrade() and upgradeStatus()authenticate with the agent's key.
import { MailpipeClient } from '@mailpipe/sdk';
const mailpipe = new MailpipeClient({ apiKey: process.env.MAILPIPE_API_KEY ?? 'placeholder' });
// 1. Claim a free Agent ID (operator gets a verification email)
const signup = await mailpipe.agents.signup({
handle: 'scout-7',
agent_name: 'Scout',
operator_email: 'human@example.com',
});
// 2. Poll until the operator approves; the FIRST poll after approval
// returns api_key exactly once — store it immediately.
const status = await mailpipe.agents.signupStatus(signup.id);
if (status.api_key) saveKey(status.api_key);
// 3. Later: send-enable the same address (operator pays $14/mo).
const upgrade = await mailpipe.agents.upgrade();
console.log('Send to operator:', upgrade.checkout_url);
// On payment: poll upgradeStatus() for your one-time full-send key +
// send_endpoint. The operator gets a receipt + a login to audit sent mail.WorkflowTV is the first-class consumer
An agent claims <handle>@agents.mailpipe.dev, uses it as its account email, and reads the verification mail it receives. When that agent starts earning and needs to send, send-enabling is one API call and one operator-paid checkout away — the same address, sending to anyone instantly with no DNS.
Our team is here to help with anything from setup to scaling.