API v1
REST API
for MailerSpark.
Bearer-token auth, idempotent endpoints for contacts and lists, full campaign creation with sequence steps. Everything your team does in the dashboard, you can do over the API.
Base URL
All API v1 endpoints live under https://app.mailerspark.com/api/v1. The base URL is the same in development and production.
Authentication
Authenticate every request with a Bearer token. Generate API keys in Settings → API Keys. The full secret is only ever shown once — store it somewhere safe immediately.
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # or X-Api-Key: ms_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Rate limits
Rate limits are enforced per API key, backed by Redis. The default limit is 100 requests per minute. Check the response headers:
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 97 X-RateLimit-Reset: 1700000000
Endpoints
/api/v1/contactsList contacts in your organization. Supports filtering by segment, list, status, and search query.
segmentFilter to a segment ID (seg_*)listFilter to a list/group ID (lst_*)statusactive | unsubscribed | bounced | complainedsearchSearch across email, firstName, lastName, companylimit1–100, default 50cursorPagination cursor from previous response/api/v1/contactsCreate a contact. Idempotent on (organizationId, email) — repeat calls return the existing record.
emailRequired · valid email addressfirstNameOptionallastNameOptionalcompanyOptionalcustomFieldsObject of { fieldName: value }listsArray of list IDs to add the contact to/api/v1/listsList contact groups/lists in your organization.
limit1–100, default 50cursorPagination cursor/api/v1/listsCreate a contact list/group. Optional double opt-in.
nameRequireddoubleOptInBoolean · default falsedescriptionOptional/api/v1/campaignsList campaigns. Filter by type (newsletter or cold), status, and date range.
typenewsletter | coldstatusdraft | scheduled | sending | sent | failedlimit1–100, default 50/api/v1/campaignsCreate a campaign. For type=cold, include the steps array with wait days and content.
typeRequired · newsletter | coldnameRequired · human-readable namelistIdRequired · recipient list IDsubjectRequired for newsletterhtmlContentRequired for newsletter · raw HTML or builder documentstepsRequired for cold · array of { waitDays, subject, htmlContent }scheduleAtOptional · ISO 8601 timestampPublic endpoints (no auth)
These endpoints are designed for public subscribe forms. They are rate-limited per IP and require no authentication.
/api/subscribeNoneAdd a contact to a list, optionally with double opt-in.
emailRequiredlistIdRequiredcustomFieldsOptional objectdoubleOptInOptional · default uses the list's setting/api/subscribe/confirmNoneConfirm a double opt-in token. Returns { status: 'subscribed' } on success.
tokenRequired · from the confirmation email/api/t/o/{token}NoneTracking pixel for opens. Returns a 1x1 transparent GIF.
/api/t/c/{token}?u=&s=NoneClick redirect. Logs the click and 302-redirects to the original URL.
uOriginal URLsSender IDErrors
The API returns standard HTTP status codes. The response body always includes a code and message:
{
"code": "rate_limited",
"message": "Rate limit exceeded. Try again in 47 seconds.",
"retryAfter": 47
}Common error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Missing or malformed parameter |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | Cross-organization access attempt |
| 404 | not_found | Resource does not exist |
| 409 | duplicate | Contact with this email already exists |
| 422 | validation_failed | Field-level validation failed |
| 429 | rate_limited | Per-minute rate limit exceeded |
Try it on the free plan
API access from day one.
Free plan includes API access. Generate a key, make a request, see it in the dashboard.