Quickstart
Provision an inbox, send it a test email, receive the arrival, and read the message — the full provision → receive → read loop in REST, TypeScript, Python, and the CLI.
This quickstart walks the full provision → receive → read loop end to end:
- Provision — create an inbox and get a live email address.
- Receive — send a real email to that address and be notified it arrived.
- Read — fetch the thread and read the message.
Every step is shown in REST (cURL), TypeScript, Python, and the CLI — pick your surface. The whole loop takes a couple of minutes.
Before you start
You need an API key. If you already have one (from onboarding or the dashboard), skip ahead. Otherwise, provision an account entirely in code with the two-step signup flow.
Sign up
sign_up creates a tenant, a first inbox, and a first API key, then emails a
6-digit code to the address you give it. It is the one unauthenticated
endpoint — you use it to obtain your first key.
curl -X POST https://app.theinboxagents.com/api/v1/sign_up \
-H "Content-Type: application/json" \
-d '{ "human_email": "you@example.com" }'const res = await fetch("https://app.theinboxagents.com/api/v1/sign_up", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ human_email: "you@example.com" }),
});
const { tenant_id, inbox_id, api_key } = await res.json();
// Store api_key now — it is shown once and never retrievable again.import requests
res = requests.post(
"https://app.theinboxagents.com/api/v1/sign_up",
json={"human_email": "you@example.com"},
)
data = res.json()
# data["api_key"] is shown once — store it now.inboxagents agent sign-up --human-email you@example.comThe response carries a one-time api_key (an ia_… secret). Store it now —
it is never returned again.
Verify
Enter the 6-digit code from the email to activate the account and lift it off the restricted new-account limits.
curl -X POST https://app.theinboxagents.com/api/v1/verify \
-H "Content-Type: application/json" \
-d '{ "otp_code": "123456" }'await fetch("https://app.theinboxagents.com/api/v1/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ otp_code: "123456" }),
});requests.post(
"https://app.theinboxagents.com/api/v1/verify",
json={"otp_code": "123456"},
)inboxagents agent verify --otp-code 123456Store your key in an environment variable
Every example below reads the key from INBOXAGENTS_API_KEY. Export it once and
never commit it:
export INBOXAGENTS_API_KEY="ia_your_secret_here"1. Provision an inbox
Create an inbox. Every field is optional — omit username and you get a
readable random address on agents.theinboxagents.com. The response includes
the live email and the inbox's inbox_id (an inb_… id) — you'll need the
id to read mail later.
curl -X POST https://app.theinboxagents.com/api/v1/inboxes \
-H "Authorization: Bearer $INBOXAGENTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "display_name": "Support Bot" }'const key = process.env.INBOXAGENTS_API_KEY!;
const base = "https://app.theinboxagents.com/api/v1";
const res = await fetch(`${base}/inboxes`, {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ display_name: "Support Bot" }),
});
const inbox = await res.json();
console.log(inbox.email); // e.g. brave-otter@agents.theinboxagents.comimport os, requests
key = os.environ["INBOXAGENTS_API_KEY"]
base = "https://app.theinboxagents.com/api/v1"
auth = {"Authorization": f"Bearer {key}"}
inbox = requests.post(
f"{base}/inboxes",
headers=auth,
json={"display_name": "Support Bot"},
).json()
print(inbox["email"]) # e.g. brave-otter@agents.theinboxagents.cominboxagents inboxes create --display-name "Support Bot"{
"inbox_id": "inb_8f2a1c9d",
"email": "brave-otter@agents.theinboxagents.com",
"display_name": "Support Bot",
"client_id": null,
"metadata": {},
"created_at": "2026-07-06T12:00:00Z",
"updated_at": "2026-07-06T12:00:00Z"
}2. Receive an email
Send a real email to the inbox's address from any mail client — subject and body of your choosing. InboxAgents receives it, threads it, and stores the message.
To be notified the moment it arrives, use one of two real-time surfaces:
- Webhook — register a URL and get a signed
POSTwhen a message lands. - WebSocket — hold a live connection and stream arrivals.
Register a webhook so your agent is pushed each new message:
curl -X POST https://app.theinboxagents.com/api/v1/webhooks \
-H "Authorization: Bearer $INBOXAGENTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-app.example.com/inboxagents/webhook" }'await fetch(`${base}/webhooks`, {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://your-app.example.com/inboxagents/webhook" }),
});requests.post(
f"{base}/webhooks",
headers=auth,
json={"url": "https://your-app.example.com/inboxagents/webhook"},
)inboxagents webhooks create --url https://your-app.example.com/inboxagents/webhookWhen a message arrives, your endpoint receives a signed event carrying the
inbox_id, thread_id, and message_id. Verify the signature (the webhook
signing secret is a whsec_… value returned when you create the webhook), then
use those ids to read the message in step 3.
No webhook endpoint handy for testing? Skip the notification and just poll — list the inbox's threads (step 3) a few seconds after sending. The message is already stored; the webhook only tells you when it landed.
3. Read the message
List the inbox's threads (newest first), then fetch the message to read its content and headers. Threads, messages, and attachments are all addressed as subresources of the inbox that owns them.
# List threads in the inbox
curl https://app.theinboxagents.com/api/v1/inboxes/inb_8f2a1c9d/threads \
-H "Authorization: Bearer $INBOXAGENTS_API_KEY"
# Read a single message
curl https://app.theinboxagents.com/api/v1/inboxes/inb_8f2a1c9d/messages/msg_5b3e7a10 \
-H "Authorization: Bearer $INBOXAGENTS_API_KEY"const inboxId = "inb_8f2a1c9d";
// List threads (newest first)
const threads = await fetch(`${base}/inboxes/${inboxId}/threads`, {
headers: { Authorization: `Bearer ${key}` },
}).then((r) => r.json());
const latest = threads.threads[0];
// Read the message
const message = await fetch(
`${base}/inboxes/${inboxId}/messages/${latest.last_message_id}`,
{ headers: { Authorization: `Bearer ${key}` } },
).then((r) => r.json());
console.log(message.subject, message.text);inbox_id = "inb_8f2a1c9d"
# List threads (newest first)
threads = requests.get(
f"{base}/inboxes/{inbox_id}/threads", headers=auth
).json()
latest = threads["threads"][0]
# Read the message
message = requests.get(
f"{base}/inboxes/{inbox_id}/messages/{latest['last_message_id']}",
headers=auth,
).json()
print(message["subject"], message["text"])# List threads
inboxagents inboxes:threads list --inbox-id inb_8f2a1c9d
# Read a message
inboxagents inboxes:messages get \
--inbox-id inb_8f2a1c9d --message-id msg_5b3e7a10That's the whole loop — you provisioned an inbox, received a real email, and read it back. If the message has attachments, fetch each one's bytes from the attachment download endpoint.
Where to next
Introduction
Email infrastructure for AI agents — provision an inbox in one API call, then receive and read mail over a simple REST API.
Connect an AI assistant (MCP)
Give an AI assistant its own email inboxes — connect Claude or ChatGPT point-and-click, or wire InboxAgents into a coding tool with the developer setup.