Desenvolvedores · REST API

A API do AI Emaily. Sua caixa de entrada, programável.

Uma API REST com versão sobre sua caixa de entrada unificada — Gmail, Outlook/Microsoft 365 e qualquer provedor IMAP — mais a camada de IA por cima: busca semântica, redação com sua voz, o Living Brief e o agente autônomo. Chaves de API com escopo, webhooks assinados e desfazer em cada envio.

URL base https://api.aiemaily.com/v1

Visão geral

Uma API para e-mail, busca, IA e o agente

REST + JSON, versionada na URL (/v1), documentada por uma especificação OpenAPI 3.1 que é a fonte da verdade do contrato. Tudo que o aplicativo AI Emaily pode fazer em seu nome, seu código também pode — dentro dos mesmos mecanismos de segurança.

E-mail como dados

Threads, mensagens, rascunhos, contatos, regras e calendário de todos os provedores — normalizados em um esquema unificado, paginados por cursor e com consistência de espelho.

A camada de IA

Busca semântica, respostas RAG sobre sua caixa de entrada, redação com sua voz fundamentada no Personal Context e o Living Brief como JSON estruturado.

Push, não polling

Webhooks assinados para novos e-mails, envios, ações do agente e briefs — HMAC-SHA256 com rotação e novas tentativas com backoff.

Segurança por construção

Chaves com escopo, envios com confirmação e janelas de desfazer, cotas diárias de envio, limites por plano e um log de auditoria completo.

Integrando com um assistente de IA em vez de código? As mesmas capacidades estão disponíveis como ferramentas MCP em https://mcp.aiemaily.com — consulte a documentação do servidor MCP.

Início rápido

Primeira chamada em menos de um minuto

Crie uma chave, liste suas threads não lidas e busque por significado. É tudo que você precisa para começar.

terminal
# 1. Create an API key at app.aiemaily.com → Settings → Developer
export AIEMAILY_API_KEY="aiem_live_..."

# 2. Your first call — what's unread in the inbox?
curl "https://api.aiemaily.com/v1/threads?state=inbox&unread=true&limit=5" \
  -H "Authorization: Bearer $AIEMAILY_API_KEY"

# 3. Search by meaning, not keywords
curl -X POST https://api.aiemaily.com/v1/search \
  -H "Authorization: Bearer $AIEMAILY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "the invoice Marta chased last month", "mode": "semantic"}'

Autenticação

Chaves de API com escopo

Autenticação Bearer com chaves que você cria, limita e revoga em Configurações → Desenvolvedor. As chaves são exibidas uma única vez e armazenadas apenas como hash.

every request
Authorization: Bearer aiem_live_3kd92mf8a1...
  • Formato da chave: aiem_live_… para produção, aiem_test_… para chaves de teste. Os prefixos são seguros para registrar; as chaves completas nunca são.
  • Os escopos são definidos na criação da chave. Crie uma chave com escopo restrito por integração para que revogar uma não afete as demais.
  • A revogação é imediata — as chaves são verificadas em cada requisição. Rotação: crie a nova chave, faça o deploy e revogue a antiga.
  • OAuth 2.1 + PKCE com registro dinâmico de clientes está disponível no servidor MCP para clientes de IA que atuam em seu nome. OAuth de três pernas para aplicativos REST de terceiros ainda não é público — fale conosco se estiver construindo um.

Escopos

Todos os escopos de permissão da API do AI Emaily
EscopoConcede
mail:readLer threads, mensagens e anexos
mail:writeArquivar, rotular, adiar, marcar como lido/não lido e destacar
mail:sendEnviar um rascunho existente (com confirmação) e cancelar dentro da janela de desfazer
drafts:readListar e ler rascunhos
drafts:writeCriar e editar rascunhos
search:readBusca por palavra-chave, semântica e híbrida
contacts:readListar contatos e dados de relacionamento
contacts:writeAtualizar contatos — status VIP, notas
context:readLer perfis de cliente e variáveis tipadas
context:writeCriar e atualizar perfis de cliente e variáveis
brief:readLer o Living Brief
ai:invokeExecutar operações de IA (ask-inbox, redação com IA) — consome créditos do plano
agent:readLer o log de ações do agente (o que Copilot/Autopilot fez)
agent:runIniciar um ciclo do agente sobre a caixa de entrada, dentro das suas configurações de autoridade
calendar:readLer eventos de calendário das contas conectadas
calendar:writeCriar e excluir eventos de calendário
webhooks:manageCriar, rotacionar e excluir endpoints de webhook
usage:readLer cotas e saldo de créditos

Convenções

Paginação, idempotência e erros

Aprenda estes três padrões e cada endpoint se comportará de forma previsível.

Paginação por cursor

Os endpoints de listagem retornam { data, has_more, next_cursor }. Passe cursor para obter a próxima página. Os cursores são opacos — não os analise.

pagination
GET /v1/threads?limit=25
→ { "data": [...25 threads...], "has_more": true, "next_cursor": "eyJvZmZzZXQiOjI1fQ" }

GET /v1/threads?limit=25&cursor=eyJvZmZzZXQiOjI1fQ
→ { "data": [...], "has_more": false }

Idempotência

Envie um cabeçalho Idempotency-Key (qualquer string única, ex.: um UUID) em requisições mutantes. Novas tentativas com a mesma chave retornam o resultado original em vez de repetir a ação. Obrigatório em endpoints de envio; recomendado em todos os demais.

Envelope de erro

Cada erro é um código estável legível por máquina mais uma mensagem legível e um request_id que você pode passar ao suporte. A tabela completa de códigos está abaixo.

error · 400
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_params",
    "message": "Sending requires confirm: true — sends are never implicit.",
    "param": "confirm",
    "request_id": "req_8f31ka92"
  }
}

Referência de endpoints

Todos os endpoints

Agrupados por recurso, cada um com parâmetros e um par real de requisição/resposta. Busque por caminho, escopo ou função.

Accounts

The mailboxes connected to the AI Emaily account. Read-only over the API — connecting a mailbox happens in-app (OAuth with the provider).

GET/accountsmail:readList connected mailboxes.
response
{
  "data": [
    { "id": "acc_71b2", "provider": "gmail", "email": "[email protected]", "status": "active" },
    { "id": "acc_98x1", "provider": "outlook", "email": "[email protected]", "status": "active" }
  ],
  "has_more": false
}

Threads

Conversations across every connected mailbox. State changes mirror back to Gmail/Outlook/IMAP so all clients stay consistent.

GET/threadsmail:readList threads, filtered and cursor-paginated.
Parameters for GET /threads
ParameterInTypeDescription
statequeryinbox | archived | snoozed | trash | sentThread state. Default inbox.
tabqueryprimary | social | promotions | updatesCategory tab filter.
labelquerystringOnly threads carrying this label.
account_idquerystringRestrict to one mailbox.
unreadquerybooleanOnly unread threads.
limitquerynumber (1–100)Page size. Default 25.
cursorquerystringCursor from a previous page.
request
GET /v1/threads?state=inbox&tab=primary&unread=true&limit=10
response
{
  "data": [
    {
      "id": "thr_9f2ka81",
      "account_id": "acc_71b2",
      "subject": "Contract renewal — need your sign-off by Friday",
      "from": { "name": "Dana Whitfield", "email": "[email protected]" },
      "snippet": "Hi — legal cleared the redlines. Can you confirm the...",
      "labels": ["important", "client/acme"],
      "unread": true,
      "message_count": 4,
      "updated_at": "2026-07-10T14:22:00Z"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJvZmZzZXQiOjEwfQ"
}
GET/threads/{id}mail:readGet one thread with its message list.
Parameters for GET /threads/{id}
ParameterInTypeDescription
id*pathstringThread id.
response
{
  "id": "thr_9f2ka81",
  "subject": "Contract renewal — need your sign-off by Friday",
  "participants": ["[email protected]", "[email protected]"],
  "labels": ["important", "client/acme"],
  "state": "inbox",
  "messages": [{ "id": "msg_77xk1", "from": { "email": "[email protected]" }, "date": "2026-07-10T14:22:00Z", "snippet": "Hi — legal cleared..." }]
}
PATCH/threads/{id}mail:writeMutate thread state — read, star, archive, labels, snooze.

All mutations are reversible and mirror to the provider. Combine multiple changes in one call.

Parameters for PATCH /threads/{id}
ParameterInTypeDescription
readbodybooleanMark read/unread.
starredbodybooleanStar / unstar.
statebodyinbox | archived | trash | spamMove the thread.
add_labels / remove_labelsbodystring[]Label changes. New labels are created on first use.
snooze_untilbodyISO 8601 datetime | nullSnooze; null unsnoozes.
request
{ "read": true, "add_labels": ["client/acme"], "state": "archived" }
response
{ "id": "thr_9f2ka81", "state": "archived", "labels": ["important", "client/acme"], "unread": false }
GET/threads/{id}/messagesmail:readList full messages in a thread.
Parameters for GET /threads/{id}/messages
ParameterInTypeDescription
include_quotedquerybooleanInclude quoted reply history in bodies. Default false.
response
{
  "data": [
    {
      "id": "msg_77xk1",
      "from": { "name": "Dana Whitfield", "email": "[email protected]" },
      "to": [{ "email": "[email protected]" }],
      "date": "2026-07-10T14:22:00Z",
      "body_text": "Hi — legal cleared the redlines. Can you confirm the renewal terms by Friday? — Dana",
      "attachments": [{ "id": "att_3m1", "name": "renewal-v4.pdf", "size": 182044, "mime": "application/pdf" }]
    }
  ],
  "has_more": false
}

Messages & attachments

Individual messages, decrypted bodies, and attachment downloads. Bodies are stored encrypted; decryption happens server-side per request.

GET/messages/{id}mail:readGet one message with metadata and text body.
response
{
  "id": "msg_77xk1",
  "thread_id": "thr_9f2ka81",
  "from": { "name": "Dana Whitfield", "email": "[email protected]" },
  "date": "2026-07-10T14:22:00Z",
  "body_text": "Hi — legal cleared the redlines...",
  "headers": { "message_id": "<[email protected]>" }
}
GET/messages/{id}/bodymail:readStream the full sanitized HTML body.

Returns text/html. Tracking pixels are stripped and links sandboxed, exactly as in the app.

response
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

<!doctype html><html>…sanitized message body…</html>
GET/messages/{id}/attachments/{att_id}mail:readDownload an attachment (streamed).
response
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="renewal-v4.pdf"

<binary>

Drafts & sending

The recommended flow is draft-then-send: iterate on a draft, then commit with an explicit send call. Idempotency-Key is required on sends.

GET/draftsdrafts:readList drafts.
response
{
  "data": [{ "id": "drf_8s31x", "to": ["[email protected]"], "subject": "Re: Contract renewal", "status": "draft", "updated_at": "2026-07-10T14:50:00Z" }],
  "has_more": false
}
POST/draftsdrafts:writeCreate a draft — plain, or AI-written in the user's voice.

With use_ai: true, AI Emaily writes the body from instructions using the user's Personal Context (spends 1 AI credit).

Parameters for POST /drafts
ParameterInTypeDescription
account_idbodystringSending mailbox. Default: primary account.
reply_to_thread_idbodystringCompose as a reply to this thread.
to / cc / bccbodystring[]Recipients. Inherited when replying.
subjectbodystringSubject. Inherited when replying.
bodybodystringPlain text or simple HTML body.
use_aibodybooleanHave AI Emaily write the body. Default false.
instructionsbodystringWhat the AI draft should say (with use_ai).
request
{
  "reply_to_thread_id": "thr_9f2ka81",
  "use_ai": true,
  "instructions": "Confirm the renewal at the agreed $24k/year, ask for the signature link, warm tone."
}
response
{
  "id": "drf_8s31x",
  "to": ["[email protected]"],
  "subject": "Re: Contract renewal — need your sign-off by Friday",
  "body": "Hi Dana — confirmed on our side at $24,000/year as agreed. Send over the signature link and I'll turn it around today. Best, Alex",
  "status": "draft",
  "credits_spent": 1
}
PATCH/drafts/{id}drafts:writeEdit a draft.
request
{ "body": "Hi Dana — confirmed at $24,000/year. Please send the signature link. Best, Alex" }
response
{ "id": "drf_8s31x", "status": "draft", "updated_at": "2026-07-10T14:58:00Z" }
DELETE/drafts/{id}drafts:writeDelete a draft.
response
{ "id": "drf_8s31x", "deleted": true }
POST/drafts/{id}/sendmail:sendSend a draft — explicit, capped, undoable.

Requires confirm: true and an Idempotency-Key header. Counts against the plan's daily send cap. Returns an undo handle valid for the undo window.

Parameters for POST /drafts/{id}/send
ParameterInTypeDescription
confirm*bodybooleanMust be true.
undo_window_sbodynumber (0–30)Server-side undo hold. Default 10.
scheduled_atbodyISO 8601 datetimeSchedule instead of sending now.
request
POST /v1/drafts/drf_8s31x/send
Idempotency-Key: 5f3e9c1a-renewal-reply

{ "confirm": true }
response
{
  "send_id": "snd_1vv92",
  "status": "scheduled",
  "undo_until": "2026-07-10T15:04:10Z"
}
POST/sends/{id}/cancelmail:sendCancel a send inside its undo window.

Atomic: succeeds only before dispatch. After the window, returns 409 undo_window_elapsed and the message stays sent.

response
{ "send_id": "snd_1vv92", "status": "undone", "draft_id": "drf_8s31x" }
POST/messages/sendmail:sendCompose and send in one call (scripts only).

For trusted automations. Same caps, idempotency requirement, and undo semantics as draft sends. Not exposed as an MCP tool — agents must use the draft-then-send flow.

request
POST /v1/messages/send
Idempotency-Key: 91c2ab-receipt-fwd

{
  "account_id": "acc_71b2",
  "to": ["[email protected]"],
  "subject": "June receipts",
  "body": "Attached digest of June receipts.",
  "undo_window_s": 10
}
response
{ "send_id": "snd_8a2m1", "status": "scheduled", "undo_until": "2026-07-10T15:10:10Z" }

Contacts

People, enriched with relationship signals from your mail history.

GET/contactscontacts:readList or search contacts.
Parameters for GET /contacts
ParameterInTypeDescription
qquerystringName, email, or domain filter.
vipquerybooleanOnly VIPs.
response
{
  "data": [{ "id": "cnt_11a", "name": "Dana Whitfield", "email": "[email protected]", "vip": true, "last_contact": "2026-07-10", "threads": 42 }],
  "has_more": false
}
PATCH/contacts/{id}contacts:writeUpdate a contact (VIP flag, notes).
request
{ "vip": true, "notes": "VP Ops at Acme — renewal owner." }
response
{ "id": "cnt_11a", "vip": true }

Rules

Inbox rules (filing, labeling) and agent rules (per-sender authority). Conditions and actions are validated against the same allowlist the app uses.

GET/rulesmail:readList rules.
response
{
  "data": [
    {
      "id": "rul_5m2",
      "kind": "inbox",
      "conditions": [{ "field": "from_domain", "op": "equals", "value": "acme.com" }],
      "actions": [{ "type": "addLabel", "value": "client/acme" }],
      "priority": 10
    }
  ]
}
POST/rulesmail:writeCreate a rule.
request
{
  "kind": "inbox",
  "conditions": [{ "field": "subject", "op": "contains", "value": "invoice" }],
  "actions": [{ "type": "addLabel", "value": "finance" }, { "type": "setCategory", "value": "updates" }]
}
response
{ "id": "rul_9k1", "kind": "inbox", "priority": 20 }
DELETE/rules/{id}mail:writeDelete a rule.
response
{ "id": "rul_9k1", "deleted": true }

Personal Context

The Context & Variables Engine: per-client profiles keyed to email domains, plus typed variables with per-client overrides. What makes AI drafts factually right.

GET/context/profilescontext:readList client/domain profiles.
response
{
  "data": [{ "id": "ctx_acme", "domain": "acme.com", "name": "Acme Corp", "updated_at": "2026-07-10T15:00:00Z" }],
  "has_more": false
}
GET/context/profiles/{id}context:readGet one profile with its variables.
response
{
  "id": "ctx_acme",
  "domain": "acme.com",
  "summary": "Enterprise client since 2024. Renewal cycle: August. Main contact Dana Whitfield (VP Ops).",
  "variables": { "client.name": "Acme Corp", "pricing.renewal": "$24,000/year", "tone": "warm, concise" }
}
PATCH/context/profiles/{id}context:writeUpdate profile variables or append a note.
request
{ "set": { "pricing.renewal": "$24,000/year" }, "append_note": "Renewal confirmed 2026-07-10 at $24k/yr." }
response
{ "id": "ctx_acme", "updated_keys": ["pricing.renewal"] }
GET/context/variablescontext:readList global typed variables.
response
{ "data": [{ "key": "pricing.pro", "value": "$20/month", "type": "string" }] }
GET/context/filescontext:readList the reference files attached to Personal Context.

Documents you've added to the context brain (rate cards, playbooks, boilerplate) that ground AI drafting. Returns metadata; bodies are fetched by id.

response
{
  "data": [{ "id": "ctf_5a2", "name": "2026-rate-card.pdf", "bytes": 84213, "profile_id": "ctx_acme", "created_at": "2026-07-01T10:00:00Z" }],
  "has_more": false
}

Brief

The Living Brief as structured data — read the latest, or generate a fresh one on demand. Generation is credit-metered (BYOK plans uncapped) and reports credits_spent.

GET/brief/latestbrief:readGet the latest Living Brief.
response
{
  "date": "2026-07-10",
  "needs_reply": [{ "thread_id": "thr_9f2ka81", "from": "[email protected]", "why": "Sign-off requested by Friday" }],
  "commitments": [{ "thread_id": "thr_5h2m6", "promise": "Send Q3 proposal to Linh", "due": "2026-07-11" }],
  "calendar": [{ "title": "Acme renewal call", "start": "2026-07-10T16:00:00Z" }]
}
POST/brief/generateai:invokeGenerate a fresh brief now (spends AI credits).
response
{ "date": "2026-07-10", "status": "ready", "credits_spent": 3 }

Calendar

Google Calendar events synced through connected accounts.

GET/calendar/eventscalendar:readList events in a window.
Parameters for GET /calendar/events
ParameterInTypeDescription
from / to*queryISO 8601 datetimeWindow bounds.
response
{ "data": [{ "id": "evt_3k1", "title": "Acme renewal call", "start": "2026-07-10T16:00:00Z", "end": "2026-07-10T16:30:00Z" }] }
POST/calendar/eventscalendar:writeCreate an event.
request
{ "title": "Contract review", "start": "2026-07-14T15:00:00Z", "end": "2026-07-14T15:30:00Z", "attendees": ["[email protected]"] }
response
{ "id": "evt_9m4", "status": "confirmed" }
DELETE/calendar/events/{id}calendar:writeDelete an event.
response
{ "id": "evt_9m4", "deleted": true }

Webhooks

Push instead of poll: register HTTPS endpoints and receive signed events. Retries with exponential backoff for 3 days, then the endpoint auto-disables (you get an email).

GET/webhookswebhooks:manageList webhook endpoints.
response
{ "data": [{ "id": "whk_2d1", "url": "https://yourco.com/hooks/aiemaily", "events": ["message.received"], "status": "active" }] }
POST/webhookswebhooks:manageRegister an endpoint. The signing secret is returned once.
request
{ "url": "https://yourco.com/hooks/aiemaily", "events": ["message.received", "send.completed"] }
response
{
  "id": "whk_2d1",
  "url": "https://yourco.com/hooks/aiemaily",
  "events": ["message.received", "send.completed"],
  "secret": "whsec_9a81c2...  // shown once — store it now",
  "status": "active"
}
POST/webhooks/{id}/rotate-secretwebhooks:manageRotate the signing secret (old secret stays valid 24h).
response
{ "id": "whk_2d1", "secret": "whsec_new...", "previous_valid_until": "2026-07-11T15:00:00Z" }
DELETE/webhooks/{id}webhooks:manageDelete an endpoint.
response
{ "id": "whk_2d1", "deleted": true }

Usage

Quota and credit visibility, so integrations can pace themselves instead of hitting 429s.

GET/usageusage:readCurrent period consumption and limits.
response
{
  "plan": "autopilot",
  "requests": { "used": 1240, "limit": 20000, "resets": "2026-07-11T00:00:00Z" },
  "sends": { "used": 12, "limit": 1000 },
  "ai_credits": { "used": 46, "limit": 1000, "byok": false }
}

Webhooks

Eventos, assinatura e verificação

Registre um endpoint HTTPS, escolha eventos e verifique assinaturas. As entregas serão repetidas com backoff exponencial por 3 dias; um endpoint que falhar persistentemente é desativado automaticamente e você receberá um e-mail.

Catálogo de eventos

message.receivedUma nova mensagem chega em qualquer caixa de entrada conectada (pós-triagem, então as tags já estão disponíveis).
payload
{
  "event": "message.received",
  "created_at": "2026-07-10T14:22:03Z",
  "data": {
    "thread_id": "thr_9f2ka81",
    "message_id": "msg_77xk1",
    "account_id": "acc_71b2",
    "from": { "email": "[email protected]" },
    "subject": "Contract renewal — need your sign-off by Friday",
    "tags": ["important", "client"]
  }
}
thread.updatedMudanças de estado da thread: arquivada, rotulada, adiada, estado de leitura.
payload
{ "event": "thread.updated", "data": { "thread_id": "thr_9f2ka81", "changes": { "state": "archived" } } }
send.completedUm envio saiu da caixa de saída com sucesso (após a janela de desfazer).
payload
{ "event": "send.completed", "data": { "send_id": "snd_1vv92", "thread_id": "thr_9f2ka81", "message_id": "msg_81aa2" } }
send.failedUm envio falhou após várias tentativas (rejeição do provedor, falha de autenticação).
payload
{ "event": "send.failed", "data": { "send_id": "snd_1vv92", "reason": "provider_rejected", "detail": "550 mailbox unavailable" } }
draft.createdO agente redigiu uma resposta e a retém para revisão (Copilot).
payload
{ "event": "draft.created", "data": { "draft_id": "drf_8s31x", "thread_id": "thr_9f2ka81", "confidence": 0.93 } }
agent.actionQualquer ação autônoma do agente: triagem, fila, envio, escalonamento.
payload
{ "event": "agent.action", "data": { "kind": "queued", "thread_id": "thr_2231a", "confidence": 0.95, "undo_until": "2026-07-10T15:09:00Z" } }
brief.readyO Living Brief diário terminou de ser gerado.
payload
{ "event": "brief.ready", "data": { "date": "2026-07-10", "needs_reply_count": 4 } }

Verifique cada entrega

Cada entrega carrega X-Aiemaily-Signature: t=<unix-ts>,v1=<hmac> — um HMAC-SHA256 de ${t}.${rawBody} com o segredo do seu endpoint. Verifique a assinatura, rejeite timestamps antigos e sempre compare em tempo constante.

verify.ts · Node
import crypto from "node:crypto";

// X-Aiemaily-Signature: t=1760107330,v1=5257a869e7...
export function verifyAiemailySignature(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
  const ts = Number(parts.t);
  // Reject stale deliveries (replay protection)
  if (!ts || Math.abs(Date.now() / 1000 - ts) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  try {
    return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(parts.v1, "hex"));
  } catch {
    return false;
  }
}

SDKs

SDKs oficiais, gerados a partir da especificação

Clientes para TypeScript e Python com requisições tipadas, erros tipados, novas tentativas automáticas com backoff e utilitários de paginação. Ou gere o seu a partir do documento OpenAPI.

@aiemaily/sdk · npm
npm install @aiemaily/sdk

import { Aiemaily } from "@aiemaily/sdk";

const aiemaily = new Aiemaily({ apiKey: process.env.AIEMAILY_API_KEY });

// List what needs attention
const { data: threads } = await aiemaily.threads.list({ state: "inbox", unread: true });

// Semantic search
const { data: hits } = await aiemaily.search({ query: "invoices from June", mode: "semantic" });

// Draft in the user's voice, then send explicitly
const draft = await aiemaily.drafts.create({
  replyToThreadId: hits[0].threadId,
  useAi: true,
  instructions: "Confirm receipt, promise payment by Friday",
});
const send = await aiemaily.drafts.send(draft.id, { confirm: true });

// Errors are typed: err.code === "rate_limited", err.retryAfter, err.requestId

Erros

Códigos de erro

Códigos estáveis, compartilhados com o servidor MCP. Avalie error.code, nunca o texto da mensagem.

Códigos de erro da API do AI Emaily
CódigoHTTPSignificadoO que fazer
unauthorized401Token / chave de API ausente, expirado ou revogado.Refaça o fluxo OAuth no seu cliente, ou emita uma nova chave de API em Configurações → Desenvolvedor.
forbidden_scope403O token não possui o escopo exigido por esta ferramenta ou endpoint.Reconecte e conceda o escopo na tela de consentimento. Ferramentas para as quais você não tem escopos ficam ocultas na lista.
invalid_params400Os parâmetros falharam na validação (campo ausente, tipo incorreto, confirm não é true em um envio).A mensagem de erro indica o parâmetro que falhou. Verifique os tipos na referência de ferramentas/endpoints.
not_found404O ID da thread, rascunho ou contato não existe ou não é seu.IDs têm escopo de usuário — busque novamente com list_inbox ou search_email.
rate_limited429Taxa de requisições por chave, por usuário ou por IP excedida.Respeite Retry-After. Chame get_usage para ver a cota restante antes de processos em lote.
quota_exceeded429Uma cota diária foi esgotada — o limite de requisições ou envios do plano.As cotas são redefinidas diariamente (UTC). Verifique get_usage; entre em contato com o suporte para limites maiores.
insufficient_credits402Os créditos de IA do período foram consumidos (planos medidos).Compre um recarregamento, aguarde a redefinição ou mude para BYOK (sem limite).
plan_required402O recurso exige um plano superior — ex.: MCP requer Autopilot ou Team.Atualize em aiemaily.com/pricing, ou peça ao administrador do seu time para adicionar um assento.
internal_error500Algo falhou do nosso lado.É seguro tentar novamente uma vez. Cada resposta contém um request_id — inclua-o ao contatar o suporte.

Limites de uso e planos

Cotas por plano

Limites diários de requisições e envios definidos pelo plano, mais um teto de rajada por minuto por chave (120/min), por usuário (300/min) e por IP (300/min). Cada resposta inclui X-RateLimit-Limit / -Remaining / -Reset; respostas 429 incluem Retry-After.

Limites de uso da API do AI Emaily por plano
PlanoAcesso à APIRequisições / diaEnvios / diaEndpoints de webhook
Free
Pro · $20/mês✓ core scopes5,0002002
Autopilot · $40/mês✓ all scopes + MCP20,0001,00010
Team · a partir de $25/assento✓ org keys + MCPAgrupado por assentoAgrupado20
  • Os endpoints de IA (/ai/*, /brief/generate, redação com use_ai, busca semântica) consomem créditos de IA do plano. Planos BYOK não têm limite.
  • Novas chaves operam com cotas de envio reduzidas nas primeiras 24 horas (proteção contra abuso).
  • Precisa de mais? Fale conosco sobre limites maiores.

FAQ

Perguntas frequentes

O que é a API do AI Emaily?

Uma API REST com versão (api.aiemaily.com/v1) que expõe sua caixa de entrada unificada — Gmail, Outlook/Microsoft 365 e qualquer provedor IMAP — mais a camada de IA do AI Emaily (busca semântica, redação com sua voz, o Living Brief, o agente autônomo) para seus próprios scripts, backends e ferramentas de automação.

Como obtenho uma chave de API?

Configurações → Desenvolvedor → Chaves de API no aplicativo AI Emaily (plano Pro ou superior). As chaves têm escopos fixos na criação, são exibidas uma única vez e armazenadas apenas como hash. Use uma chave com escopo restrito por integração.

Quais planos incluem acesso à API?

Pro ($20/mês) inclui a API REST com escopos básicos. Autopilot ($40/mês) adiciona escopos de agente e o servidor MCP. Team (a partir de $25/assento) adiciona chaves de organização e cotas agrupadas. O plano Free não tem acesso à API.

Existe uma especificação OpenAPI?

Sim — o documento OpenAPI 3.1 legível por máquina está em api.aiemaily.com/v1/openapi.json e é a fonte da verdade do contrato completo. Os SDKs de TypeScript e Python são gerados a partir dele, e você pode gerar clientes para qualquer outro idioma.

Como os webhooks são mantidos seguros?

Cada entrega é assinada: o cabeçalho X-Aiemaily-Signature carrega um timestamp e um HMAC-SHA256 do payload com o segredo do seu endpoint. Verifique a assinatura e rejeite timestamps antigos (com mais de 5 minutos) para evitar ataques de replay. Os segredos rodam com uma janela de validade dupla de 24 horas.

O que acontece se eu exceder um limite de uso?

Você recebe um 429 com um cabeçalho Retry-After. Um teto de rajada por minuto (rate_limited) se aplica por chave, por usuário e por IP; as cotas diárias de requisições e envios (quota_exceeded) são definidas pelo plano. Verifique GET /v1/usage (ou os cabeçalhos X-RateLimit em qualquer resposta) para gerenciar jobs em lote.

A API pode ignorar as configurações de segurança do aplicativo?

Não. A API usa o mesmo núcleo de aplicação com escopo de propriedade que o aplicativo e o servidor MCP: os envios exigem confirmação explícita e contam contra os limites diários, as execuções do agente respeitam seus modos de autoridade e listas de remetentes permitidos, e cada mutação é auditada.

O conteúdo dos meus e-mails é usado para treinar modelos?

Nunca. Acordos de retenção zero com provedores de modelos e sem treinamento sobre e-mails do usuário — a mesma política de privacidade que governa o aplicativo cobre cada chamada à API e ao servidor MCP.

Versionamento e changelog

Um contrato sobre o qual você pode construir

Versão principal na URL (/v1). Mudanças aditivas — novos endpoints, novos campos opcionais — são publicadas continuamente e nunca quebram clientes existentes. Mudanças disruptivas vão para /v2 com pelo menos 6 meses de aviso de depreciação com execução dupla, anunciadas aqui e por e-mail para todos os proprietários de chaves ativas.

v1.0.0

2026 — GAatual
  • Lançamento público inicial: 21 ferramentas em leitura, busca & IA, organização, redação & envio, e contexto & análise.
  • JSON-RPC HTTP com streaming em https://mcp.aiemaily.com, negociando o protocolo MCP 2025-11-25; as ferramentas carregam anotações (indicadores readOnly / destructive / idempotent).
  • OAuth 2.1 com PKCE e registro dinâmico de clientes — a tela de consentimento mostra um badge de verificado/não verificado e o host de redirecionamento, e restringe escopos privilegiados; portador de chave de API (aiem_live_…) para clientes headless.
  • Ferramentas de busca e recuperação compatíveis com ChatGPT, para que os conectores de pesquisa profunda e de conhecimento empresarial funcionem sem configuração adicional.
  • Envio em duas etapas com confirmação e janela de desfazer no servidor; delimitação de conteúdo não confiável em todas as saídas derivadas de e-mail.
  • Limites de uso por chave, por usuário e por IP, cotas diárias de requisições/envios e log de auditoria completo.

v0.9.0

2026 — beta privada
  • Beta com parceiros de design sobre a API REST v1.
  • Adicionados get_attachment_text e list_agent_actions com base no feedback da beta.
  • Tela de consentimento reescrita em linguagem de produto (scope → inglês simples).

Construa sobre sua caixa de entrada.

Crie uma chave, faça uma chamada, publique algo. O acesso à API começa no Pro; os agentes têm o servidor MCP no Autopilot.