Reference

API reference

Base URL https://xmails.si/api/v1. Bodies are JSON; GET and DELETE take their parameters in the query string. Each endpoint is also the MCP tool named under it. The same reference as OpenAPI 3.1.

Overview

Subscribers, email results and sends per hour, as on the dashboard's first page.

Get the overview

GET/api/v1/overview

The dashboard's overview for one newsletter: subscribers each day of the last 30 days, email results of the last 30 days against the 30 before, emails sent per hour today and yesterday, and the plan's usage this month, which the account's newsletters share.

MCP toolget_overviewKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

timeZone

query · string

IANA time zone for days and hours, e.g. Europe/Paris. Default: UTC.

Request
curl "https://xmails.si/api/v1/overview?timeZone=Europe%2FParis" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Analytics

Date-filtered account analytics, engagement, audience, campaigns and delivery health.

Get newsletter analytics

GET/api/v1/analytics

Reports account-owned email performance, audience, campaigns, inbox providers, recorded links and operational inventory. Dates are inclusive UTC calendar days with an equal previous-period comparison. Email outcomes belong to their send cohort, as observed now; audience and inventory are current snapshots. Test emails are excluded by default.

MCP toolget_analyticsKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

Only this newsletter's: its ID or slug. Default: every newsletter.

days

query · integer

Calendar days ending today, 30 by default; ignored when both start and end are supplied

start

query · string

Inclusive UTC start date, YYYY-MM-DD; provide end too, at most 366 days

end

query · string

Inclusive UTC end date, YYYY-MM-DD, no later than today

includeTests

query · boolean

Include test emails in message metrics; false by default

Request
curl "https://xmails.si/api/v1/analytics?days=30" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Newsletters

Sender, postal address, welcome and confirmation emails, list cleanup and archive.

List newsletters

GET/api/v1/newsletters

Lists the account's newsletters, 3 at most, first created first, with their settings and active contacts. Actions that take a newsletter use the first one when it's left out.

MCP toollist_newslettersKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/newsletters" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get a newsletter

GET/api/v1/newsletters/{id}

Gets a newsletter's settings: sender, postal address, welcome and confirmation emails, list cleanup and archive.

MCP toolget_newsletterKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The newsletter's ID or slug

Request
curl "https://xmails.si/api/v1/newsletters/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Create a newsletter

POST/api/v1/newsletters

Creates a newsletter. An account has up to 3, sharing its plan's emails and subscribers; one more answers conflict. Without a fromEmail it sends from the shared address hello@<slug>.<shared domain>, which XMails sets up in a few minutes. List cleanup is on unless cleanup.enabled is false. Without a postalAddress, its emails print the server's default if it has one: XMails’ address on XMails Cloud.

MCP toolcreate_newsletterKeyFull access
Parameter
namerequired

body · string

The newsletter's name, shown in emails and on the archive

slug

body · string

Lowercase letters, digits and dashes. Default: made from the name, numbered when another newsletter has it.

imageUrl

body · string

Square logo, 128×128 or larger: an https:// link

fromName

body · string

Name in the From field

fromEmail

body · string

The shared address (hello@<slug>.<shared domain>, set automatically) or an address on a domain added to this account

replyTo

body · string

Where replies go. Empty: replies to the shared address go to the account owner.

postalAddress

body · string

Printed in the footer of every email. Never set, it's the server's default (XMails’ address on XMails Cloud, none on a self-hosted server); saved empty, there's none and sending waits for one.

archiveEnabled

body · boolean

A public page for each sent issue, with a signup form. On for new newsletters: the website goes live after the first issue.

description

body · string

One sentence under the name on the archive, 200 characters at most

author

body · object

The archive's author page; the author's name is fromName

author.bio

body · string

Under the author's name on the archive, 160 characters at most

author.imageUrl

body · string

Author photo: an https:// link. The newsletter image otherwise.

socialLinks

body · string[]

https:// links shown on the archive, 8 at most

requireConfirmation

body · boolean

Confirmed opt-in: new signups get an email with a button and only join once they click it. On for new newsletters.

cleanup

body · object

List cleanup at each send: contacts who ignored several issues get a last-chance email instead, and become dormant if they don't answer

cleanup.enabled

body · boolean

On for new newsletters

cleanup.issues

body · number | null

Ignored issues in a row before the last-chance email, 2 to 100. Default 6.

cleanup.days

body · number | null

Days without an open, click or signup, 30 to 3650. Default 180.

welcome

body · object

Email sent to each new subscriber. Not sent while signups need confirming.

welcome.enabled

body · boolean

welcome.subject

body · string

welcome.previewText

body · string

welcome.markdown

body · string

Markdown

confirmation

body · object

The confirmation email for confirmed opt-in. Sent back unchanged, the built-in one stays built-in and follows the name and description.

confirmation.subject

body · string

confirmation.previewText

body · string

confirmation.markdown

body · string

Markdown that keeps the button: an HTML link like <a href="{{confirm_url}}">Confirm</a>

Request
curl -X POST "https://xmails.si/api/v1/newsletters" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Field notes","postalAddress":"Field Notes Ltd, 1 Main St, Paris, France"}'

Update a newsletter

PATCH/api/v1/newsletters/{id}

Changes a newsletter's settings. Send only the fields to change; nested groups (welcome, confirmation, cleanup, author) keep the fields you leave out. An account changes slugs 3 times a day at most: one more answers rate_limited.

MCP toolupdate_newsletterKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The newsletter's ID or slug

name

body · string

The newsletter's name, shown in emails and on the archive

slug

body · string

Lowercase letters, digits and dashes, not a name XMails keeps like www, api or mail. The shared from address (hello@<slug>.<shared domain>) and the archive subdomain follow it.

imageUrl

body · string

Square logo, 128×128 or larger: an https:// link

fromName

body · string

Name in the From field

fromEmail

body · string

The shared address (hello@<slug>.<shared domain>, set automatically) or an address on a domain added to this account

replyTo

body · string

Where replies go. Empty: replies to the shared address go to the account owner.

postalAddress

body · string

Printed in the footer of every email. Never set, it's the server's default (XMails’ address on XMails Cloud, none on a self-hosted server); saved empty, there's none and sending waits for one.

archiveEnabled

body · boolean

A public page for each sent issue, with a signup form. On for new newsletters: the website goes live after the first issue.

description

body · string

One sentence under the name on the archive, 200 characters at most

author

body · object

The archive's author page; the author's name is fromName

author.bio

body · string

Under the author's name on the archive, 160 characters at most

author.imageUrl

body · string

Author photo: an https:// link. The newsletter image otherwise.

socialLinks

body · string[]

https:// links shown on the archive, 8 at most

requireConfirmation

body · boolean

Confirmed opt-in: new signups get an email with a button and only join once they click it. On for new newsletters.

cleanup

body · object

List cleanup at each send: contacts who ignored several issues get a last-chance email instead, and become dormant if they don't answer

cleanup.enabled

body · boolean

On for new newsletters

cleanup.issues

body · number | null

Ignored issues in a row before the last-chance email, 2 to 100. Default 6.

cleanup.days

body · number | null

Days without an open, click or signup, 30 to 3650. Default 180.

welcome

body · object

Email sent to each new subscriber. Not sent while signups need confirming.

welcome.enabled

body · boolean

welcome.subject

body · string

welcome.previewText

body · string

welcome.markdown

body · string

Markdown

confirmation

body · object

The confirmation email for confirmed opt-in. Sent back unchanged, the built-in one stays built-in and follows the name and description.

confirmation.subject

body · string

confirmation.previewText

body · string

confirmation.markdown

body · string

Markdown that keeps the button: an HTML link like <a href="{{confirm_url}}">Confirm</a>

Request
curl -X PATCH "https://xmails.si/api/v1/newsletters/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"replyTo":"jane@example.com","requireConfirmation":true}'

Check a slug

GET/api/v1/newsletters/slugs/{slug}

Says whether a newsletter can take a slug: available, or taken by another newsletter, reserved by XMails or invalid, with the message saving it would answer. Checking doesn't count toward the 3 slug changes a day.

MCP toolcheck_newsletter_slugKeyFull accessRead-onlySafe to repeat
Parameter
slugrequired

path · string

The slug to check

id

query · string

The newsletter that would take it, by ID or slug: its own slug is available to it

Request
curl "https://xmails.si/api/v1/newsletters/slugs/6650f1c2e9b1d4a012345678?slug=field-notes" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Send a test of the welcome email

POST/api/v1/newsletters/{id}/welcome-test

Sends the saved welcome email to the account owner's address, switched on or not. It counts toward the plan's emails.

MCP toolsend_welcome_test_emailKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The newsletter's ID or slug

Request
curl -X POST "https://xmails.si/api/v1/newsletters/6650f1c2e9b1d4a012345678/welcome-test" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Catalog

Account-owned products and services, with reusable facts, prices, links and images.

Get a product or service

GET/api/v1/catalog/{id}

Returns an account-owned product or service, including archived items, with its editable catalog details.

MCP toolget_catalog_itemKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The catalog item's ID

Request
curl "https://xmails.si/api/v1/catalog/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Delete a product or service

DELETE/api/v1/catalog/{id}

Permanently deletes an account-owned product or service. Existing template snapshots, campaign drafts and image library assets are preserved. This cannot be undone.

MCP tooldelete_catalog_itemKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The catalog item's ID

Request
curl -X DELETE "https://xmails.si/api/v1/catalog/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

List products and services

GET/api/v1/catalog

Lists this account's products and services, newest first. Archived items are hidden unless requested. Pass nextCursor back as cursor for the next page.

MCP toollist_catalog_itemsKeyFull accessRead-onlySafe to repeat
Parameter
status

query · "active" | "archived"

Item status, active by default

limit

query · integer

Items per page, 50 by default

cursor

query · string

nextCursor from the previous page

Request
curl "https://xmails.si/api/v1/catalog" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Add a product or service

POST/api/v1/catalog

Adds a product or service to this account's catalog. Its facts, price, links and pictures can be reused in newsletter templates.

MCP toolcreate_catalog_itemKeyFull access
Parameter
kindrequired

body · "product" | "service"

A product or a service

namerequired

body · string

The product or service name

descriptionrequired

body · string

Facts and benefits to use in templates

price

body · string

Display price including currency and billing period, e.g. USD 49/month

url

body · string

The product, service, or booking page

imageUrl

body · string

An existing product image's public HTTPS URL

Request
curl -X POST "https://xmails.si/api/v1/catalog" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"service","name":"Design consultation","description":"A one-hour consultation to plan your next project.","price":"USD 99","url":"https://example.com/book"}'

Update a product or service

PATCH/api/v1/catalog/{id}

Updates an account-owned catalog item or archives it. Templates keep a snapshot so changing an item never rewrites an existing template or campaign.

MCP toolupdate_catalog_itemKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The catalog item's ID

kind

body · "product" | "service"

A product or a service

name

body · string

The product or service name

description

body · string

Facts and benefits to use in templates

price

body · string

Display price including currency and billing period, e.g. USD 49/month

url

body · string

The product, service, or booking page

imageUrl

body · string

An existing product image's public HTTPS URL

status

body · "active" | "archived"

Archive or restore an item

Request
curl -X PATCH "https://xmails.si/api/v1/catalog/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Templates

DIY email designs, catalog-grounded AI copy and consistent Nano Banana artwork.

Delete a template

DELETE/api/v1/templates/{id}

Permanently deletes an account-owned template. An active generation worker must finish or its lease expire first. Queued work skips deleted templates. Existing campaigns, guide revisions and image library assets are preserved. This cannot be undone.

MCP tooldelete_templateKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The template's ID

Request
curl -X DELETE "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get generation guide

GET/api/v1/generation-guide

Returns this account's current Markdown generation guide and its last ten revisions. Recommendations reflect human feedback, not a measured quality score.

MCP toolget_generation_guideKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/generation-guide" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Recommend template improvements

POST/api/v1/templates/{id}/feedback

Saves one review of a ready AI template and rebuilds the account's versioned Markdown guide from its latest twenty reviews. Repeat the same review to recover an interrupted guide update. Existing templates stay unchanged; recommendations guide future generations.

MCP toolsubmit_template_feedbackKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The template's ID

targetrequired

body · "text" | "image" | "both"

Whether the recommendation concerns copy, artwork or both

ratingrequired

body · "good" | "needs_work"

Preserve a successful approach or request an improvement

recommendationrequired

body · string

Concrete preferences to preserve or change in future generations

Request
curl -X POST "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678/feedback" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target":"…","rating":"…","recommendation":"…"}'

Generate an improved version

POST/api/v1/templates/{id}/improve

Creates a new AI template using the current account guide after reviewing a ready template. Keeps the original, links the new version to its parent, and snapshots the guide for reproducible retries. Uses the original brief and current catalog facts; nothing is sent.

MCP toolimprove_templateKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The template's ID

Request
curl -X POST "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678/improve" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Create a DIY template

POST/api/v1/templates

Creates an editable drag-and-drop email design with validated blocks and brand settings. Requires no catalog or AI service. HTML is generated on the server; nothing is sent.

MCP toolcreate_templateKeyFull access
Parameter
namerequired

body · string

A name for the reusable template

designrequired

body · object

Version 1 email design with brand settings and up to 80 editable blocks

design.versionrequired

body · number

design.themerequired

body · object

design.blocksrequired

body · object[]

Request
curl -X POST "https://xmails.si/api/v1/templates" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…","design":"…"}'

List templates

GET/api/v1/templates

Lists this account's reusable templates and AI generation progress, newest first. A ready template can become a campaign draft using create_campaign.

MCP toollist_templatesKeyFull accessRead-onlySafe to repeat
Parameter
limit

query · integer

Templates per page, 50 by default

cursor

query · string

nextCursor from the previous page

Request
curl "https://xmails.si/api/v1/templates" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get a template

GET/api/v1/templates/{id}

Returns an account-owned template, its editable email content, catalog snapshot and generation status. Poll this action while AI generation runs.

MCP toolget_templateKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The template's ID

Request
curl "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Generate an AI template

POST/api/v1/templates/generate

Queues an AI template using account-owned catalog items and a brief. Gemini writes editable copy; optional Nano Banana artwork is stored in the account's image library. Returns immediately; poll get_template. Nothing is sent.

MCP toolgenerate_templateKeyFull accessReaches outside XMails
Parameter
namerequired

body · string

A name for the reusable template

itemIdsrequired

body · string[]

One to twelve active catalog item IDs from this account, in display order

style

body · "editorial" | "minimal" | "bold"

An editorial, minimal, or bold layout

briefrequired

body · string

Audience, goal, tone, language, and creative direction

generateImage

body · boolean

Generate a Nano Banana hero image; false by default

Request
curl -X POST "https://xmails.si/api/v1/templates/generate" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…","itemIds":"…","brief":"…"}'

Retry template generation

POST/api/v1/templates/{id}/retry

Retries a failed AI template or a worker whose six-minute lease expired. Reuses completed copy and artwork stages rather than regenerating them. Nothing is sent.

MCP toolretry_template_generationKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The template's ID

Request
curl -X POST "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678/retry" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Update a template

PATCH/api/v1/templates/{id}

Saves a ready template's name, subject, preview text or content. DIY templates use structured design blocks and server-rendered HTML; other templates use sanitized rich content. Existing campaign drafts are independent.

MCP toolupdate_templateKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The template's ID

name

body · string

A name for the reusable template

subject

body · string

The email subject

previewText

body · string

Inbox preview text

design

body · object

The editable design for a DIY template; cannot be combined with content

design.versionrequired

body · number

design.themerequired

body · object

design.blocksrequired

body · object[]

content

body · string

Editable rich HTML content for templates without a structured design

Request
curl -X PATCH "https://xmails.si/api/v1/templates/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Campaigns

Drafts, test emails, scheduling, sending, sending in steps and reports.

List campaigns

GET/api/v1/campaigns

Lists campaigns, newest activity first: sent issues by send date, scheduled ones by send time, drafts by last edit. Content is left out; get_campaign has it.

MCP toollist_campaignsKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

Only this newsletter's: its ID or slug. Default: every newsletter.

status

query · "draft" | "scheduled" | "sending" | "paused" | "sent"

Only campaigns with this status

limit

query · integer

How many, 50 by default, 200 at most

Request
curl "https://xmails.si/api/v1/campaigns?status=sent&limit=10" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get a campaign

GET/api/v1/campaigns/{id}

Gets a campaign with its content, stats and, for drafts, what would block sending it now.

MCP toolget_campaignKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The campaign's ID

Request
curl "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get a campaign's report

GET/api/v1/campaigns/{id}/report

Delivery, open, click, bounce, complaint and unsubscribe rates of a sent campaign, its list cleanup emails, results by inbox provider, and how many contacts a capped send hasn't reached yet.

MCP toolget_campaign_reportKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The campaign's ID

Request
curl "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/report" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Create a draft campaign

POST/api/v1/campaigns

Creates a draft. Nothing is sent: review it in the dashboard or with get_campaign, then send_test_email, schedule_campaign or send_campaign.

MCP toolcreate_campaignKeyFull access
Parameter
newsletter

body · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

template

body · string

A ready template ID from this account; its content, subject and preview text become an independent draft

subject

body · string

Subject line, 200 characters at most

previewText

body · string

Text inbox apps show after the subject, 300 characters at most

format

body · "markdown" | "rich" | "html"

markdown (the default when content is given), rich or html, as in update_campaign

content

body · string

The body in that format, 500 KB at most

archiveSlug

body · string

The issue's page path once sent. Default: made from the subject; a taken slug gets a number.

Request
curl -X POST "https://xmails.si/api/v1/campaigns" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"This week","previewText":"Three links worth your time","content":"# This week\n\nThree links worth your time."}'

Update a draft campaign

PATCH/api/v1/campaigns/{id}

Changes a draft or scheduled campaign's subject, preview text or content. Send only the fields to change; format goes with content. Sent campaigns can't change.

MCP toolupdate_campaignKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The campaign's ID

subject

body · string

Subject line, 200 characters at most

previewText

body · string

Text inbox apps show after the subject, 300 characters at most

format

body · "markdown" | "rich" | "html"

With content: the format it's in. Default: the campaign's current format.

content

body · string

The body in that format, 500 KB at most

Request
curl -X PATCH "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subject":"This week, and one more link"}'

Delete a campaign

DELETE/api/v1/campaigns/{id}

Deletes a draft, scheduled, paused or sent campaign from lists and the public archive. Pause actively sending campaigns first. Delivery records remain for analytics, billing and suppression; sent emails cannot be recalled.

MCP tooldelete_campaignKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X DELETE "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Duplicate a campaign

POST/api/v1/campaigns/{id}/duplicate

Copies a campaign's subject, preview text and content into a new draft.

MCP toolduplicate_campaignKeyFull access
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/duplicate" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Send a test email

POST/api/v1/campaigns/{id}/test

Sends the campaign as saved to the account owner's address, subject prefixed with [Test]. Nobody else gets it. It counts toward the plan's emails.

MCP toolsend_test_emailKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/test" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Schedule a campaign

POST/api/v1/campaigns/{id}/schedule

Schedules a draft to send by itself at a time within a year. It goes out without asking again, unless unschedule_campaign runs first. Sending can't be undone: emails can't be recalled once they go out. Ask the user to confirm first. Plan limits and pre-send checks run now and again when it goes out. XMails Cloud paces a send by the volume its account has proven: its largest campaign of the last 60 days whose bounces and complaints stayed under the pause level, counted a day after it went out. A send, with what the account's other sends still have to send or sent in the last 24 hours, goes at full speed up to 200 emails, or that volume times 2 on the first day of the account's 30-day warm-up, rising to 5 by its last day and after it. A bigger send goes out over 4 hours plus 4 for each time it doubles that, 72 at most (spreadHours, sendingUntil); a resume keeps the pace, each step of send_campaign_to_more gets its own. Contacts never mailed before go in steps: a slice first, the rest 3 hours after it if the slice's bounces and complaints stay under the pause level. Past 2.00% hard bounces (at least 5) or 0.08% complaints (at least 2), the campaign pauses with pauseCode high_rates, or first_send_slice for a slice, and resume_campaign sends the rest. Past 5.00% (at least 10) or 0.30% (at least 3), the account is blocked.

MCP toolschedule_campaignKeyFull accessCan't be undoneSafe to repeatReaches outside XMails
Parameter
idrequired

path · string

The campaign's ID

scheduledAtrequired

body · string

ISO 8601 date and time, e.g. 2026-10-20T09:00:00Z, at least a minute ahead

audienceLimit

body · integer

Send to this many contacts at most, the most engaged first. The rest can follow with send_campaign_to_more.

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/schedule" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduledAt":"2026-10-20T09:00:00Z"}'

Cancel a scheduled send

POST/api/v1/campaigns/{id}/unschedule

Turns a scheduled campaign back into a draft, so it doesn't go out.

MCP toolunschedule_campaignKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/unschedule" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Send a campaign now

POST/api/v1/campaigns/{id}/send

Sends a draft or scheduled campaign now to the newsletter's active contacts, most engaged first. Sending can't be undone: emails can't be recalled once they go out. Ask the user to confirm first. A campaign that is already sending or sent answers conflict, so a retry never sends twice. Plan limits, the from address, the postal address and the email size are checked first. XMails Cloud paces a send by the volume its account has proven: its largest campaign of the last 60 days whose bounces and complaints stayed under the pause level, counted a day after it went out. A send, with what the account's other sends still have to send or sent in the last 24 hours, goes at full speed up to 200 emails, or that volume times 2 on the first day of the account's 30-day warm-up, rising to 5 by its last day and after it. A bigger send goes out over 4 hours plus 4 for each time it doubles that, 72 at most (spreadHours, sendingUntil); a resume keeps the pace, each step of send_campaign_to_more gets its own. Contacts never mailed before go in steps: a slice first, the rest 3 hours after it if the slice's bounces and complaints stay under the pause level. Past 2.00% hard bounces (at least 5) or 0.08% complaints (at least 2), the campaign pauses with pauseCode high_rates, or first_send_slice for a slice, and resume_campaign sends the rest. Past 5.00% (at least 10) or 0.30% (at least 3), the account is blocked.

MCP toolsend_campaignKeyFull accessCan't be undoneReaches outside XMails
Parameter
idrequired

path · string

The campaign's ID

audienceLimit

body · integer

Send to this many contacts at most, the most engaged first. The rest can follow with send_campaign_to_more.

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/send" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Send a campaign to more contacts

POST/api/v1/campaigns/{id}/send-more

Sends a sent campaign to contacts who haven't received it yet, the next most engaged first: a send in steps. Sending can't be undone: emails can't be recalled once they go out. Ask the user to confirm first. Each call starts a new step, so check get_campaign_report before calling it again; while a step is still sending it answers conflict. XMails Cloud paces a send by the volume its account has proven: its largest campaign of the last 60 days whose bounces and complaints stayed under the pause level, counted a day after it went out. A send, with what the account's other sends still have to send or sent in the last 24 hours, goes at full speed up to 200 emails, or that volume times 2 on the first day of the account's 30-day warm-up, rising to 5 by its last day and after it. A bigger send goes out over 4 hours plus 4 for each time it doubles that, 72 at most (spreadHours, sendingUntil); a resume keeps the pace, each step of send_campaign_to_more gets its own. Contacts never mailed before go in steps: a slice first, the rest 3 hours after it if the slice's bounces and complaints stay under the pause level. Past 2.00% hard bounces (at least 5) or 0.08% complaints (at least 2), the campaign pauses with pauseCode high_rates, or first_send_slice for a slice, and resume_campaign sends the rest. Past 5.00% (at least 10) or 0.30% (at least 3), the account is blocked.

MCP toolsend_campaign_to_moreKeyFull accessCan't be undoneReaches outside XMails
Parameter
idrequired

path · string

The campaign's ID

additional

body · integer

How many more contacts. Default: everyone who hasn't received it.

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/send-more" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"additional":2000}'

Pause a campaign

POST/api/v1/campaigns/{id}/pause

Stops a campaign that is sending. Emails already sent stay sent; the rest wait until resume_campaign.

MCP toolpause_campaignKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/pause" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Resume a paused campaign

POST/api/v1/campaigns/{id}/resume

Sends the rest of a paused campaign. Sending can't be undone: emails can't be recalled once they go out. Ask the user to confirm first. The plan limits and the account's state are checked again first. Resumed after a high_rates or first_send_slice pause, only the block level stops it again.

MCP toolresume_campaignKeyFull accessCan't be undoneReaches outside XMails
Parameter
idrequired

path · string

The campaign's ID

Request
curl -X POST "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/resume" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Update a campaign's archive page

PATCH/api/v1/campaigns/{id}/archive

Changes the path of a campaign's archive page (/p/<slug>), or pins a sent issue to the top of the archive. Works on sent campaigns too.

MCP toolupdate_campaign_archiveKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The campaign's ID

slug

body · string

Lowercase letters, digits and dashes. Empty removes it from a draft.

pinned

body · boolean

Pinned issues lead the archive

Request
curl -X PATCH "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/archive" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pinned":true}'

Preview the list cleanup of a send

GET/api/v1/campaigns/{id}/cleanup-preview

Counts what the newsletter's list cleanup would do if the campaign went out now: issues sent, last-chance emails instead, contacts still waiting to answer one, and contacts made dormant. Reads the whole list, so it can take a few seconds.

MCP toolpreview_campaign_cleanupKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The campaign's ID

audienceLimit

query · integer

Count for a send capped at this many contacts

includeRanks

query · boolean

Also return, for each cold contact, how many issue recipients come before it, to recount any limit without asking again

Request
curl "https://xmails.si/api/v1/campaigns/6650f1c2e9b1d4a012345678/cleanup-preview" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Contacts

Contact groups, search, signups, imports, status changes, deletes and filtered exports.

List contacts

GET/api/v1/contacts

Lists contacts, newest signups first, 50 a page. Filter by newsletter, contact group, status or the start of the email address; pass nextCursor back as cursor for the next page. counts has every status for the same filters.

MCP toollist_contactsKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

Only this newsletter's: its ID or slug. Default: every newsletter.

group

query · string

An owned contact group ID or everyone; Everyone requires newsletter

status

query · "active" | "pending" | "unsubscribed" | "bounced" | "complained" | "dormant"

Only contacts with this status

search

query · string

Contacts whose email starts with this

limit

query · integer

Contacts per page, 50 by default, 100 at most

cursor

query · string

nextCursor from the previous page

Request
curl "https://xmails.si/api/v1/contacts?status=active&search=jane" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get a contact

GET/api/v1/contacts/{id}

Gets one contact by ID or email address, with its status, dates and engagement.

MCP toolget_contactKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The contact's ID or email address

newsletter

query · string

The newsletter's ID or slug, needed for an email address that is a contact of several newsletters

Request
curl "https://xmails.si/api/v1/contacts/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Add a contact

POST/api/v1/contacts

Signs someone up, like the archive's form: they get the welcome email, or the confirmation email when the newsletter asks new subscribers to confirm. Signing up again keeps the contact as it is unless resubscribe is true. Works with signups only keys, for website forms. Signups and confirmation emails keep coming in over the plan's limits; welcome emails count toward the month's emails and are skipped once they're used up, never sent later (get_billing's usage.welcomeEmailsPaused). A misspelled domain (gmial.com) answers validation_failed with the address it was likely meant to be; spam trap addresses, domains that can't receive email, and addresses XMails knows can't receive email (they hard bounced or hit a spam trap, from any sender on XMails) answer validation_failed too.

MCP tooladd_contactKeyFull access or signups onlyReaches outside XMails
Parameter
newsletter

body · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

emailrequired

body · string

The subscriber's email address

name

body · string

The contact's display name

source

body · string

Where they signed up, e.g. website. Default: api.

resubscribe

body · boolean

Bring back a contact who unsubscribed or went dormant. Bounced and complained addresses never come back, nor does a contact deleted after it unsubscribed.

ip

body · string

The visitor's IP address: one visitor gets 5 signups in 10 minutes

Request
curl -X POST "https://xmails.si/api/v1/contacts" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","source":"website"}'

Edit contact details

PATCH/api/v1/contacts/{id}/profile

Updates an account-owned contact's name, source and private notes. Email identifies the subscription and remains unchanged, as do consent, engagement, group membership and suppression status. No email is sent.

MCP toolupdate_contactKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The contact's ID or email address

newsletter

body · string

The newsletter's ID or slug, needed for an email address that is a contact of several newsletters

name

body · string

The contact's display name; empty clears it

source

body · string

Where the contact came from; empty clears it

notes

body · string

Private notes for this contact; empty clears them

Request
curl -X PATCH "https://xmails.si/api/v1/contacts/6650f1c2e9b1d4a012345678/profile" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Unsubscribe or reactivate a contact

PATCH/api/v1/contacts/{id}

unsubscribed stops all emails to the contact, for good: only the person signing up again brings them back. active brings back a dormant contact; unsubscribes, bounces and complaints are final.

MCP toolupdate_contact_statusKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The contact's ID or email address

newsletter

body · string

The newsletter's ID or slug, needed for an email address that is a contact of several newsletters

statusrequired

body · "active" | "unsubscribed"

active (dormant contacts only) or unsubscribed

Request
curl -X PATCH "https://xmails.si/api/v1/contacts/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"unsubscribed"}'

Delete a contact

DELETE/api/v1/contacts/{id}

Deletes a contact from its newsletter, with its dates and engagement. It can't be undone. For a contact who unsubscribed, bounced or complained, XMails keeps a hash of the address so the newsletter never emails it again: import_contacts leaves it out, and add_contact or a signup form adds it back with that status. Any other contact can be added again like a new one.

MCP tooldelete_contactKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The contact's ID or email address

newsletter

query · string

The newsletter's ID or slug, needed for an email address that is a contact of several newsletters

Request
curl -X DELETE "https://xmails.si/api/v1/contacts/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Import contacts

POST/api/v1/contacts/import

Adds up to 1000 contacts per call, with the same checks as the dashboard's CSV import: invalid, misspelled (gmial.com…), spam trap, role (info@, support@…), throwaway, duplicate and suppressed addresses, undeliverable ones (XMails knows they can't receive email: they hard bounced or hit a spam trap, from any sender on XMails), and addresses on domains that can't receive email, are left out and counted. consent must be true: "These people agreed to receive my emails". Existing contacts keep their status unless a row gives a stricter one (unsubscribed, bounced, complained), which is final. No welcome emails go out. For more rows, send the next chunk with the importId of the first.

MCP toolimport_contactsKeyFull accessCan't be undoneSafe to repeat
Parameter
newsletter

body · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

consentrequired

body · boolean

Must be true: These people agreed to receive my emails. Bought or scraped lists aren't allowed.

contactsrequired

body · object[]

The rows, 1000 at most

contacts[].emailrequired

body · string

Invalid addresses are left out and counted

contacts[].status

body · "active" | "dormant" | "unsubscribed" | "bounced" | "complained"

active (default), dormant, unsubscribed, bounced or complained

contacts[].subscribedAt

body · string

When they signed up, ISO 8601

contacts[].emailsReceived

body · number

Emails they got on the previous platform

contacts[].openRate

body · number

0 to 1, from the previous platform: sends reach the most engaged first

contacts[].clickRate

body · number

0 to 1, from the previous platform

importId

body · string

The importId of the first chunk, to add rows to the same import

duplicates

body · integer

Duplicates you removed before sending, counted in the import's report

Request
curl -X POST "https://xmails.si/api/v1/contacts/import" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"consent":true,"contacts":[{"email":"jane@example.com","subscribedAt":"2025-03-01T00:00:00Z"},{"email":"sam@example.com","status":"unsubscribed"}]}'

Export contacts

GET/api/v1/contacts/export

Makes a CSV download link for the contacts matching the filters, valid for an hour, no API key needed to open it. The columns go back in through the import as they are.

MCP toolexport_contactsKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

Only this newsletter's: its ID or slug. Default: every newsletter.

group

query · string

An owned contact group ID or everyone; Everyone requires newsletter

status

query · "active" | "pending" | "unsubscribed" | "bounced" | "complained" | "dormant"

Only contacts with this status

search

query · string

Contacts whose email starts with this

Request
curl "https://xmails.si/api/v1/contacts/export?status=active" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

List contact groups

GET/api/v1/contact-groups

Lists this newsletter's groups and counts. Ensures its automatic Everyone group exists; Everyone includes new contacts automatically, regardless of subscription status.

MCP toollist_contact_groupsKeyFull accessRead-onlySafe to repeat
Parameter
newsletter

query · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

Request
curl "https://xmails.si/api/v1/contact-groups" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Create a contact group

POST/api/v1/contact-groups

Creates a custom group inside an owned newsletter. Everyone is reserved. Contacts may belong to multiple custom groups; group membership never changes subscription or suppression status.

MCP toolcreate_contact_groupKeyFull access
Parameter
newsletter

body · string

The newsletter's ID or slug. Default: the account's first newsletter, the one it has had longest.

namerequired

body · string

A unique group name within this newsletter, up to 80 characters

Request
curl -X POST "https://xmails.si/api/v1/contact-groups" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…"}'

Rename a contact group

PATCH/api/v1/contact-groups/{id}

Renames an owned custom group. Everyone cannot be renamed.

MCP toolrename_contact_groupKeyFull access
Parameter
idrequired

path · string

An account-owned contact group ID

namerequired

body · string

A unique group name within this newsletter, up to 80 characters

Request
curl -X PATCH "https://xmails.si/api/v1/contact-groups/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…"}'

Delete a contact group

DELETE/api/v1/contact-groups/{id}

Deletes a custom group and its memberships. Contacts and their subscription/suppression states are kept. Everyone cannot be deleted.

MCP tooldelete_contact_groupKeyFull accessCan't be undone
Parameter
idrequired

path · string

An account-owned contact group ID

Request
curl -X DELETE "https://xmails.si/api/v1/contact-groups/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Update contact group members

PATCH/api/v1/contact-groups/{id}/members

Adds or removes up to 200 contact IDs in an owned custom group. Every contact must belong to its newsletter and account. Everyone is automatic; membership never resubscribes anyone.

MCP toolupdate_contact_group_membersKeyFull access
Parameter
idrequired

path · string

An account-owned contact group ID

contactIdsrequired

body · string[]

One to 200 contact IDs from the group’s own newsletter

operationrequired

body · "add" | "remove"

Add contacts to this group or remove their membership

Request
curl -X PATCH "https://xmails.si/api/v1/contact-groups/6650f1c2e9b1d4a012345678/members" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contactIds":"…","operation":"…"}'

Domains

Own sending domains with their DNS records, and the shared address.

List domains

GET/api/v1/domains

Lists the account's own sending domains with their DNS records and status as last checked, and each newsletter's shared address (hello@<slug>.<shared domain>), which works with no setup.

MCP toollist_domainsKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/domains" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Add a domain

POST/api/v1/domains

Adds a domain to send from, in the account's own tenant at the email provider: emails are signed with DKIM and bounces return to a subdomain of it (rp.<domain> on PostShiba, bounce.<domain> on Amazon SES). The answer lists the DNS records to add; check_domain reads them once they're in. Newsletters can send from it once it's verified.

MCP tooladd_domainKeyFull accessReaches outside XMails
Parameter
domainrequired

body · string

e.g. example.com. An address or a link works too: jane@example.com and https://www.example.com/about both add example.com.

archiveHost

body · string

Used when the domain's setup lists an archive step: the subdomain for the archive, tracked links and unsubscribe links. Default: news.<domain>.

Request
curl -X POST "https://xmails.si/api/v1/domains" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain":"example.com"}'

Check a domain's DNS records

POST/api/v1/domains/{id}/check

Asks the email provider and DNS again whether the domain's records are in, and looks up its DMARC record or its parent domain's. On PostShiba, a check within a minute of the last one answers what that one found. When its setup lists an archive step, the newsletter sending from the domain moves its archive and links to that subdomain once it points at XMails.

MCP toolcheck_domainKeyFull accessSafe to repeatReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

Request
curl -X POST "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/check" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Remove a domain

DELETE/api/v1/domains/{id}

Removes a domain from the email provider, and its archive subdomain from XMails when its setup lists one. Newsletters on it can't send until they move to another address. Refused while a campaign from it is sending, paused or scheduled. Adding it again needs new DNS records.

MCP toolremove_domainKeyFull accessCan't be undoneSafe to repeatReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

Request
curl -X DELETE "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Start Cloudflare authorization

POST/api/v1/domains/{id}/cloudflare/authorize

Starts Cloudflare sign-in for an account-owned sending domain, with PKCE and a ten-minute single-use state. The browser connect endpoint sets the matching secure cookie. Authorizing grants setup permission to add only missing email-provider DNS records after provisioning SES.

MCP toolstart_cloudflare_authorizationKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

Request
curl -X POST "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare/authorize" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Finish Cloudflare authorization

POST/api/v1/domains/cloudflare/callback

Completes Cloudflare authorization using its code and the browser's matching state cookie. Discovers the authorized zone, encrypts access and refresh tokens per account and domain, provisions missing email-provider setup, adds nonconflicting DNS records, and checks verification. Never returns credentials. A connected domain may still need DNS conflict resolution or administrator attention.

MCP toolfinish_cloudflare_authorizationKeyFull accessReaches outside XMails
Parameter
staterequired

body · string

Single-use state returned by Cloudflare

browserStaterequired

body · string

Matching state from the secure browser cookie

code

body · string

Cloudflare authorization code

error

body · string

Authorization error returned when consent was declined

Request
curl -X POST "https://xmails.si/api/v1/domains/cloudflare/callback" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"state":"…","browserState":"…"}'

Get Cloudflare connection

GET/api/v1/domains/{id}/cloudflare

Returns the account-owned domain's Cloudflare connection status. API tokens and encrypted credentials are never returned.

MCP toolget_cloudflare_connectionKeyFull accessRead-onlySafe to repeat
Parameter
idrequired

path · string

The domain's ID

Request
curl "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Connect Cloudflare

POST/api/v1/domains/{id}/cloudflare

Connects an owned sending domain to an active Cloudflare zone using a zone-scoped token with Zone Read and DNS Edit. Validates zone ownership and read access, encrypts the token per account and domain, and makes no DNS changes. Never returns the token.

MCP toolconnect_cloudflareKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

zoneIdrequired

body · string

Cloudflare Zone ID shown on the domain's Overview page

apiTokenrequired

body · string

Secret API token scoped to this zone with Zone Read and DNS Edit permissions

Request
curl -X POST "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"zoneId":"…","apiToken":"…"}'

Preview Cloudflare DNS setup

POST/api/v1/domains/{id}/cloudflare/preview

Reads Cloudflare DNS and previews missing SES or PostShiba authentication and optional archive records. Preserves valid existing or inherited DMARC policies, reports conflicts, and makes no DNS changes.

MCP toolpreview_cloudflare_dnsKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

Request
curl -X POST "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare/preview" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Configure Cloudflare records

POST/api/v1/domains/{id}/cloudflare/apply

Rechecks and adds only missing provider-generated DNS records to the connected zone, with CNAME proxying disabled. Refuses conflicting plans, never updates or deletes existing records, serializes simultaneous applies, and checks provider verification afterward. Retry safely after partial failure; DNS propagation may take time.

MCP toolapply_cloudflare_dnsKeyFull accessReaches outside XMails
Parameter
idrequired

path · string

The domain's ID

Request
curl -X POST "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare/apply" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Disconnect Cloudflare

DELETE/api/v1/domains/{id}/cloudflare

Removes the saved encrypted Cloudflare token for this account-owned domain. Existing DNS records are left in place and the token can be revoked in Cloudflare. Wait for active DNS setup to finish first.

MCP tooldisconnect_cloudflareKeyFull accessSafe to repeat
Parameter
idrequired

path · string

The domain's ID

Request
curl -X DELETE "https://xmails.si/api/v1/domains/6650f1c2e9b1d4a012345678/cloudflare" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Images

Pictures for campaign content, on XMails’ CDN, kept in the account's library to use again.

List images

GET/api/v1/images

Lists the images uploaded to the account, newest first, 50 a page, so a campaign can use one again without uploading it twice. Pass nextCursor back as cursor for the next page.

MCP toollist_imagesKeyFull accessRead-onlySafe to repeat
Parameter
limit

query · integer

Images per page, 50 by default, 100 at most

cursor

query · string

nextCursor from the previous page

Request
curl "https://xmails.si/api/v1/images?limit=20" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Upload an image

POST/api/v1/images

Stores a PNG, JPEG, GIF or WebP image under 4 MB on XMails’ CDN and returns its URL for campaign content. Send the file as base64 (under about 3 MB, since requests stop at 4.5 MB) or an https:// link XMails downloads. The URL never changes: sent emails keep pointing at it. list_images finds images uploaded before.

MCP toolupload_imageKeyFull accessReaches outside XMails
Parameter
base64

body · string

The image file, base64 encoded; a data: URL works too

url

body · string

An https:// link to the image

fileName

body · string

Used in the stored file's name

contentType

body · string

The file's type, checked against its first bytes

Request
curl -X POST "https://xmails.si/api/v1/images" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/cover.png"}'

API keys

Keys for the REST API and MCP, plus account-scoped image-model preferences using the shared Gemini connection.

List API keys

GET/api/v1/api-keys

Lists the account's API keys, revoked ones included, with their level and when they were last used. Keys themselves are never shown again.

MCP toollist_api_keysKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/api-keys" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Create an API key

POST/api/v1/api-keys

Creates an API key and returns it once; only its hash is stored. full can do everything a full key can, including creating more keys; signups can only add contacts, for keys that end up in website code. An account has up to 20 active keys: one more answers conflict until one is revoked.

MCP toolcreate_api_keyKeyFull access
Parameter
namerequired

body · string

What the key is for, e.g. Website signups

levelrequired

body · "full" | "signups"

full or signups

Request
curl -X POST "https://xmails.si/api/v1/api-keys" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Website signups","level":"signups"}'

Revoke an API key

DELETE/api/v1/api-keys/{id}

Revokes an API key for good: requests with it answer unauthorized from now on. A key can revoke itself.

MCP toolrevoke_api_keyKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The API key's ID

Request
curl -X DELETE "https://xmails.si/api/v1/api-keys/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Get AI settings

GET/api/v1/ai-settings

Returns this account's Gemini models and reference-image settings, plus the shared server connection status. The server API key is never returned.

MCP toolget_ai_settingsKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/ai-settings" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Save AI settings

PATCH/api/v1/ai-settings

Saves account-scoped model and visual preferences. All generation uses the shared server Gemini key; customers cannot supply keys. Changes apply to new templates; queued templates retain their models and visual brief. No provider request is made.

MCP toolupdate_ai_settingsKeyFull access
Parameter
textModel

body · string

Gemini model ID used to write newsletter copy

imageModel

body · string

Nano Banana / Gemini image model ID used for artwork

artDirection

body · string

Brand colors, lighting, composition and visual identity to reuse across newsletter artwork

aspectRatio

body · "16:9" | "4:3" | "1:1"

Aspect ratio of generated newsletter artwork

referenceLimit

body · integer

Maximum selected product/service images to combine, 3 by default

Request
curl -X PATCH "https://xmails.si/api/v1/ai-settings" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

List connected apps

GET/api/v1/connected-apps

Lists the apps connected to the account with OAuth, such as ChatGPT, Claude and Grok Bot, with when they were connected and last used. Each one has full access, like a full access API key.

MCP toollist_connected_appsKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/connected-apps" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Disconnect an app

DELETE/api/v1/connected-apps/{id}

Disconnects an app connected with OAuth: its tokens stop working at once, and it has to ask for access again to come back. An app can disconnect itself.

MCP toolrevoke_connected_appKeyFull accessCan't be undoneSafe to repeat
Parameter
idrequired

path · string

The connected app's ID

Request
curl -X DELETE "https://xmails.si/api/v1/connected-apps/6650f1c2e9b1d4a012345678" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Billing

Plan, usage and links to Stripe to change plan.

Get the plan and usage

GET/api/v1/billing

The account's plan, subscription status and this month's usage against the plan's limits, with every plan on sale for comparison. Works without an active plan. A self-hosted server has no billing and answers billing_off.

MCP toolget_billingKeyFull accessRead-onlySafe to repeat
Request
curl "https://xmails.si/api/v1/billing" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"

Change plan

POST/api/v1/billing/change-plan

Returns a Stripe page where the account owner picks up the change: Checkout without a paid plan (on a free plan too: the paid plan takes over), the Customer Portal's confirmation page with one. Nothing changes until they confirm there. Give the URL to the user. A self-hosted server has no billing and answers billing_off.

MCP toolchange_planKeyFull accessReaches outside XMails
Parameter
planrequired

body · "starter" | "growth" | "pro" | "scale" | "max"

starter, growth, pro, scale or max

interval

body · "month" | "year"

month (default) or year, which costs 10 months

Request
curl -X POST "https://xmails.si/api/v1/billing/change-plan" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan":"growth","interval":"year"}'

Open the billing portal

POST/api/v1/billing/portal

Returns a Stripe Customer Portal link for the account owner: payment method, invoices, plan changes and cancellation. A self-hosted server has no billing and answers billing_off.

MCP toolopen_billing_portalKeyFull accessReaches outside XMails
Request
curl -X POST "https://xmails.si/api/v1/billing/portal" \
  -H "Authorization: Bearer $MAILCHEAP_API_KEY"