Developer

A REST email API built for AI agents

AutoEmail's Agent REST API gives an AI agent a token-authenticated email inbox over HTTP: list and read mail, draft or send replies, run outreach, and manage contacts and calendar events. One bearer API key fixes the key's mode - human_in_the_loop queues every write for approval, full_autonomous sends immediately unless told otherwise.

The agent loop

A typical run looks the same whether the caller is a scheduled job or a long-running agent process: authenticate once, discover what the key is allowed to touch, then loop through read, decide, and draft or send. Automated senders should also set a fresh Idempotency-Key header on every write and reuse that same key only when retrying the exact same logical email, so a network timeout or a 5xx response can never send the same reply twice.

  1. 1GET/meAuthenticate

    Send the bearer key and read back its mode (human_in_the_loop or full_autonomous) and its allowedAccounts. Nothing else works until this call succeeds.

  2. 2GET/accountsDiscover sendable accounts

    List the mailboxes this specific key may read and send from - the same non-secret businessId, domain, email, name shape returned inside GET /me.

  3. 3GET/emailsRead the inbox

    Page through mail, filterable by businessId, status, or a search term. Each row already carries the resolved effectiveReplyTo and effectiveReplySubject a reply will actually use.

  4. 4GET/emails/{id}Open one message

    Fetch the full body, any attachments, and the latest draft (or null) for a single email inside the key's allowlist.

  5. 5POST/emails/{id}/replyDraft or send a reply

    Reply with final copy, or set mode: "generate" and let AutoEmail write it. What happens next depends entirely on the key's mode - see below.

  6. 6POST/emails/{id}/approveApprove the draft

    On a full_autonomous key, approve sends the latest draft over SMTP and marks the email sent.

  7. 7POST/emails/{id}/declineOr decline it

    Reject a pending item instead. Optional feedback is summarized into a learning that improves future drafts, in either key mode.

Human-in-the-loop vs full-autonomous

The API has two operating modes, fixed per key, that mirror the two paid tiers where API access exists at all. On the Team plan ($149/month billed monthly, $127/month billed annually), every key is human_in_the_loop: a call to POST /emails/{id}/reply or POST /emails/send always creates a pending draft in the dashboard approval queue. Nothing sends until a person reviews it and clicks approve, whatever the request body says.

On the Agentic plan ($399/month billed monthly, $339/month billed annually), keys are full_autonomous: final-copy replies and sends go out over SMTP immediately, and the email is marked sent in the same response. Setting send: false on that same call downgrades it back to a draft for that one request, so an otherwise autonomous key can still ask for review on a case-by-case basis. AI-generated copy (mode: "generate") always queues a draft by default and only sends with an explicit send: true.

The same split governs POST /outreach/batch: a human_in_the_loop key that sets send: true is rejected outright with 403 mode_not_allowed, while a full_autonomous key with send: true drip-sends the accepted recipients with a small jittered delay between each send for deliverability, and reports the real per-recipient outcome asynchronously.

Free and Operator plans have no agent API access at all (agentApiAccess: "none") - no key can be issued on those plans, so GET /me returns 401 for any bearer token presented against them.

Authentication

Every request carries one bearer API key: Authorization: Bearer ak_live_<random>. Auth fails closed (401) on a missing or non-Bearer header, an empty token, an unknown key, or a revoked key.

Keys are created in the dashboard under Settings, API Keys. The plaintext is shown exactly once at creation; the server stores only a SHA-256 hash, so a lost key cannot be recovered, only revoked and replaced. Call GET /me first in any new integration - it returns the key's id, its mode, and the allowedAccounts it may read and send from, which is everything needed to start the loop above.

The API is CORS-closed on purpose: no Access-Control-Allow-* headers, no OPTIONS handlers. It is meant to be called from a backend, never from client-side JavaScript.

Every route also enforces its own per-key rate limit on a 60-second sliding window: discovery reads such as GET /me and GET /accounts allow up to 60 requests per minute, listing endpoints like GET /emails allow 120, writes such as replying or sending are capped at 30, and the IMAP sync trigger is limited to 6. A well-behaved agent reads GET /usage to track remaining quota and backs off before it hits a 429 or a 402 quota_exceeded.

Endpoint reference

28 operations across 13 tags, generated directly from the committed OpenAPI spec (v2.0.2). Open the interactive explorer for full request/response schemas and to try a call.

Discovery

MethodPathSummary
GET/meGet key identity and capabilities
GET/accountsList accounts this key may send from

Read

MethodPathSummary
GET/emailsList / filter emails
GET/searchFull-text email search
GET/emails/{id}Get a single email and its latest draft

Write

MethodPathSummary
POST/emails/{id}/replyReply to an existing inbound email
POST/emails/sendCompose and send a new outbound email
POST/outreach/batchBulk-send outreach to up to 100 recipients (API-only primitive)

Sync

MethodPathSummary
POST/accounts/{businessId}/syncTrigger an IMAP sync for one mailbox

Threads

MethodPathSummary
GET/threadsList conversation threads
GET/threads/{id}Get a thread + message summaries

State

MethodPathSummary
PATCH/emails/{id}Update email state (read/starred/status) or the reply recipient/subject

Drafts

MethodPathSummary
GET/emails/{id}/draftsList draft versions of an email
POST/emails/{id}/approveApprove + send the latest draft
POST/emails/{id}/declineDecline a pending email

Attachments

MethodPathSummary
GET/emails/{id}/attachmentsList attachment metadata for an email
GET/attachments/{id}/download-urlGet a short-lived attachment download URL

Contacts

MethodPathSummary
GET/contactsList/search contacts
POST/contactsCreate or upsert a contact
PATCH/contacts/{id}Update a contact
DELETE/contacts/{id}Delete a contact

Calendar

MethodPathSummary
GET/calendar-eventsList calendar events (read-only)

Spam

MethodPathSummary
GET/accounts/{businessId}/spam-settingsGet spam settings
PUT/accounts/{businessId}/spam-settingsUpdate spam settings

Lessons

MethodPathSummary
GET/accounts/{businessId}/lessonsList active learnings + spam lessons
POST/accounts/{businessId}/lessonsAdd a manual learning
DELETE/lessons/{id}Delete a learning

Usage

MethodPathSummary
GET/usageGet current-period quota usage

Examples

Two real calls against the production base URL. Replace the bearer token with your own key and the email id with one returned by GET /emails.

Discover the key's identity and capabilities:

curl https://courteous-gopher-315.eu-west-1.convex.site/api/v1/me \
  -H "Authorization: Bearer ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Reply to an email with final copy, held as a draft for this one call:

curl -X POST https://courteous-gopher-315.eu-west-1.convex.site/api/v1/emails/m3k9q1w5e7r2t4y6u8i0o9p1/reply \
  -H "Authorization: Bearer ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f3c1e2a-0b4d-4c9e-8a21-9d6f0b2e5c14" \
  -d '{
    "body": "Your order shipped yesterday - tracking attached.",
    "send": false
  }'

What this is not

This is not a bulk transactional-email provider. POST /outreach/batch takes 1 to 100 recipients per call, with a per-mailbox daily send cap, dedupe against recently-contacted addresses, and a targeted pre-send reply check - it is built for agent-orchestrated outreach, not for replacing an ESP send API designed for six-figure volumes per hour.

This is not CORS-enabled. There are no Access-Control-Allow-* headers and no OPTIONS handlers, so the API cannot be called from a browser. Treat the bearer key like any other server secret and call it from a backend only.

This is not available on every plan. GET /me and GET /accounts work for any valid key, but writes require a plan that grants agent API access: human_in_the_loop on Team, full (including autonomous send) on Agentic. Free and Operator plans have no agent API access at all.

This is not a durable task queue. Idempotency keys are scoped per API key and expire after 24 hours, after which the same key value is treated as new; pending drafts persist until a human or a full_autonomous key resolves them, but the approval queue is meant to be worked continuously, not used as a long-term backlog.

Frequently asked questions

A single bearer API key of the form ak_live_<random>, sent as an Authorization: Bearer header. Keys are created in the dashboard under Settings, API Keys; the plaintext is shown once and only a SHA-256 hash is stored server-side, so a lost key must be revoked and replaced rather than retrieved.

autoemail

Put AI on every reply. Keep yourself in the loop.

Connect one inbox, watch AutoEmail draft every reply, and approve before anything sends. Free to start, no card required.

30-day money-back guarantee

Try any paid plan risk-free. If AutoEmail is not saving you time inside 30 days, email us and we refund you in full - no forms, no friction.