SparkPost’s REST API has been on v1 since 2014 and remains the single source of truth for the platform — every send, template, webhook and metric flows through the same JSON surface exposed at api.sparkpost.com (US) and api.eu.sparkpost.com (EU). Official SDKs cover 6 languages but most were last tagged in 2018–2021, so teams shipping new integrations increasingly call the REST API directly. For AI agents the story is thinner: as of August 2026 there is no first-party MCP server, only three third-party wrappers (Zapier, Vinkius, MCP Bundles) built on top of the public API.
SparkPost (owned by Bird, formerly MessageBird since November 2021) has not shipped a first-party Model Context Protocol server. The public REST API is stable and well-scoped, so third-party MCP wrappers appeared quickly — but if your compliance team requires a vendor-audited MCP surface for LLM agents, SparkPost is not there yet in 2026. Compare with Postmark and Resend, whose newer developer-first APIs have attracted more community MCP work, and SendGrid, which is in the same “wrapper-only” position.
SparkPost / Bird publishes no first-party MCP endpoint. All three usable servers are third-party wrappers over the public v1 REST API — Zapier MCP (Send Email action), Vinkius (~10 tools) and MCP Bundles (7 read-only list tools). For audited first-party coverage, use the REST API directly from your agent or wait for a Bird announcement.
Three hosted MCP surfaces are available today. All three read a SparkPost API key you provision yourself (US or EU region), so credential rotation stays inside your SparkPost account.
Zapier-hosted MCP endpoint exposing the SparkPost Send Email action (and every other trigger/action in the Zapier SparkPost app) to any MCP-compatible client. Best fit when the agent also needs to touch other SaaS.
Hosted third-party MCP connector with roughly 10 tools covering send email, templates CRUD, suppression list, webhooks, deliverability metrics and bounce events. Paid plan, no self-hosting.
MCPBundles-hosted bundle with 7 read-only list tools (templates, sending domains, message events, recipients, snippets, subaccounts, AB tests) plus a bundled skill doc. Read-only — safe for exploratory agents.
Why buyers should care. The absence of a first-party MCP server is not a blocker — SparkPost’s REST API is small enough (roughly 15 top-level resources) that a bespoke MCP shim is a one-afternoon project. What it does mean: no vendor SLA on the MCP layer, no guarantee of parity when SparkPost ships new endpoints, and every third-party server hosts your API key on its own infra. If that is a compliance issue, provision the key with the minimum scope, rotate on a schedule, and prefer the read-only MCP Bundles surface for exploratory agents.
| Base URL (US) | https://api.sparkpost.com/api/v1 |
|---|---|
| Base URL (EU) | https://api.eu.sparkpost.com/api/v1 |
| API version | v1 — stable since 2014, no v2 announced |
| Response format | JSON (UTF-8), Content-Type: application/json |
| Pagination (Events) | Cursor-based — cursor starts at initial, next cursor returned in links.next; default per_page 1000, max 10,000 |
| Pagination (lists) | Simple limit / offset or per_page on most other list endpoints |
| Bulk operations | One Transmissions call can address up to 1,000 recipients |
| Regions | US and EU are separate accounts — a US key does not work against the EU endpoint and vice versa |
| Auth | API key in Authorization header (no Bearer prefix) |
| Content types | application/json for requests; UTF-8 required for non-ASCII substitution data |
The API is organised around 15 top-level resources: Transmissions (create/list/cancel sends), Templates, Sending Domains, Tracking Domains, Inbound Domains, Relay Webhooks, event Webhooks, Events Search, Metrics/Deliverability, Suppression List, Recipient Lists, Recipient Validation, Subaccounts and IP Pools / Sending IPs. Most write endpoints accept the same JSON shape you would post via SMTP, so the API and SMTP relay share a mental model — useful when migrating from providers like Amazon SES or Brevo where the two channels are more decoupled.
The primary method. Provision an API key in the SparkPost dashboard under Configuration › API Keys, scope it to the minimum permissions needed (Transmissions: Read/Write, plus any specific resources), then send it as the raw Authorization header value — no Bearer or Basic prefix. Example:
curl -H "Authorization: 1234567890abcdef1234567890abcdef12345678"
https://api.sparkpost.com/api/v1/accountThis differs from SendGrid and Postmark, which use Authorization: Bearer <key> and X-Postmark-Server-Token respectively. Copying a SendGrid header into a SparkPost request is one of the most common early-stage 401s.
For toolchains that only speak Basic auth, SparkPost accepts the API key as the username with an empty password. The equivalent curl:
curl -u "1234567890abcdef1234567890abcdef12345678:"
https://api.sparkpost.com/api/v1/accountFor the SMTP relay, authentication is unusual: the username is the literal string SMTP_Injection (case-sensitive), and the password is a SparkPost API key that carries the Send via SMTP permission. For subaccounts, append :X-MSYS-SUBACCOUNT=<subaccount_id> to the username. See the SparkPost SMTP tab for the full config.
Scope caveat. API-key permissions in SparkPost are granular per resource, not RBAC. A key scoped only to Transmissions: Read/Write cannot list templates or read metrics — you will get 403 with a helpful error body, not a silent failure. Provision one broad key for backend services and separate narrow keys for third-party MCP surfaces and CI runners; SparkPost lets you have as many keys as you like and rotate them individually.
| Limit | Value | Notes |
|---|---|---|
| Recipients per Transmissions call | 1,000 | Sum of To + Cc + Bcc + archive lists — hard cap, chunk larger sends client-side |
| Message payload size | 20 MB | HTML + text + attachments + inline images combined per message |
| Events Search page size | 10,000 max | Default 1,000; pagination consumes rate-limit budget |
| Sandbox domain volume | 5 messages total | Only on sparkpostbox.com, only to the account owner’s verified address |
| Free-plan monthly cap | 100,000/month | Requires a valid credit card once exceeded; enforced with HTTP 420, not 429 |
| API RPM / RPS | Not publicly documented | Signalled per endpoint with HTTP 429; varies by plan tier and endpoint class (transactional vs query) |
SparkPost’s rate-limit philosophy is closer to Amazon SES than to SendGrid: there is no single account-wide RPM published in the docs, and the platform enforces a mix of monthly volume caps (HTTP 420 Enhance Your Calm) and per-endpoint throttles (HTTP 429) that you discover empirically. The pragmatic workaround: keep a jittered exponential-backoff wrapper around Transmissions and Events calls, respect the Retry-After header when present, and shift heavy Events queries to a nightly cron rather than the request path. High-volume customers (3M+ per month) can negotiate guaranteed burst rates as part of the Enterprise contract.
SparkPost publishes SDKs for 6 stacks. All target the v1 REST API and cover the common surface (Transmissions, Templates, Suppressions, Webhooks) — but as of 2026 most release cadences are slow, and newer resources like Events Search and Signals Analytics are often easier to consume by calling the REST API directly.
| Language | Package | Install | Repo |
|---|---|---|---|
| Python | sparkpost | pip install sparkpost | SparkPost/python-sparkpost — last tag 1.3.10 (Nov 2021) |
| Node.js | sparkpost | npm install sparkpost | SparkPost/node-sparkpost — last tag 2.1.3 (Oct 2018) |
| PHP | sparkpost/sparkpost | composer require sparkpost/sparkpost | SparkPost/php-sparkpost — renamed from sparkpost/php-sparkpost at 2.0, maintenance PRs still merging |
| Go | github.com/SparkPost/gosparkpost | go get github.com/SparkPost/gosparkpost | SparkPost/gosparkpost — community-maintained, tracks REST surface |
| Java | com.sparkpost:sparkpost-lib | Maven / Gradle dependency | SparkPost/java-sparkpost — low release cadence |
| Nodemailer transport | nodemailer-sparkpost-transport | npm install nodemailer-sparkpost-transport | SparkPost/nodemailer-sparkpost-transport — official Nodemailer transport |
SDK staleness — plan accordingly. The official Node SDK’s last tagged release is October 2018 and the Python SDK’s is November 2021. Both still work against v1 for the common send/template/suppression paths — but Events Search cursors, Inline Seeds and Signals Analytics are safer to call directly with requests / axios. If you need long-term support, budget a small internal wrapper rather than pinning to an SDK version.
Beyond the six official clients, the ecosystem is small but functional: nodemailer-sparkpost-transport for any Node app that already speaks Nodemailer, a maintained Django backend at django-sparkpost, a Symfony Mailer bridge in the mainline Symfony repo, Laravel’s built-in SparkPost mail driver (deprecated in Laravel 9 but still functional via community shims), and the official Postman collection covering the full v1 surface. For Rust / Elixir / Kotlin there is no maintained wrapper — call the REST API directly.
The full API surface is 15 top-level resources. Full reference lives at the SparkPost Developer Hub; the table below is the short list you will use in practice.
| Resource | Methods | Description |
|---|---|---|
| Transmissions /api/v1/transmissions | POST, GET, DELETE | Create, list and cancel outbound email transmissions (single or bulk, immediate or scheduled). |
| Templates /api/v1/templates | GET, POST, PUT, DELETE | CRUD for stored templates with substitution data and preview-with-substitution. |
| Sending Domains /api/v1/sending-domains | GET, POST, PUT, DELETE | Register, verify (DKIM / SPF / ownership) and manage sending domains. |
| Tracking Domains /api/v1/tracking-domains | GET, POST, PUT, DELETE | Manage custom domains for click/open tracking pixels and link rewrites. |
| Inbound Domains /api/v1/inbound-domains | GET, POST, DELETE | Configure domains for parsing inbound email through Relay Webhooks. |
| Relay Webhooks /api/v1/relay-webhooks | GET, POST, PUT, DELETE | Register HTTP endpoints that receive inbound (relay) email payloads. |
| Webhooks (events) /api/v1/webhooks | GET, POST, PUT, DELETE | Register push webhooks for delivery, bounce, open, click and other engagement events. |
| Events (search) /api/v1/events/message | GET | Cursor-paginated search of message events with rich filters and up to 10,000 per page. |
| Message Events (legacy) /api/v1/message-events | GET | Legacy event query endpoint (superseded by Events Search). |
| Metrics / Deliverability /api/v1/metrics/deliverability | GET | Aggregate deliverability metrics (delivered, bounces, opens, clicks) by many dimensions. |
| Suppression List /api/v1/suppression-list | GET, PUT, DELETE | Manage transactional and non-transactional suppressions (bounces, unsubscribes, complaints). |
| Recipient Lists /api/v1/recipient-lists | GET, POST, PUT, DELETE | Store reusable recipient lists with per-recipient substitution data. |
| Recipient Validation /api/v1/recipient-validation/single/{email} | GET | Real-time single-address validation (paid add-on). |
| Subaccounts /api/v1/subaccounts | GET, POST, PUT | Provision and manage subaccounts (compartmentalised tenants) inside a parent account. |
| IP Pools & Sending IPs /api/v1/ip-pools, /api/v1/sending-ips | GET, POST, PUT, DELETE | Group and assign dedicated sending IPs into pools for reputation isolation. |
from sparkpost import SparkPost
sp = SparkPost('YOUR_SPARKPOST_API_KEY') # or set SPARKPOST_API_KEY env var
# For EU: SparkPost('YOUR_SPARKPOST_API_KEY', base_uri='https://api.eu.sparkpost.com')
response = sp.transmissions.send(
recipients=[{'address': 'user@example.com'}],
from_email='hello@yourverifieddomain.com',
subject='Hello from SparkPost',
html='<p>Hi <strong>{{name}}</strong>, this is a test.</p>',
text='Hi {{name}}, this is a test.',
substitution_data={'name': 'Friend'},
track_opens=True,
track_clicks=True,
)
print(response['id'], response['total_accepted_recipients'])const SparkPost = require('sparkpost');
// For EU: new SparkPost('YOUR_SPARKPOST_API_KEY', { origin: 'https://api.eu.sparkpost.com' })
const client = new SparkPost('YOUR_SPARKPOST_API_KEY');
client.transmissions.send({
content: {
from: 'hello@yourverifieddomain.com',
subject: 'Hello from SparkPost',
html: '<p>Hi <strong>{{name}}</strong>, this is a test.</p>',
text: 'Hi {{name}}, this is a test.',
},
substitution_data: { name: 'Friend' },
recipients: [{ address: 'user@example.com' }],
options: { open_tracking: true, click_tracking: true },
})
.then(data => console.log('Sent:', data.results.id))
.catch(err => console.error('SparkPost error:', err));curl -X POST https://api.sparkpost.com/api/v1/transmissions
-H "Authorization: YOUR_SPARKPOST_API_KEY"
-H "Content-Type: application/json"
-d '{
"options": { "open_tracking": true, "click_tracking": true },
"content": {
"from": "hello@yourverifieddomain.com",
"subject": "Hello from SparkPost",
"html": "<p>Hi <strong>{{name}}</strong>, this is a test.</p>",
"text": "Hi {{name}}, this is a test."
},
"substitution_data": { "name": "Friend" },
"recipients": [ { "address": "user@example.com" } ]
}'SparkPost EU accounts (created at eu.sparkpost.com) will return 401 or empty responses against the US endpoints. Use smtp.eu.sparkpostmail.com for SMTP and https://api.eu.sparkpost.com/api/v1 for REST. Every official SDK accepts a base_uri / origin option — set it once at client init rather than sprinkling it per call. Getting this wrong is the single most common cause of “my key does not work” support tickets in the SparkPost community forum.
Unlike SendGrid, MailerSend and most modern APIs, SparkPost expects Authorization: <key> with no scheme prefix. If you paste Authorization: Bearer <key> you get 401 Unauthorized. This trips up teams migrating from SendGrid or Resend who assume the header shape is universal.
The Events Search endpoint is powerful (10,000 events per page, rich filters) but every cursor request counts against the account’s per-endpoint rate limit. A backfill loop that walks 30 days of history in a tight while cursor can burn the budget for the whole account and start rejecting production Transmissions calls. Add time.sleep(0.5) between pages, respect Retry-After, and run backfills off-peak.
A single POST /transmissions can address at most 1,000 recipients across To, Cc, Bcc and archive lists combined. Larger sends must be chunked client-side — there is no server-side auto-split. Total payload (HTML + text + attachments + inline images) is capped at 20 MB regardless of recipient count. Compare with Amazon SES (50 recipients per SendEmail, 10 MB payload) and Postmark (500 per batch).
When you cross the free-plan 100,000/month cap without a credit card on file, or a paid tier’s monthly volume ceiling, SparkPost returns HTTP 420 Enhance Your Calm — not the usual 429 Too Many Requests. A generic retry helper that only treats 429 as retryable will treat 420 as a permanent failure and drop the message. Extend your retry classifier to include 420 with a much longer backoff (hours, not seconds) or, better, wire a Signals Analytics alert on approaching the monthly ceiling.
sparkpost.com, sparkpostmail.com), gradually surfaced under bird.com.python-sparkpost 1.3.10 released. Last tagged release of the official Python SDK; still compatible with the v1 REST API but new resources require calling the API directly.scph<selector> DKIM CNAME rotation used by all new domains from that date forward (selector prefix scph0421).Full release notes: SparkPost Developer Hub release notes.
Two base URLs depending on account region: https://api.sparkpost.com/api/v1 for US accounts and https://api.eu.sparkpost.com/api/v1 for EU accounts. Authenticate by putting the raw API key in the Authorization header — no Bearer prefix. A curl smoke test: curl -H "Authorization: <key>" https://api.sparkpost.com/api/v1/account. HTTP Basic auth also works with the key as the username and an empty password.
Six official clients: Python (sparkpost, last tag 1.3.10 in Nov 2021), Node.js (sparkpost, last tag 2.1.3 in Oct 2018), PHP (sparkpost/sparkpost, still receiving maintenance PRs), Go (gosparkpost, community-maintained), Java (com.sparkpost:sparkpost-lib, low cadence), plus the nodemailer-sparkpost-transport. All still work against v1 for common send/template/suppression paths — but newer resources like Events Search cursors and Signals Analytics are easier to call directly with requests or axios.
The Events Search endpoint (GET /api/v1/events/message) uses cursor pagination. First request: cursor=initial with a per_page between 1 and 10,000 (default 1,000). The response includes a links.next URL containing the next cursor. Loop until links.next is absent. Each page counts against the endpoint’s rate limit, so sleep between pages when backfilling. Other list endpoints use simple limit / offset or per_page.
SparkPost does not publish a single account-wide RPM/RPS. Per-endpoint throttles are signalled with HTTP 429 plus a Retry-After header, and monthly volume ceilings fire HTTP 420 Enhance Your Calm (not 429 — a common trap for generic retry helpers). Hard payload limits: 1,000 recipients per Transmissions call, 20 MB per message, 10,000 per Events page. Enterprise contracts (3M+/month) can negotiate guaranteed burst rates.
No. As of August 2026 SparkPost / Bird publishes no first-party MCP server. Three third-party wrappers exist on top of the public REST API: Zapier MCP for SparkPost (exposes the Send Email action and everything else the Zapier SparkPost app supports), Vinkius SparkPost MCP (~10 tools, commercial), and MCP Bundles (7 read-only list tools). None come with vendor-level SLAs on the MCP layer.
POST /api/v1/transmissions with a body containing content (from, subject, html, text or template_id), recipients (array of {address, substitution_data}) and optional top-level substitution_data for defaults. SparkPost merges per-recipient substitutions over defaults, so you can define {"name": "Friend"} at the top level and override per recipient. See the curl example above. Response includes results.id (the transmission id) and total_accepted_recipients.
This review follows our email infrastructure testing methodology. We disclose affiliate relationships in our editorial independence policy.