API and MCP

MCP server and REST API

EmailPal exposes the send-to-close loop over a REST API and an MCP server (npx -y @emailpal/mcp): workspaces, domains, mailboxes, warming, campaigns, leads, replies and the pipeline. How to get a key, how one key works across your workspaces, what is covered, what is not, the webhook events, and how read-only mode works.

What you can automate

The REST API and the MCP server cover the whole loop from buying a domain to closing a deal:

  • Workspaces: list them, add one to your bill and rename one
  • Domains and DNS
  • Mailboxes, including pre-warmed inventory
  • Warming
  • The inbox: read, send, mark and delete
  • List verification and suppressions
  • Campaigns: settings, schedules, sequences (steps and A/B variants), launch, pause, resume and analytics
  • Leads: campaign leads, the lead list, lead statuses and notes
  • Replies: list and label them
  • The CRM: pipelines, opportunities and tasks
  • Webhooks and jobs
  • Notifications: your bell and your notification email settings

Base URL: https://www.emailpal.io/api/public/v1. There are 113 endpoints today. The human reference is the API documentation, and the machine-readable one is GET /api/public/v1/openapi.json.

The MCP server wraps those operations as 104 tools for Claude, Cursor, Claude Code, or any MCP client. Each tool is one call to the REST API, so it uses the same keys, scopes and rate limits. One command:

npx -y @emailpal/mcp

with EMAILPAL_API_KEY set. Tool names are prefixed with emailpal_, for example emailpal_create_campaign.

What the MCP tools cover

AreaToolsExamples
Account and balance2get_account, top_up_balance
Workspaces3list_workspaces, create_workspace, rename_workspace
Domains10search_domains, purchase_domains, verify_dns, release_domain
Pre-warmed inboxes2browse_prewarmed, lease_prewarmed
Mailboxes6list_mailboxes, create_mailboxes, export_mailboxes
Warming2get_warming, set_warming
Inbox6list_inbox, get_message, send_email
Verification and suppressions4verify_list, suppress
Jobs3list_jobs, get_job, retry_job
Notifications4list_notifications, mark_notifications_read, update_notification_preferences
Campaigns11create_campaign, campaign_preflight, launch_campaign, pause_campaign, get_campaign_analytics
Campaign leads3add_campaign_leads, list_campaign_leads, manage_campaign_leads
Sequences8add_campaign_step, update_campaign_step, add_step_variant
Leads and statuses8list_leads, create_lead, set_lead_status, add_lead_note
Pipeline5list_pipelines, create_opportunity, move_opportunity
Tasks3list_tasks, create_task, update_task
Replies2list_replies, label_reply

Working across workspaces

If you run several workspaces on one bill, for example one per client, a key created on the paying workspace can work in all of them. Name the workspace on each request:

  • REST: an X-Workspace-Id header with the workspace's id, or a workspace_id query parameter.
  • MCP: every tool takes an optional workspace_id. Leave it out to use the key's own workspace. EMAILPAL_WORKSPACE_ID sets a default for the whole server, and on the hosted server an X-Workspace-Id header on the connection does the same.

To read replies from every workspace at once, send X-Workspace-Id: all to GET /inbox or GET /replies, or pass workspace_id: "all" to list_inbox or list_replies. The list covers every workspace the key can reach, newest first, and each item has a workspace_id so you know where to act on it. GET /replies leaves out workspaces that do not have campaigns switched on. An endpoint that does not support all answers it with a 400.

Find the ids with GET /workspaces or list_workspaces. Each workspace comes back with its domain and mailbox counts and how many Unibox threads have unread mail. An admin key on the paying workspace can add a workspace with POST /workspaces (create_workspace) and start setting it up straight away by using the new id.

A key created inside a workspace that someone else pays for reaches only that workspace. Naming any other workspace returns 404 workspace_not_found. Scopes and the hourly request budget belong to the key and do not change between workspaces. See Create an API key for the details.

Notifications over the API

GET /notifications lists the bell of the person who created the key, or who approved the MCP connection, and POST /notifications/read marks notices read. Both accept X-Workspace-Id: all. GET and PUT /notification-preferences read and change that person's notification email settings: per topic in the bell and by email, muted workspaces, the daily digest and a pause. A key that was not created by a person answers 409 no_key_user. Reply notifications and email alerts

Launching a campaign from code

A typical run, whether you script it or an assistant does it:

  1. Create a draft with create_campaign. Nothing sends yet.
  2. Add leads with add_campaign_leads, from a lead list or by value.
  3. Run campaign_preflight. It is the same Ready to launch checklist as the dashboard, and can_launch is exactly what launch enforces. See The campaign launch checklist.
  4. Call launch_campaign. This starts sending real email and sent mail cannot be recalled.
  5. Read replies with list_replies and label them with label_reply. Labelling sets the lead's status, can open an opportunity and applies blocklist rules, just as it does in the Unibox.

Launching and resuming a campaign need a key with the write scope. They run the same pre-flight as the dashboard and fail with launch_blocked, listing the blockers, if something is wrong.

What is not in the API

The API does not cover everything the dashboard does. Today it has no endpoints for:

  • Deleting leads, opportunities or tasks
  • Managing lead lists or custom lead statuses. Both are read-only.
  • Searching Prospects or building intent audiences, except on the Scale plan, which includes the Prospects and intent leads API. The Prospects and intent leads API. On every plan, POST /lead-records/{id}/report reports a single lead-table record and hides it for your account
  • Bulk actions on the lead list. Pausing, resuming or removing leads works inside one campaign.
  • A separate schedule endpoint. Change a campaign's schedules with PATCH /campaigns/{id}.

The tasks list returns one page and does not take a cursor. The API documentation is the source of truth if this list ages.

How to get an API key

  1. Sign in → API keys.
  2. Create a key. Copy it once; we store a hash, not the secret.
  3. Send it as a bearer token on REST, or as EMAILPAL_API_KEY for MCP.

Step-by-step: Create an API key. Client paste configs: Connect the MCP server.

Webhooks

Register an endpoint under Webhooks or with POST /webhooks. Deliveries are signed with an EmailPal-Signature header and are at-least-once, so dedupe on the event id. There are 18 events:

EventWhen it fires
job.succeeded, job.failedAn asynchronous job finished or failed
domain.ready, domain.failedA domain finished setup or failed
mailbox.provisioned, mailbox.campaign_ready, mailbox.failedA mailbox was created, finished its 14 days of warming (informational, not a gate), or failed
list.progress, list.completedMore addresses in a list check were decided (at most one a minute per list), or the check finished
message.receivedAny non-warming message arrived in a mailbox
message.delivery_updatedThe receiving server decided what happened to a send
reply.receivedA prospect answered a campaign email. It says which campaign, step and variant, whether it was an auto-reply, and whether it stopped the sequence
lead.status_changedA lead's status changed, from the Unibox, the CRM, the API, a campaign reply or bounce, or an automation
campaign.pausedA campaign stopped sending, with the reason. auto is true when the platform paused it
account.restriction_changedThe account's sending was throttled, suspended or restored, or the domains a throttle covers changed. It names the domains and the reason
domain.restriction_changedA domain was held, restarted slowly, limited or released. It names the mailboxes, the reason and when a resting domain restarts
mailbox.restriction_changedOne mailbox's sending hold began or ended, with what caused it
domain.movedA domain and its mailboxes moved to another workspace on the same plan. Both workspaces receive it. See Move a domain to another workspace

reply.received is the event to use for a CRM sync or a notifier. campaign.paused with auto: true is the one worth alerting on. See Auto-pause on bounces.

The three *.restriction_changed events tell your own systems when sending is limited and why, the same text the dashboard shows. Each carries restricted (true when it began, false when it ended), a stable reason code and a plain-language message. A domain hold sends one domain event and one mailbox event per mailbox. The same state is readable by polling: enforcement, enforcement_scope, enforcement_reason, enforcement_since and restricted_domains on GET /account, a restriction block on GET /domains and GET /domains/{id}, and source and reason inside sending_pause on GET /mailboxes/{id}. An endpoint with no event filter receives these events automatically.

Read-only MCP

Set EMAILPAL_MCP_READ_ONLY=true and every mutating tool disappears from the list. Use this when an agent should inspect warming, DNS, campaign results or replies but must not buy domains, send mail, or launch or edit a campaign.

Even without read-only mode, the tools that put mail on the wire or cannot be undone, such as launch_campaign, resume_campaign, send_email, purchase_domains and the delete tools, are marked destructive so a client can ask before it runs them.

Rate limits

Each plan has an hourly API request budget (see the account payload and the docs). Jobs (provisioning, claims, DNS) are asynchronous: create, then poll /jobs.

FAQs

Can I search Prospects or build intent audiences over the API or MCP?

On the Scale plan, yes: it includes the Prospects and intent leads API, with fair-use limits. On Starter and Growth, intent audiences are built in the dashboard, included on every paid plan as unlimited intent leads, and the API can create leads and add them to campaigns (create_lead, add_campaign_leads) and report a lead-table record. Export a list as a CSV from the dashboard if you need the people elsewhere. The Prospects and intent leads API

Is MCP a different product?

No. Same auth, same data, same prices. MCP is how an assistant calls the API without you writing glue.

Do I need a paid plan or an add-on for campaigns and the CRM over the API?

No. The sequencer, Unibox and CRM are part of every plan, and so are the API endpoints for them. A key follows the same rules as the dashboard: sending limits come from each mailbox's own cold-email limit (never above 100 a day) and your campaign's daily limit, not from your plan. See Campaign sending limits and mailbox rotation.

Why do campaign or CRM calls return 404 not_enabled?

Campaigns, leads and the CRM can be switched off for a workspace, and the API answers the same way the pages do. If you expect them to be on, open a ticket with the request id.

Can I use this with Smartlead or Instantly?

REST and SMTP are how those tools send, and you can still use them with EmailPal mailboxes. MCP is for agents operating EmailPal itself: provisioning, warming, verifying, running campaigns and working replies. It does not drive another vendor's campaign UI.

Where is OpenAPI?

GET /api/public/v1/openapi.json and the docs site.

Need More Help?

Create an API key or open a ticket with the request id if a call returns 401/429.