1. Create an inbox and a key
Sign-up is unauthenticated. One call returns an organization, an inbox and an API key — which is what lets an agent bootstrap its own mailbox without a human opening a dashboard.
```bash cURL curl -X POST https://api.carlyemail.com/v0/agent/sign-up \ -H 'content-type: application/json' \ -d '{ "human_email": "you@yourcompany.com", "username": "support" }'
```python Python
import httpx
r = httpx.post(
"https://api.carlyemail.com/v0/agent/sign-up",
json={"human_email": "you@yourcompany.com", "username": "support"},
)
account = r.json()
```typescript TypeScript const res = await fetch("https://api.carlyemail.com/v0/agent/sign-up", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ human_email: "you@yourcompany.com", username: "support", }), }); const account = await res.json();
```json Response
{
"organization_id": "org_00ms93lsavnm83rw519vzpgw",
"inbox_id": "support@agents.carlyemail.com",
"api_key": "ce_us_dvfstqsgs0k7f0o7kkxafozcitwrv46cpp9tas03"
}
Warning
The key is returned once and stored only as a hash. There is no endpoint that
will show it to you again. Repeating sign-up for the same human_email rotates
the key and revokes the previous one.
Sign-up is idempotent by human_email, so a retrying agent is never wedged — it
gets a fresh key rather than an error.
2. Confirm the address
A six-digit code goes to the human_email you gave. Until it is confirmed the
key can read and organize mail but cannot send — see
limits.
curl -X POST https://api.carlyemail.com/v0/agent/verify \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
-H 'content-type: application/json' \
-d '{"otp_code": "307354"}'
Once verified, the inbox moves to the apex domain (carlyemail.com) for new
inboxes, and sending is enabled.
3. Send
```bash cURL curl -X POST "https://api.carlyemail.com/v0/inboxes/$INBOX_ID/messages/send" \ -H "Authorization: Bearer $CARLYEMAIL_API_KEY" \ -H 'content-type: application/json' \ -d '{ "to": ["someone@example.org"], "subject": "Hello", "text": "Sent from an agent." }'
```python Python
httpx.post(
f"https://api.carlyemail.com/v0/inboxes/{inbox_id}/messages/send",
headers={"Authorization": f"Bearer {api_key}"},
json={"to": ["someone@example.org"], "subject": "Hello", "text": "Sent from an agent."},
)
4. Read what comes back
curl "https://api.carlyemail.com/v0/inboxes/$INBOX_ID/messages" \
-H "Authorization: Bearer $CARLYEMAIL_API_KEY"
Replies are threaded automatically — a reply to a message you sent arrives on the
same thread_id. See threads.
Tip
Read extracted_text rather than text when reasoning over a thread. It has the
quoted reply chain stripped, so a model sees the new message rather than the
whole history repeated.