REST API v1

API Reference

All endpoints are under https://api.emails4agents.com/v1. Authenticate with X-API-Key: e4a_... on every request.

Authentication

Pass your API key in the X-API-Key header on every request. Keys are prefixed with e4a_.

Request header
X-API-Key: e4a_your_key_here

Permissions: Keys have scopes — read, send, admin. Admin keys can manage domains, inboxes, and other keys. Read-only keys can only list and fetch. Send keys can send email but not manage resources.

Domains

POST /v1/domains Add a domain

Adds a new domain. With auto_dns: true (default), automatically configures DNS in Cloudflare and registers a SES sending identity.

Request
curl -X POST https://api.emails4agents.com/v1/domains \
  -H "X-API-Key: e4a_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "yourdomain.com",
    "auto_dns": true
  }'
Response 201
{
  "id": "dom_uuid",
  "name": "yourdomain.com",
  "mx_verified": false,
  "spf_verified": false,
  "dkim_verified": false,
  "dmarc_verified": false,
  "warmup_status": "new",
  "daily_send_limit": 100,
  "is_active": true,
  "dns_records": { ... },
  "dns_setup": {
    "ses": "ok",
    "cloudflare": "ok"
  },
  "created_at": "2025-04-16T10:00:00Z"
}
GET /v1/domains List all domains
Request
curl https://api.emails4agents.com/v1/domains \
  -H "X-API-Key: e4a_..."
POST /v1/domains/{id}/verify Verify DNS records

Checks MX, SPF, DKIM, and DMARC records are correctly configured.

Response 200
{
  "mx_verified": true,
  "spf_verified": true,
  "dkim_verified": true,
  "dmarc_verified": true
}

Inboxes

POST /v1/inboxes Create an inbox

Provisions a new inbox. The address is {username}@{domain}.

Request
curl -X POST https://api.emails4agents.com/v1/inboxes \
  -H "X-API-Key: e4a_..." \
  -d '{
    "username": "agent",
    "domain_id": "dom_uuid",
    "display_name": "My Agent"
  }'
Response 201
{
  "id": "inb_uuid",
  "domain_id": "dom_uuid",
  "username": "agent",
  "display_name": "My Agent",
  "address": "[email protected]",
  "is_active": true,
  "created_at": "2025-04-16T10:00:00Z"
}
GET /v1/inboxes List inboxes

Optionally filter by domain_id.

Request
curl "https://api.emails4agents.com/v1/inboxes?domain_id=dom_uuid" \
  -H "X-API-Key: e4a_..."
GET /v1/inboxes/{id} Get inbox by ID
DELETE /v1/inboxes/{id} Deactivate inbox

Soft-deletes the inbox (sets is_active: false). Message history is preserved.

Messages

POST /v1/messages/send Send an email

Sends an email from an inbox via AWS SES. Provide at least text or html.

Request body
{
  "from_inbox_id": "inb_uuid",
  "to": "[email protected]",
  "subject": "Hello from my agent",
  "text": "Plain text body",
  "html": "<p>HTML body</p>",

  // Optional: reply in an existing thread
  "reply_to_message_id": "msg_uuid",

  // Optional: prevent duplicate sends
  "idempotency_key": "unique-op-id"
}
Response 201
{
  "id": "msg_uuid",
  "inbox_id": "inb_uuid",
  "thread_id": "thr_uuid",
  "direction": "outbound",
  "from_address": "[email protected]",
  "to_address": "[email protected]",
  "subject": "Hello from my agent",
  "status": "queued",
  "created_at": "2025-04-16T10:00:00Z"
}
GET /v1/inboxes/{id}/messages List inbox messages

Query params: direction (inbound|outbound), read (true|false), limit, offset.

Request
curl "https://api.emails4agents.com/v1/inboxes/inb_uuid/messages?direction=inbound&read=false" \
  -H "X-API-Key: e4a_..."
GET /v1/messages/{id} Get a single message
POST /v1/messages/{id}/reply Reply in-thread

Sends a reply that preserves the In-Reply-To header chain, keeping email clients in the same conversation thread.

Request body
{
  "text": "Thanks for reaching out. Here's what I found...",
  "html": "<p>Thanks for reaching out. Here's what I found...</p>"
}
GET /v1/threads/{thread_id} Get full thread

Returns all messages in the thread ordered chronologically.

GET /v1/messages/search Search messages

Full-text search across message content. Query params: q (search term), inbox_id, limit.

Request
curl "https://api.emails4agents.com/v1/messages/search?q=invoice&inbox_id=inb_uuid" \
  -H "X-API-Key: e4a_..."

Webhooks

Webhooks deliver real-time event notifications to your endpoint. Register one or more URLs and specify which events to receive.

Event Trigger
message.received New inbound email stored in inbox
message.sent Outbound email accepted by SES
message.delivered SES confirms delivery
message.bounced Email bounced (hard or soft)
message.classified AI classification completed
message.failed Send failed after all retries
domain.verified DNS records verified successfully
POST /v1/webhooks Register a webhook
Request body
{
  "url": "https://your-server.com/webhooks/email",
  // null = receive events for all domains
  "domain_id": null,
  "events": [
    "message.received",
    "message.bounced"
  ]
}
Webhook payload
{
  "event": "message.received",
  "timestamp": "2025-04-16T10:23:45Z",
  "data": {
    "id": "msg_uuid",
    "inbox_id": "inb_uuid",
    "thread_id": "thr_uuid",
    "direction": "inbound",
    "from_address": "[email protected]",
    "to_address": "[email protected]",
    "subject": "Re: Your request",
    "text_body": "Thanks, but can you also...",
    "classification": "follow_up",
    "classification_confidence": 0.94
  }
}
GET /v1/webhooks List webhooks
DELETE /v1/webhooks/{id} Delete a webhook

Retry policy: Failed deliveries are retried with exponential backoff: 30s → 2m → 10m → 1h → 6h. After all retries fail, the event is logged with status: failed.

API Keys

Manage programmatic access. Keys are scoped to permissions (read, send, admin) and optionally to a single domain.

POST /v1/api-keys Create an API key

The raw key is only returned once at creation time — store it securely.

Request body
{
  "name": "production-agent",
  // null = global (all domains)
  "domain_id": null,
  // read | send | admin
  "permissions": ["read", "send"]
}
Response 201
{
  "id": "key_uuid",
  "key": "e4a_abc123...",  // only shown once
  "key_prefix": "e4a_abc123",
  "name": "production-agent",
  "domain_id": null,
  "permissions": ["read", "send"],
  "rate_limit_per_minute": 60,
  "is_active": true,
  "created_at": "2025-04-16T10:00:00Z"
}
GET /v1/api-keys List API keys

Returns all active keys. Raw key values are never returned after creation.

DELETE /v1/api-keys/{id} Revoke an API key

Agent Configuration

Configure an AI classifier on any inbox. When enabled, the agent runs via OpenRouter on every inbound message and attaches a classification label before the webhook fires.

PUT /v1/inboxes/{id}/agent Configure agent for an inbox
Request body
{
  "system_prompt": "Classify this email as one of: sales_lead, support_request, spam, follow_up, other. Respond with JSON: {"classification": "...", "confidence": 0.0-1.0}",
  // Any OpenRouter model ID
  "model": "openai/gpt-4o-mini",
  "max_iterations": 3,
  "is_enabled": true,
  // Optional knowledge base context
  "kb_sources": []
}
Response 200
{
  "id": "agc_uuid",
  "inbox_id": "inb_uuid",
  "is_enabled": true,
  "system_prompt": "...",
  "model": "openai/gpt-4o-mini",
  "max_iterations": 3,
  "kb_sources": [],
  "tools_enabled": null,
  "created_at": "2025-04-16T10:00:00Z",
  "updated_at": "2025-04-16T10:00:00Z"
}
GET /v1/inboxes/{id}/agent Get agent config
GET /v1/inboxes/{id}/agent/runs Get agent run logs

Returns classification run history including outcome, tokens used, and any errors.

Response item
{
  "id": "run_uuid",
  "message_id": "msg_uuid",
  "inbox_id": "inb_uuid",
  "outcome": "classified",
  "tokens_used": 247,
  "tools_called": [],
  "context_used": {},
  "error": null,
  "created_at": "2025-04-16T10:00:00Z"
}

MCP Server

The Emails4Agents API container ships a built-in Model Context Protocol server. Connect it to Claude Code, Cursor, or any MCP-compatible client to get native email tools.

Connect to Claude Code

~/.claude/settings.json
{
  "mcpServers": {
    "emails4agents": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://api.emails4agents.com/mcp/sse",
        "--header", "X-API-Key:${E4A_API_KEY}"
      ],
      "env": {
        "E4A_API_KEY": "e4a_your_key_here"
      }
    }
  }
}

Available tools

Tool Description
list_domains List all configured email domains
create_domain Add a new domain (auto DNS setup)
verify_domain Check DNS propagation status
list_inboxes List inboxes, optionally filter by domain
create_inbox Provision a new inbox
send_email Send an email from an inbox
read_messages Read messages from an inbox
get_thread Retrieve a full conversation thread
reply_to_message Reply in-thread preserving context
search_messages Full-text search across messages

Error Codes

Status Meaning
400 Bad Request — missing or invalid fields
401 Unauthorized — invalid or missing API key
403 Forbidden — key lacks required permission scope
404 Not Found — resource does not exist
409 Conflict — resource already exists (e.g. duplicate inbox)
422 Unprocessable — validation error in request body
429 Rate Limited — exceeded requests per minute for this key
500 Internal Server Error — something went wrong on our side
Error response shape
{
  "detail": "Domain already exists"
}