[ Preview ]This is the API we are building. Endpoints, packages and limits may change before launch.
docs / overview
Primedmail API
Warmed inboxes for AI agents, for B2B SaaS and enterprise teams running outbound. One resource, the inbox, and a handful of calls around it. Your agent asks for inboxes, Primedmail registers the domains, configures DNS and warms them, and your agent sends once each one reports ready. Replies come back as webhooks.
base url https://api.primedmail.com/v1
auth Authorization: Bearer <key>
Keys are issued when your account is approved. Talk to Sriram about early beta access.
SDKs, CLI and MCP Planned
Install
Python and TypeScript SDKs, a CLI and an MCP server are planned, all thin wrappers over the same REST API. Each reads your key from PRIMEDMAIL_API_KEY.
- primedmail pip
- Python SDK.
- @primedmail/sdk npm
- TypeScript SDK.
- @primedmail/cli npm
- The primedmail command.
- @primedmail/mcp npm
- MCP server for Claude Code, Codex, Cursor and any MCP client.
Harness configs for the MCP server are on the home page.
from primedmail import Primedmailprimedmail = Primedmail() # reads PRIMEDMAIL_API_KEYinboxes = primedmail.inboxes.create( count=5, provider="google", persona={ "name": "Tomás Herrera", "company": "ledgerloop", },)# 5 inboxes on 2 new domains, state: "warming"POST/v1/inboxes
Create inboxes
Registers secondary domains for the persona, sets SPF, DKIM, DMARC and a tracking domain, creates the mailboxes and starts warmup. Returns immediately with every inbox in the warming state.
- count integer
- Inboxes to create. Spread across new domains, at most three inboxes per domain.
- provider string
- google, microsoft or mixed. Mixed splits each domain across both.
- persona object
- name and company. Used for display names and to choose lookalike domains.
- delivery string
- endpoint (default) or smtp. With smtp, credentials arrive on inbox.ready.
curl https://api.primedmail.com/v1/inboxes \ -H "Authorization: Bearer $PRIMEDMAIL_API_KEY" \ -d '{ "count": 5, "provider": "google", "persona": { "name": "Tomás Herrera", "company": "ledgerloop" } }'{ "data": [ { "id": "inb_7Qk2mX", "address": "tomas@tryledgerloop.com", "domain": "tryledgerloop.com", "provider": "google", "state": "warming", "temperature": 12, "ready_at": null } ], "domains": ["tryledgerloop.com", "getledgerloop.com"]}GET/v1/inboxes/{id}
Read an inbox
Returns the inbox with its current temperature (0 to 100), its state, and ready_at, the time it crossed into ready. An inbox can send once it is ready.
- warmingTrading mail with the warm pool. Cannot send yet.
- readyWarm. Sends up to its daily cap.
- restingPaused for the day to protect reputation. Back tomorrow.
- replacedPulled from the pool. Its replacement is in inbox.replaced.
curl https://api.primedmail.com/v1/inboxes/inb_7Qk2mX \ -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"{ "id": "inb_7Qk2mX", "address": "tomas@tryledgerloop.com", "state": "ready", "temperature": 71, "ready_at": "2026-10-29T06:00:00Z", "sent_today": 12, "daily_cap": 30}POST/v1/inboxes/{id}/send
Send a message
Sends one email from a ready inbox. Pass thread_id to reply inside an existing thread. A send from an inbox that is still warming returns 409 inbox_not_ready, and a send past the daily cap returns 429 daily_cap_reached. Neither is queued silently.
curl https://api.primedmail.com/v1/inboxes/inb_7Qk2mX/send \ -H "Authorization: Bearer $PRIMEDMAIL_API_KEY" \ -d '{ "to": "maria@example.com", "subject": "Quick question about your Q4 close", "text": "Hi Maria, ..." }'{ "id": "msg_3Fh9Lp", "thread_id": "thr_K2c8Wd", "status": "accepted"}POST/v1/inboxes/{id}/rotate
Rotate an inbox
Retires the inbox and hands back a ready replacement on the same persona. Primedmail also does this on its own when reputation slips, and tells you with inbox.replaced.
curl -X POST https://api.primedmail.com/v1/inboxes/inb_7Qk2mX/rotate \ -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"{ "retired": "inb_7Qk2mX", "replacement": { "id": "inb_Vn4tQe", "address": "tomas@ledgerloophq.com", "state": "ready", "temperature": 68 }}DELETE/v1/inboxes/{id}
Retire an inbox
Stops the inbox sending and removes it from your pool. Replies that arrive in the next 30 days are still delivered to your webhook, so no conversation is cut off mid-thread.
curl -X DELETE https://api.primedmail.com/v1/inboxes/inb_7Qk2mX \ -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"{ "id": "inb_7Qk2mX", "state": "retired"}inbox.ready · message.received · inbox.replaced
Webhooks
Three events, posted as JSON to the URL you register and signed with your webhook secret.
- inbox.ready event
- An inbox finished warmup and can send. Carries SMTP and IMAP credentials when delivery is smtp.
- message.received event
- A reply arrived. Carries the message and the whole thread, so your agent can answer in context.
- inbox.replaced event
- We pulled an inbox whose reputation slipped. Carries the retired id and its replacement.
{ "type": "message.received", "inbox_id": "inb_7Qk2mX", "thread_id": "thr_K2c8Wd", "message": { "from": "maria@example.com", "subject": "Re: Quick question about your Q4 close", "text": "Happy to talk. Thursday works." }, "thread": [ { "id": "msg_3Fh9Lp" }, { "id": "msg_9Tr2Ab" } ]}Limits
Daily cap, planned. Each inbox will start at 30 cold sends a day. Caps are raised per account after review, never per request, and the cap counts every message an inbox sends, not only first touches.
Acceptable use. Every account is reviewed before it gets an inbox. Send to people with a plausible reason to hear from you, honour every opt-out, and never disguise who is sending. Accounts that burn domains, buy scraped lists without a lawful basis or send deceptive mail are cut off. The full rule is in the terms.
Something here does not fit what your agent needs? Tell us at sriram@primedmail.com while the API can still change.