Documentation
Email API
The full REST reference. All endpoints are under https://app.mailstein.com/api/v1 and require a bearer API key. For live, schema-complete request builders use the interactive reference ↗.
Conventions
- Auth —
Authorization: Bearer ms_...on every request. - Content type — send and receive
application/json. - IDs — prefixed and stable (
em_emails,ms_keys).
Emails
POST /v1/emails Send an email
POST /v1/emails/batch Send up to a batch of emails in one call
GET /v1/emails List emails
GET /v1/emails/{emailId} Retrieve one email + status
PATCH /v1/emails/{emailId} Reschedule a queued email
POST /v1/emails/{emailId}/cancel Cancel a scheduled email
POST /v1/emails
| Field | Type | Notes |
|---|---|---|
from required | string | Sender on a verified domain. Name <you@domain.com> is supported. |
to required | string | string[] | One recipient or an array. |
subject | string | Optional when templateId is provided. |
html | string | HTML body. |
text | string | Plain-text body / fallback. |
templateId | string | ID of a template from the dashboard. |
variables | object | Values substituted into the template. |
replyTo | string | string[] | Reply-To address(es). |
cc / bcc | string | string[] | Carbon / blind copy. |
attachments | array | File attachments (name + base64 content). |
headers | object | Custom headers to include on the message. |
scheduledAt | string | ISO-8601 time to send later. |
inReplyToId | string | Thread a reply to a prior message. |
Request
{
"from": "hello@yourdomain.com",
"to": "customer@example.com",
"subject": "Your receipt",
"html": "<p>Thanks for your order.</p>"
}200 Response
{ "emailId": "em_8fk2..." }Domains
GET /v1/domains List domains
POST /v1/domains Add a sending domain
GET /v1/domains/{id} Retrieve a domain + DNS records
PUT /v1/domains/{id}/verify Re-check DNS and verify
DELETE /v1/domains/{id} Remove a domain
See Domains & DNS for the records and verification flow.
Contacts & contact books
GET /v1/contactBooks List contact books
POST /v1/contactBooks Create a contact book
GET /v1/contactBooks/{contactBookId} Retrieve a book
PATCH /v1/contactBooks/{contactBookId} Update a book
DELETE /v1/contactBooks/{contactBookId} Delete a book
POST /v1/contactBooks/{id}/contacts Add a contact
GET /v1/contactBooks/{id}/contacts List contacts
POST /v1/contactBooks/{id}/contacts/bulk Bulk add contacts
DELETE /v1/contactBooks/{id}/contacts/bulk Bulk delete contacts
GET /v1/contactBooks/{id}/contacts/{contactId} Retrieve a contact
PATCH /v1/contactBooks/{id}/contacts/{contactId} Update a contact
PUT /v1/contactBooks/{id}/contacts/{contactId} Upsert a contact
DELETE /v1/contactBooks/{id}/contacts/{contactId} Delete a contact
Campaigns
POST /v1/campaigns Create a broadcast campaign
GET /v1/campaigns List campaigns
GET /v1/campaigns/{campaignId} Retrieve a campaign
POST /v1/campaigns/{campaignId}/schedule Schedule a send
POST /v1/campaigns/{campaignId}/pause Pause a running campaign
POST /v1/campaigns/{campaignId}/resume Resume a paused campaign
DELETE /v1/campaigns/{campaignId} Delete a campaign
Analytics
GET /v1/analytics/email-time-series Sends / deliveries / opens over time
GET /v1/analytics/reputation-metrics Bounce & complaint reputation
Errors
Errors return the matching HTTP status and a JSON body:
Error body
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key"
}
}| Code | HTTP | Meaning |
|---|---|---|
BAD_REQUEST | 400 | Malformed or invalid parameters. |
UNAUTHORIZED | 401 | Missing or invalid API key. |
FORBIDDEN | 403 | Key lacks permission, or domain not allowed. |
NOT_FOUND | 404 | Resource does not exist. |
METHOD_NOT_ALLOWED | 405 | Wrong HTTP method for the route. |
NOT_UNIQUE | 409 | Conflicts with an existing resource. |
RATE_LIMITED | 429 | Too many requests — back off and retry. |
INTERNAL_SERVER_ERROR | 500 | Something went wrong on our side. |