Skip to content
MailMarcodocs

01 · MailMarco API

Getting started

Five requests from nothing to a delivered email. Everything on this page is copy-pasteable against the live API.


What the API covers

MailMarco is one API for the whole lifecycle of a message. The surface splits into six areas, each documented on its own page:

  • Sending/v1/emails, single, batch and scheduled, with idempotency, attachments and templates.
  • Domains/v1/domains, DKIM keypair generation and DNS verification.
  • Events/v1/webhooks, signed HTTP callbacks for every state change.
  • Deliverability — suppressions, bounces, complaints, plan limits and warm-up caps.
  • Marketing — contacts, topics, segments and broadcasts.
  • Inbound — MX-hosted receiving, routing rules and message retrieval.

Base URL and versioning

Every route lives under a single origin and is prefixed with the API version. There is one version today.

base url
https://api.mailmarco.com/v1

Requests and responses are JSON (content-type: application/json) unless a route explicitly says otherwise — the contact export returns CSV, the raw-message endpoint returns message/rfc822, and the tracking pixel returns a GIF. Timestamps are ISO-8601 with an offset. Identifiers are UUIDs.

1. Create an account

Signing up creates a user and their first organization in one call. The organization is the tenant boundary: every key, domain, contact and message belongs to exactly one organization.

curl
curl -X POST https://api.mailmarco.com/v1/auth/signup \
  -H "content-type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "a-long-password",
    "organizationName": "Example Inc"
  }'

organizationName is optional — omit it and the name and slug are derived from the email local-part. The password must be at least 8 characters. Sign-up is rate limited to 5 requests per hour per IP.

Then log in to get a session access token:

curl
curl -X POST https://api.mailmarco.com/v1/auth/login \
  -H "content-type: application/json" \
  -d '{"email":"[email protected]","password":"a-long-password"}'

# => {"accessToken":"eyJhbGciOi...","refreshToken":"..."}

2. Create an API key

Key management is part of the dashboard surface, so it authenticates with the session access token from the previous step — not with an API key.

curl
curl -X POST https://api.mailmarco.com/v1/api-keys \
  -H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN" \
  -H "content-type: application/json" \
  -d '{"name":"production","scopes":["emails:send"]}'
response · 201
{
  "id": "0f0a1a1e-6f6f-4f3a-9c2e-6b6a5a1d7c11",
  "name": "production",
  "prefix": "9f1c3d5b7e9a1c3d",
  "scopes": ["emails:send"],
  "token": "mf_live_9f1c3d5b7e9a1c3d.8kQ2h9Rt7vXc1mB4nZ0pL6sW",
  "lastUsedAt": null,
  "revokedAt": null,
  "createdAt": "2026-07-29T09:14:02.113Z"
}

3. Add and verify a sending domain

You can only send from a domain your organization owns and has verified. Adding one mints a fresh DKIM keypair and returns the exact records to publish.

curl
curl -X POST https://api.mailmarco.com/v1/domains \
  -H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN" \
  -H "content-type: application/json" \
  -d '{"domain":"mail.example.com"}'
response · 201 (abridged)
{
  "id": "3c2b1a09-8d7e-4c5b-a6f2-1e0d9c8b7a65",
  "domain": "mail.example.com",
  "status": "pending",
  "region": "eu",
  "verifiedAt": null,
  "createdAt": "2026-07-29T09:16:41.882Z",
  "records": [
    {
      "type": "SPF",
      "host": "mail.example.com",
      "value": "v=spf1 include:spf.mailmarco.com ~all",
      "ttl": 3600,
      "verified": false
    },
    {
      "type": "DKIM",
      "host": "mm20260729a1b2c3._domainkey.mail.example.com",
      "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq...",
      "ttl": 3600,
      "verified": false
    }
  ]
}

Publish all five records at your DNS provider, then ask MailMarco to re-check. The selector in the DKIM host is unique to your domain — copy it from the response, never from this page.

curl
curl -X POST https://api.mailmarco.com/v1/domains/$DOMAIN_ID/verify \
  -H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN"

The domain reaches verified when every required record resolves. Full detail, including what each record does and why the return-path record is a CNAME, is on the Domains page.

4. Send your first email

Sending uses the API key, not the session token. A successful send answers 202 Accepted — the message is persisted and queued, not yet delivered.

curl
curl -X POST https://api.mailmarco.com/v1/emails \
  -H "authorization: Bearer $MAILMARCO_API_KEY" \
  -H "content-type: application/json" \
  -H "idempotency-key: welcome-user-42" \
  -d '{
    "from": "[email protected]",
    "to": "[email protected]",
    "subject": "Welcome aboard",
    "html": "<h1>Hello</h1><p>Thanks for signing up.</p>",
    "text": "Hello. Thanks for signing up."
  }'
response · 202
{
  "id": "b1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
  "status": "queued"
}

5. Look up the message

Fetching a message returns its recipients and the full event timeline — the same events that fire your webhooks.

curl
curl https://api.mailmarco.com/v1/emails/$MESSAGE_ID \
  -H "authorization: Bearer $MAILMARCO_API_KEY"
response · 200
{
  "id": "b1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
  "status": "queued",
  "from": "[email protected]",
  "subject": "Welcome aboard",
  "sandbox": false,
  "createdAt": "2026-07-29T09:22:10.004Z",
  "recipients": [
    { "type": "to", "address": "[email protected]", "status": "queued" }
  ],
  "events": [
    { "type": "queued", "occurredAt": "2026-07-29T09:22:10.004Z", "providerResponse": null }
  ]
}

Next steps

Do this nextWhy
Subscribe to webhooks202 means accepted, not delivered. Delivery, bounce and complaint outcomes only arrive as events.
Read the deliverability rulesSuppressions, plan limits (402) and warm-up caps (429) all reject sends before they leave the API.
Learn the error envelopeOne shape for every failure, with a stable `error` code you can branch on.
Install the Node SDKTyped helpers over the same routes, plus a machine-readable OpenAPI document.

Environment variables used on this site

Every sample assumes these are exported:

shell
export MAILMARCO_API_KEY="mf_live_…"        # runtime routes: /v1/emails, /v1/webhooks, …
export MAILMARCO_ACCESS_TOKEN="eyJhbGciOi…"  # management routes: /v1/domains, /v1/api-keys, …