Skip to content
machinemail

AgentMail compatibility

What works the same as AgentMail's /v0 API, what differs, what is missing, and what MachineMail adds.

MachineMail’s /v0 API is wire-compatible with AgentMail’s. Code written against AgentMail’s API or SDKs works against MachineMail by changing the base URL and the API key.

The rule

Wherever AgentMail’s published API defines a path, an enum value or a field name, MachineMail uses exactly that. MachineMail-only features use their own names and never change the meaning of an AgentMail field.

In practice:

  • JSON is snake_case: organization_id, api_key_id, pod_id, inbox_id, thread_id, message_id, draft_id, webhook_id, domain_id.
  • inbox_id is the email address, as in AgentMail.
  • Pagination is limit and page_token; responses carry count, limit and next_page_token.
  • client_id on create is an idempotency key: the same client_id returns the existing resource.
  • Enums match AgentMail: domain status (NOT_STARTED, PENDING, INVALID, FAILED, VERIFYING, VERIFIED), DNS record status (MISSING, INVALID, VALID) and type (TXT, CNAME, MX), inbox status (active, paused), draft send_status (scheduled, sending, failed), list direction (send, receive) and type (allow, block).
  • API key permissions use AgentMail’s names (inbox_read, message_send, …) and its object-of-booleans format.

Switching from AgentMail

  1. Create an API key in the MachineMail dashboard (or let your agent onboard itself through https://api.machinemail.dev/auth.md).

  2. Point your client at https://api.machinemail.dev. With AgentMail’s SDKs, set the base URL option to that value and the API key to your mm_live_... key.

  3. Use addresses on machinemail.dev, or add your own domain with POST /v0/domains.

Supported

AreaEndpoints
Inboxeslist, create, get, update (including pause), delete, search
Messageslist, get, send, reply, reply-all, forward, update labels, delete, raw, attachments, batch-get, batch-update, search
Threadslist, get, update labels, delete, search; at /v0/threads and /v0/inboxes/{inbox_id}/threads
Draftslist, create, get, update, delete, send; scheduled sends with send_at
Domainslist, create, get, update, delete, verify, zone-file
Webhookslist, create, get, update, delete
Listsallow and block lists at /v0/lists, /v0/pods/{pod_id}/lists and /v0/inboxes/{inbox_id}/lists
Podslist, create, get, update, delete
API keyslist, create, get, update, delete; organization, pod and inbox keys
OrganizationGET /v0/organizations
Metrics/v0/metrics/events, /v0/metrics/usage, /v0/metrics/rates
Scoped routesevery resource under /v0/pods/{pod_id}/...; webhooks, lists, metrics, events and API keys under /v0/inboxes/{inbox_id}/...

Differences

TopicAgentMailMachineMail
Error bodyAgentMail’s error shapesOne envelope on every /v0 route: {"error": {"type", "message", "param"?}}. See Errors.
Agent sign-up/v0/agent/sign-up, /v0/agent/human, /v0/agent/verifyThe auth.md protocol: POST /agent/identity, POST /agent/identity/claim, POST /oauth2/token. See Authentication.
Webhook signaturesAgentMail’s own signing schemeX-MachineMail-Signature: t=...,v1=... (HMAC-SHA256 over <t>.<body>) plus X-MachineMail-Event, -Event-Id, -Delivery-Id. See Webhook events.
Webhook bodyevent payloadSame keys at the top level, plus type: "event", event_id, event_type, timestamp, and the payload again under data.
Creating keysbody may carry pod_id / inbox_idThe route sets the scope: POST /v0/pods/{pod_id}/api-keys, POST /v0/inboxes/{inbox_id}/api-keys. pod_id and inbox_id in the body are ignored.
Status codes200 on create (per AgentMail’s spec)201 on create and on sends, 200 when a client_id matches. Deletes return {"ok": true}.
Inbox eventsGET /v0/inboxes/{inbox_id}/events is a label-event logThe same path returns MachineMail’s event log narrowed to the inbox.
LabelsSystem labels are uppercase: INBOX, SENT, UNREAD, SPAM, BLOCKED, UNAUTHENTICATED, QUARANTINE, TRASH. Other labels are free strings.
Recipientsno published per-message capAt most 50 recipients per message (deployment default) across to, cc and bcc, each address counted once; more is a 400 validation error. See Limits.
Organizationbilling and limit fieldsinbox_limit, domain_limit, billing and authentication fields are not returned. Inbox count is not a quota.

Not available

AgentMail featureStatus
Calendar (/v0/inboxes/{inbox_id}/calendar/...)Out of scope
Apps and accounts (/v0/apps, /v0/accounts, .../accounts)Out of scope
Custom webhook headers (.../webhooks/{webhook_id}/headers)Not yet; headers on create is ignored
Domain setup-linkNot planned; MachineMail offers Domain Connect instead (GET /v0/domains/{domain_id}/domain-connect)
POST /v0/inboxes/{inbox_id}/authorizeNot yet
Draft and thread attachment routes (/drafts/{draft_id}/attachments/..., /threads/{thread_id}/attachments/...)Not yet; use the message attachment route
Open tracking (track_opens, message.opened)Not available; track_opens is ignored
Fields accepted but ignoredforward_of and reply_all on draft create, attachment and label changes on draft update, quarantine_threshold on inboxes, subdomains_enabled, tracking_enabled and allow_conflicting_provider on domains

MachineMail extensions

ExtensionWhere
Trust reportstrust on every inbound message, trust_level on list items, GET /v0/inboxes/{inbox_id}/messages/{message_id}/trust. Verdicts verified, known, unknown, suspicious, quarantined, with SPF/DKIM/DMARC results, classifier scores for spam, phishing and prompt injection, link and attachment analysis, and an agent-safe trust.content.text.
QuarantineMail that looks like prompt injection or phishing gets the QUARANTINE label and the message.received.quarantined event, and is hidden from lists unless asked for.
Ephemeral inboxesttl_seconds, ephemeral, expires_at on inboxes; inbox.created and inbox.expired events.
Catch-all domainscatch_all and catch_all_ttl_seconds on domains: mail to an unknown address creates an inbox. Also inbound_enabled, feedback_enabled, nameservers, dns_provider, dns_provider_url.
Domain ConnectGET /v0/domains/{domain_id}/domain-connect returns a one-click DNS setup link where the DNS provider supports it.
Event log and streamsGET /v0/events (with after=<event_id> cursors), GET /v0/events/{event_id}, server-sent events at GET /v0/events/stream, WebSocket at /v0/ws.
Delivery inspection and replayGET /v0/webhooks/{webhook_id}/deliveries, POST .../deliveries/{delivery_id}/replay, POST /v0/webhooks/{webhook_id}/test.
Suppressions/v0/suppressions: addresses that bounced, complained or were added by hand.
ExportGET /v0/inboxes/{inbox_id}/export?format=mbox|jsonl.
Extra event typesmessage.received.quarantined, message.received.blocked, inbox.created, inbox.expired, draft.sent, webhook.test.
Extra fieldsdirection, delivery_status, received_via and pod_id on messages; organization_id on inboxes, domains and keys.
Remote MCP server/mcp, with agent-safe tools such as wait_for_message. See MCP tools.
Agent onboardingauth.md (/auth.md, /agent/identity, /oauth2/token), /v0/agent-registrations.
Raw injectionPOST /inbound/raw with the inbound_raw permission, for testing with real MIME.
ListsA reply list direction, and entry_type (email or domain) on entries.