Skip to content

[ 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.

Preview
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.
Request
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"    }  }'
Response
{  "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.
Request
curl https://api.primedmail.com/v1/inboxes/inb_7Qk2mX \  -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"
Response
{  "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.

Request
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, ..."  }'
Response
{  "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.

Request
curl -X POST https://api.primedmail.com/v1/inboxes/inb_7Qk2mX/rotate \  -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"
Response
{  "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.

Request
curl -X DELETE https://api.primedmail.com/v1/inboxes/inb_7Qk2mX \  -H "Authorization: Bearer $PRIMEDMAIL_API_KEY"
Response
{  "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.
message.received
{  "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

Founder of Primedmail

Sriram Alluri

Primedmail is in early beta. Sriram reads and answers every message at sriram@primedmail.com.