Give your AI agent an email inbox in one call
Send one unauthenticated POST to https://getcourier.dev/alias, with no body and no API key, and GetCourier returns a working inbox: an address on getcourier.dev, a read_token, a 72-hour expiry and an Ed25519 DID identity. The call takes about 15 ms and answers 201. The inbox receives mail; it does not send.
The call
curl -s -X POST https://getcourier.dev/alias
Every field is optional. To label the inbox, send a JSON body:
curl -s -X POST https://getcourier.dev/alias \
-H "Content-Type: application/json" \
-d '{"purpose":"signing up for an API key","agent":"build-bot-7","service":"generic","alias":"my-agent","ttl_hours":72}'
purposeis at most 200 characters;agentandserviceat most 100.aliasmust match^[a-z0-9][a-z0-9-]{1,30}$. A 6-character random suffix is always appended, so addresses stay unguessable. A reserved name returns 400ALIAS_RESERVED.ttl_hours:72is free and is the default;720needs paid credits, funded with USDC on Base or BTC on-chain.
POST /v1/sandbox/inboxes is the same handler with the same body, 201 shape and errors.
The response
201 (payment fields omitted):
{
"success": true,
"address": "my-agent-k3xmqz@getcourier.dev",
"inbox_id": "5b40d4d6-c046-46c9-aaa1-d0f1e20194e0",
"read_token": "<read_token>",
"expires_at": "2026-10-26T12:00:00.000Z",
"ttl_hours": 72,
"paid": false,
"identity": {
"did": "did:key:z6Mk...",
"public_key": "<base64url ed25519 public key>",
"fingerprint": "9f2c4b1d0a7e5566",
"private_key": "<base64url pkcs8 private key - shown once>"
},
"links": {
"messages": "/inbox/5b40d4d6-c046-46c9-aaa1-d0f1e20194e0/messages",
"wait": "/v1/sandbox/inboxes/my-agent-k3xmqz/wait",
"mcp": "/mcp"
},
"note": "read_token and identity.private_key are shown once"
}
Paid creations additionally return charged_credits and balance once the credit rails are live.
What the read_token and identity are
read_token is the credential for reading that one inbox, sent as Authorization: Bearer <read_token>. It is inbox-scoped: a valid token for a different inbox gets 403 NOT_OWNER, and a missing or unknown token gets 401 UNAUTHORIZED. Tokens are never accepted in the query string. It is shown once, so store it before the response is thrown away.
identity is an Ed25519 keypair minted per inbox and expressed as a DID (did:key:z6Mk...), with a base64url public key and a short fingerprint. The private key (base64url PKCS#8) is returned once. The reference does not document the identity as a way to authenticate to the inbox - the read_token is what authorises reads - so treat the key as an identifier you hold, not a login.
Python (urllib)
import json, urllib.request
req = urllib.request.Request(
"https://getcourier.dev/alias",
data=b"{}",
method="POST",
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as r:
inbox = json.load(r)
print(inbox["address"], inbox["read_token"])
Node (fetch)
const res = await fetch("https://getcourier.dev/alias", { method: "POST" });
const inbox = await res.json();
console.log(inbox.address, inbox.read_token);
POST with no body works here too: the endpoint does not require one.
Reading mail from the inbox
curl -s https://getcourier.dev/inbox/<inbox_id>/messages \
-H "Authorization: Bearer <read_token>"
Or by alias, with paging: GET /v1/sandbox/inboxes/{alias}/messages?after=<message id>&limit=20 (limit default 20, max 100). To block until mail arrives, use GET /v1/sandbox/inboxes/{alias}/wait.
Limits
- Free tier: 3 inboxes per hour and 5 per day per client IP, 72-hour lifetime, receive-only.
- Over the limit: HTTP 402
FREE_QUOTA_EXCEEDED,retryable: true, withretry_after_secondsand aRetry-Afterheader. - Per inbox: 100 messages;
textis truncated to 4000 characters. - No sending: GetCourier is receive-only and does not send email yet.
- Paid inboxes: 100 credits for 72 hours, 2000 credits for 30 days, 1 credit = US$0.0001. Fund an account with USDC on Base or BTC on-chain (minimum US$1);
GET /v1/pricingis authoritative on rails and prices.
FAQ
Do I need an API key to create an inbox?
No. POST /alias takes no auth. You may optionally send Authorization: Bearer cak_... to buy a longer-lived inbox with credits; without it the inbox is free and expires after 72 hours.
What happens when the inbox expires?
expires_at gives the time; the free lifetime is 72 hours. A message that "does not exist or has expired" returns 404 NOT_FOUND. Delete an inbox early with DELETE /v1/sandbox/inboxes/{alias}, which needs the matching read_token.
Can I choose the address?
Partly. You supply the prefix with alias, but a 6-character random suffix is always appended, so my-agent becomes my-agent-k3xmqz@getcourier.dev.