Skip to content

Developers

Sync contacts, send campaigns, get events back

Sync contacts and orders, launch campaigns and automations, and get every open, click and unsubscribe pushed back to your server. One REST API, one key.

Base URLhttps://mintmailer.app/api/v1Every path is relative to it, so /contacts is https://mintmailer.app/api/v1/contacts.

Quickstart

Three steps from zero to your first contact. Every snippet reads your key from MINTMAIL_API_KEY, so nothing secret ends up in a script you paste around.

  1. Create an API key

    In the app, open Settings → API keys and create a key with the scopes you need — each endpoint below shows the one it requires. The key is shown once.

    Shell
    export MINTMAIL_API_KEY="rvz_live_…"
  2. Make your first request

    List your contacts. A 200 with {data, has_more, next_cursor} means the key works.

    GET /contacts
    curl https://mintmailer.app/api/v1/contacts \
      -H "Authorization: Bearer $MINTMAIL_API_KEY"
  3. Write something — safely

    Add a contact. The Idempotency-Key makes a retry return the first response instead of creating a duplicate.

    POST /contacts
    curl -X POST https://mintmailer.app/api/v1/contacts \
      -H "Authorization: Bearer $MINTMAIL_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: a-unique-key-per-request" \
      -d '{
      "email": "[email protected]",
      "first_name": "Ada"
    }'

Concepts

Authentication

Send your key as Authorization: Bearer rvz_live_…. A key belongs to one organisation and carries a fixed set of scopes, chosen when it was created; every operation states the scope it requires. A key without the scope gets 403, and a request for another organisation's row gets 404 rather than 403 — confirming that an id exists elsewhere is itself a disclosure.

Idempotency

Send an Idempotency-Key header on any write and a retry of that exact request returns the first response byte for byte, including its status and any id, rather than creating a second row. Idempotent-Replay on the response says which of the two happened. Omitting the header is allowed and gives you ordinary at-least-once semantics.

Rate limits

Per key, not per organisation, so one integration cannot spend another's budget. RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset are on every response, so you never have to exceed the limit to discover it.

Versioning

v1 changes additively only: an endpoint, an optional field or a new enum value may appear at any time, and nothing is ever removed, renamed or retyped inside a major version. Parse leniently and a release cannot break you. No version is withdrawn on less than twelve months' notice, announced with a Sunset header on every affected response long before it stops answering.

Webhooks guide

Get every open, click, bounce and unsubscribe POSTed to your server as it happens — no polling.

EventFires when
email.deliveredThe receiving mail server accepted the message.
email.openedThe recipient opened the message.
email.clickedThe recipient clicked a tracked link.
email.bouncedThe message was rejected — permanently or temporarily.
email.complainedThe recipient marked the message as spam.
contact.unsubscribedA contact opted out of your emails.
campaign.finishedA campaign finished sending to its whole audience.
Preview an event

email.delivered — The receiving mail server accepted the message.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=9cab143e7b23987d59f15fe67fd9ade631ca2ee235b9c9d262b2ac3309da0eb7
Mintmail-Event-Id: evt_01hxyz_email_delivered
Mintmail-Event-Type: email.delivered
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_email_delivered",
  "type": "email.delivered",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false
  }
}

email.opened — The recipient opened the message.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=3ea7fc0e64ea7412d6d1c3115d2f026404141bfa1e3697f276ef0c608feef412
Mintmail-Event-Id: evt_01hxyz_email_opened
Mintmail-Event-Type: email.opened
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_email_opened",
  "type": "email.opened",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false
  }
}

email.clicked — The recipient clicked a tracked link.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=4f005801241ab1c0a1aa202f8ce2f328a3438067a8d7ac774c897276e6be4f60
Mintmail-Event-Id: evt_01hxyz_email_clicked
Mintmail-Event-Type: email.clicked
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_email_clicked",
  "type": "email.clicked",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false,
    "link_url": "https://example.com/pricing?utm_source=mintmail"
  }
}

email.bounced — The message was rejected — permanently or temporarily.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=3a59b5c4d6937d242036e7ac719d06e1891ffa0f555c3b7b2b5b2afd5ccf2e5b
Mintmail-Event-Id: evt_01hxyz_email_bounced
Mintmail-Event-Type: email.bounced
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_email_bounced",
  "type": "email.bounced",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false,
    "bounce_type": "permanent",
    "bounce_subtype": "General",
    "diagnostic_code": "smtp; 550 5.1.1 user unknown"
  }
}

email.complained — The recipient marked the message as spam.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=112faf7fa0435780bda1d5f9bd5c9430f79d5f6dd2790f237929e641a2d3f5b5
Mintmail-Event-Id: evt_01hxyz_email_complained
Mintmail-Event-Type: email.complained
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_email_complained",
  "type": "email.complained",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false
  }
}

contact.unsubscribed — A contact opted out of your emails.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=7a830866a2862a0cb1738d9f59bf5c8236b83f16a5cdb60d2e0a0e4c2b051ddf
Mintmail-Event-Id: evt_01hxyz_contact_unsubscribed
Mintmail-Event-Type: contact.unsubscribed
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_contact_unsubscribed",
  "type": "contact.unsubscribed",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "campaign_id": "cmp_01hxyz"
  }
}

campaign.finished — A campaign finished sending to its whole audience.

Headers
Content-Type: application/json
Mintmail-Signature: t=1785753000,v1=74310658153aab32669c705dd5958fb79e5104a44f9436abadec1d87f3c9d550
Mintmail-Event-Id: evt_01hxyz_campaign_finished
Mintmail-Event-Type: campaign.finished
User-Agent: MintMail-Webhooks/1
Body
{
  "id": "evt_01hxyz_campaign_finished",
  "type": "campaign.finished",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "name": "November newsletter",
    "sent": 4980,
    "failed": 20,
    "total": 5000
  }
}

Test your verifier against these exact bytes with the sample secret whsec_docs_example_do_not_use_in_production — skip the five-minute age check, since the timestamp is fixed. Real deliveries are sent compact, without the indentation shown here.

How it works

Rather than polling, register an endpoint — in Settings → Webhooks or with POST /webhooks — and we POST each event you subscribe to as it happens: email.delivered, email.bounced, email.complained, email.opened, email.clicked, contact.unsubscribed and campaign.finished.

Verify the signature

Every request carries Mintmail-Signature: t=<unix seconds>,v1=<hex>, an HMAC-SHA256 over the string {t}.{raw body} keyed with the secret shown once when the endpoint was created. Verify it against the RAW body before parsing — re-serialising JSON changes the bytes and the signature will not match. Reject anything whose t is more than five minutes old, or a payload captured off the wire can be replayed at leisure.

Expect duplicates, not order

Delivery is at-least-once and unordered. An email.opened can reach you before the email.delivered it belongs to, and any event can arrive twice — after a retry, or after our own reconciliation notices a delivery went missing. Key your handler's idempotency on the payload's top-level id, which is stable for the life of the event.

Acknowledge with 2xx

Answer 2xx within ten seconds to acknowledge. Anything else is retried six times over roughly a quarter of an hour with exponential backoff; ten consecutive events that exhaust their retries disable the endpoint and email your admins. Answer 410 Gone to unsubscribe permanently — we stop immediately and do not retry.

Payload

Every delivery is {id, type, occurred_at, organization_id, data} — the WebhookEvent object, not the Webhook subscription resource. Message events (email.*) put campaign_id, contact_id, email, message_recipient_id and machine in data (clicks add link_url; bounces add bounce_type, bounce_subtype, diagnostic_code). contact.unsubscribed is {contact_id, email, campaign_id?}. campaign.finished is {campaign_id, name, sent, failed, total} with no contact fields.

Verification code

verify
# Check a captured delivery by hand. RAW_BODY must be the exact bytes received.
T=$(echo "$SIGNATURE_HEADER" | sed -E 's/.*t=([0-9]+).*/\1/')
V1=$(echo "$SIGNATURE_HEADER" | sed -E 's/.*v1=([0-9a-f]+).*/\1/')
EXPECTED=$(printf '%s.%s' "$T" "$RAW_BODY" \
  | openssl dgst -sha256 -hmac "$MINTMAIL_WEBHOOK_SECRET" | awk '{print $NF}')
[ "$EXPECTED" = "$V1" ] && echo "valid" || echo "invalid"
Ready to try it?Add an endpoint, then hit Send test in Settings → Webhooks to get a signed sample event at your URL.Endpoint API →

Contacts

get/contactscontact:view

List contacts

Requires the contact:view scope (View contacts and their details).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
status("subscribed" | "unsubscribed" | "bounced" | "complained" | "pending") | ("subscribed" | "unsubscribed" | "bounced" | "complained" | "pending")[]
list_idstring | string[]
tag_idstring | string[]
searchstring
Returns
200 page of Contact in data
Errors
400401403429500Error shape
GET /contacts
curl https://mintmailer.app/api/v1/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "contact",
      "email": "[email protected]",
      "first_name": "Jamie",
      "last_name": "Rivera",
      "status": "subscribed",
      "custom_fields": {
        "plan": "Pro",
        "signup_source": "webinar"
      },
      "opt_in_source": "signup_form",
      "opt_in_at": "2026-07-14T09:31:02.000Z",
      "last_engaged_at": "2026-07-14T09:31:02.000Z",
      "timezone": "timezone",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/contactscontact:edit

Create or update a contact

Requires the contact:edit scope (Create and edit contacts).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

emailrequiredstring
first_namestring | null
last_namestring | null
opt_in_sourcestring | null
status"subscribed" | "unsubscribed" | "bounced" | "complained" | "pending"
timezonestring | null
Returns
200 or 201 Contact in data
Errors
400401403409422429500Error shape
POST /contacts
curl -X POST https://mintmailer.app/api/v1/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "email": "[email protected]"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "contact",
    "email": "[email protected]",
    "first_name": "Jamie",
    "last_name": "Rivera",
    "status": "subscribed",
    "custom_fields": {
      "plan": "Pro",
      "signup_source": "webinar"
    },
    "opt_in_source": "signup_form",
    "opt_in_at": "2026-07-14T09:31:02.000Z",
    "last_engaged_at": "2026-07-14T09:31:02.000Z",
    "timezone": "timezone",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/contacts/{id}contact:view

Retrieve a contact

Requires the contact:view scope (View contacts and their details).

Path parameters

idrequiredstringThe contact's id.
Returns
200 Contact in data
Errors
400401403404429500Error shape
GET /contacts/{id}
curl https://mintmailer.app/api/v1/contacts/CONTACT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "contact",
    "email": "[email protected]",
    "first_name": "Jamie",
    "last_name": "Rivera",
    "status": "subscribed",
    "custom_fields": {
      "plan": "Pro",
      "signup_source": "webinar"
    },
    "opt_in_source": "signup_form",
    "opt_in_at": "2026-07-14T09:31:02.000Z",
    "last_engaged_at": "2026-07-14T09:31:02.000Z",
    "timezone": "timezone",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/contacts/{id}contact:edit

Update a contact

Requires the contact:edit scope (Create and edit contacts).

Path parameters

idrequiredstringThe contact's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

emailstring
first_namestring | null
last_namestring | null
opt_in_sourcestring | null
status"subscribed" | "unsubscribed" | "bounced" | "complained" | "pending"
timezonestring | null
Returns
200 Contact in data
Errors
400401403404409422429500Error shape
PATCH /contacts/{id}
curl -X PATCH https://mintmailer.app/api/v1/contacts/CONTACT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "email": "[email protected]"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "contact",
    "email": "[email protected]",
    "first_name": "Jamie",
    "last_name": "Rivera",
    "status": "subscribed",
    "custom_fields": {
      "plan": "Pro",
      "signup_source": "webinar"
    },
    "opt_in_source": "signup_form",
    "opt_in_at": "2026-07-14T09:31:02.000Z",
    "last_engaged_at": "2026-07-14T09:31:02.000Z",
    "timezone": "timezone",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/contacts/{id}contact:delete

Delete a contact

Requires the contact:delete scope (Delete contacts).

Path parameters

idrequiredstringThe contact's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /contacts/{id}
curl -X DELETE https://mintmailer.app/api/v1/contacts/CONTACT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
get/contacts/{id}/listslist:view

List the lists a contact belongs to

Requires the list:view scope (View lists).

Path parameters

idrequiredstringThe contact's id.

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of List in data
Errors
400401403404429500Error shape
GET /contacts/{id}/lists
curl https://mintmailer.app/api/v1/contacts/CONTACT_ID/lists \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "list",
      "name": "Weekly digest",
      "description": "Everyone who opened something in the last 90 days.",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
get/contacts/{id}/tagslist:view

List the tags on a contact

Requires the list:view scope (View lists).

Path parameters

idrequiredstringThe contact's id.

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of Tag in data
Errors
400401403404429500Error shape
GET /contacts/{id}/tags
curl https://mintmailer.app/api/v1/contacts/CONTACT_ID/tags \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "tag",
      "name": "Weekly digest",
      "color": "neutral",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Lists

get/listslist:view

List contact lists

Requires the list:view scope (View lists).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
namestring
Returns
200 page of List in data
Errors
400401403429500Error shape
GET /lists
curl https://mintmailer.app/api/v1/lists \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "list",
      "name": "Weekly digest",
      "description": "Everyone who opened something in the last 90 days.",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/listslist:edit

Create a contact list

Requires the list:edit scope (Create and edit lists).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namerequiredstring
descriptionstring | null
Returns
201 List in data
Errors
400401403409422429500Error shape
POST /lists
curl -X POST https://mintmailer.app/api/v1/lists \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "list",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/lists/{id}list:view

Retrieve a contact list

Requires the list:view scope (View lists).

Path parameters

idrequiredstringThe list's id.
Returns
200 List in data
Errors
400401403404429500Error shape
GET /lists/{id}
curl https://mintmailer.app/api/v1/lists/LIST_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "list",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/lists/{id}list:edit

Update a contact list

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe list's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namestring
descriptionstring | null
Returns
200 List in data
Errors
400401403404409422429500Error shape
PATCH /lists/{id}
curl -X PATCH https://mintmailer.app/api/v1/lists/LIST_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "list",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/lists/{id}list:edit

Delete a contact list, keeping its contacts

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe list's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /lists/{id}
curl -X DELETE https://mintmailer.app/api/v1/lists/LIST_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
get/lists/{id}/contactscontact:view

List the contacts on a list

Requires the contact:view scope (View contacts and their details).

Path parameters

idrequiredstringThe list's id.

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of Contact in data
Errors
400401403404429500Error shape
GET /lists/{id}/contacts
curl https://mintmailer.app/api/v1/lists/LIST_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "contact",
      "email": "[email protected]",
      "first_name": "Jamie",
      "last_name": "Rivera",
      "status": "subscribed",
      "custom_fields": {
        "plan": "Pro",
        "signup_source": "webinar"
      },
      "opt_in_source": "signup_form",
      "opt_in_at": "2026-07-14T09:31:02.000Z",
      "last_engaged_at": "2026-07-14T09:31:02.000Z",
      "timezone": "timezone",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/lists/{id}/contactslist:edit

Add contacts to a list

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe list's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

contact_idsrequiredstring[]
Returns
200 MembershipChange in data
Errors
400401403404409422429500Error shape
POST /lists/{id}/contacts
curl -X POST https://mintmailer.app/api/v1/lists/LIST_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "contact_ids": [
    "con_01hxyz"
  ]
}'
Example response
{
  "data": {
    "object": "membership_change",
    "changed": 128
  }
}
delete/lists/{id}/contactslist:edit

Remove contacts from a list

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe list's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

contact_idsrequiredstring[]
Returns
200 MembershipChange in data
Errors
400401403404409422429500Error shape
DELETE /lists/{id}/contacts
curl -X DELETE https://mintmailer.app/api/v1/lists/LIST_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "contact_ids": [
    "con_01hxyz"
  ]
}'
Example response
{
  "data": {
    "object": "membership_change",
    "changed": 128
  }
}

Tags

get/tagslist:view

List tags

Requires the list:view scope (View lists).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
namestring
Returns
200 page of Tag in data
Errors
400401403429500Error shape
GET /tags
curl https://mintmailer.app/api/v1/tags \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "tag",
      "name": "Weekly digest",
      "color": "neutral",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/tagslist:edit

Create a tag

Requires the list:edit scope (Create and edit lists).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namerequiredstring
color"neutral" | "positive" | "warning" | "danger" | "info"
Returns
201 Tag in data
Errors
400401403409422429500Error shape
POST /tags
curl -X POST https://mintmailer.app/api/v1/tags \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "tag",
    "name": "Weekly digest",
    "color": "neutral",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/tags/{id}list:view

Retrieve a tag

Requires the list:view scope (View lists).

Path parameters

idrequiredstringThe tag's id.
Returns
200 Tag in data
Errors
400401403404429500Error shape
GET /tags/{id}
curl https://mintmailer.app/api/v1/tags/TAG_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "tag",
    "name": "Weekly digest",
    "color": "neutral",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/tags/{id}list:edit

Update a tag

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe tag's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namestring
color"neutral" | "positive" | "warning" | "danger" | "info"
Returns
200 Tag in data
Errors
400401403404409422429500Error shape
PATCH /tags/{id}
curl -X PATCH https://mintmailer.app/api/v1/tags/TAG_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "tag",
    "name": "Weekly digest",
    "color": "neutral",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/tags/{id}list:edit

Delete a tag, keeping its contacts

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe tag's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /tags/{id}
curl -X DELETE https://mintmailer.app/api/v1/tags/TAG_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
post/tags/{id}/contactslist:edit

Apply a tag to contacts

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe tag's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

contact_idsrequiredstring[]
Returns
200 MembershipChange in data
Errors
400401403404409422429500Error shape
POST /tags/{id}/contacts
curl -X POST https://mintmailer.app/api/v1/tags/TAG_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "contact_ids": [
    "con_01hxyz"
  ]
}'
Example response
{
  "data": {
    "object": "membership_change",
    "changed": 128
  }
}
delete/tags/{id}/contactslist:edit

Remove a tag from contacts

Requires the list:edit scope (Create and edit lists).

Path parameters

idrequiredstringThe tag's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

contact_idsrequiredstring[]
Returns
200 MembershipChange in data
Errors
400401403404409422429500Error shape
DELETE /tags/{id}/contacts
curl -X DELETE https://mintmailer.app/api/v1/tags/TAG_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "contact_ids": [
    "con_01hxyz"
  ]
}'
Example response
{
  "data": {
    "object": "membership_change",
    "changed": 128
  }
}

Segments

get/segmentssegment:view

List segments

Requires the segment:view scope (View segments).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
namestring
Returns
200 page of Segment in data
Errors
400401403429500Error shape
GET /segments
curl https://mintmailer.app/api/v1/segments \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "segment",
      "name": "Weekly digest",
      "description": "Everyone who opened something in the last 90 days.",
      "rules": {
        "version": 1,
        "match": "all",
        "groups": [
          "groups"
        ]
      },
      "last_count": 128,
      "last_counted_at": "2026-07-14T09:31:02.000Z",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/segmentssegment:edit

Create a segment

Requires the segment:edit scope (Create and edit segments).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namerequiredstring
descriptionstring | null
rulesrequiredany
Returns
201 Segment in data
Errors
400401403409422429500Error shape
POST /segments
curl -X POST https://mintmailer.app/api/v1/segments \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers",
  "rules": null
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "segment",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "rules": {
      "version": 1,
      "match": "all",
      "groups": [
        "groups"
      ]
    },
    "last_count": 128,
    "last_counted_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/segments/{id}segment:view

Retrieve a segment

Requires the segment:view scope (View segments).

Path parameters

idrequiredstringThe segment's id.
Returns
200 Segment in data
Errors
400401403404429500Error shape
GET /segments/{id}
curl https://mintmailer.app/api/v1/segments/SEGMENT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "segment",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "rules": {
      "version": 1,
      "match": "all",
      "groups": [
        "groups"
      ]
    },
    "last_count": 128,
    "last_counted_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/segments/{id}segment:edit

Update a segment

Requires the segment:edit scope (Create and edit segments).

Path parameters

idrequiredstringThe segment's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namestring
descriptionstring | null
rulesany
Returns
200 Segment in data
Errors
400401403404409422429500Error shape
PATCH /segments/{id}
curl -X PATCH https://mintmailer.app/api/v1/segments/SEGMENT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "segment",
    "name": "Weekly digest",
    "description": "Everyone who opened something in the last 90 days.",
    "rules": {
      "version": 1,
      "match": "all",
      "groups": [
        "groups"
      ]
    },
    "last_count": 128,
    "last_counted_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/segments/{id}segment:edit

Delete a segment

Requires the segment:edit scope (Create and edit segments).

Path parameters

idrequiredstringThe segment's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /segments/{id}
curl -X DELETE https://mintmailer.app/api/v1/segments/SEGMENT_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
get/segments/{id}/contactscontact:view

List the contacts a segment selects

Requires the contact:view scope (View contacts and their details).

Path parameters

idrequiredstringThe segment's id.

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of Contact in data
Errors
400401403404429500Error shape
GET /segments/{id}/contacts
curl https://mintmailer.app/api/v1/segments/SEGMENT_ID/contacts \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "contact",
      "email": "[email protected]",
      "first_name": "Jamie",
      "last_name": "Rivera",
      "status": "subscribed",
      "custom_fields": {
        "plan": "Pro",
        "signup_source": "webinar"
      },
      "opt_in_source": "signup_form",
      "opt_in_at": "2026-07-14T09:31:02.000Z",
      "last_engaged_at": "2026-07-14T09:31:02.000Z",
      "timezone": "timezone",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Custom fields

get/custom_fieldscontact:view

List the organisation's custom field definitions

Requires the contact:view scope (View contacts and their details).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of CustomField in data
Errors
400401403429500Error shape
GET /custom_fields
curl https://mintmailer.app/api/v1/custom_fields \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "custom_field",
      "key": "plan",
      "label": "Plan",
      "type": "text",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Campaigns

get/campaignscampaign:view

List campaigns

Requires the campaign:view scope (View campaigns).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
status("draft" | "scheduled" | "dispatching" | "sending" | "testing" | "paused" | "sent" | "cancelled" | "failed") | ("draft" | "scheduled" | "dispatching" | "sending" | "testing" | "paused" | "sent" | "cancelled" | "failed")[]
Returns
200 page of Campaign in data
Errors
400401403429500Error shape
GET /campaigns
curl https://mintmailer.app/api/v1/campaigns \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "campaign",
      "name": "Weekly digest",
      "status": "draft",
      "subject": "Your July statement",
      "preheader": "Everything that moved this month, in one place.",
      "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "from_name": "Acme",
      "from_email": "[email protected]",
      "reply_to": "[email protected]",
      "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "audience": {
        "include": {
          "list_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ],
          "tag_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ],
          "segment_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ]
        },
        "exclude": {
          "list_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ],
          "tag_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ],
          "segment_ids": [
            "cly3k9f2b0000q8n1h4d7g5xz"
          ]
        }
      },
      "track_opens": true,
      "track_clicks": true,
      "scheduled_at": "2026-07-14T09:31:02.000Z",
      "send_started_at": "2026-07-14T09:31:02.000Z",
      "send_completed_at": "2026-07-14T09:31:02.000Z",
      "recipient_count": 128,
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/campaignscampaign:edit

Create a campaign

Requires the campaign:edit scope (Create and edit campaigns).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namerequiredstring
Returns
201 Campaign in data
Errors
400401403409422429500Error shape
POST /campaigns
curl -X POST https://mintmailer.app/api/v1/campaigns \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "campaign",
    "name": "Weekly digest",
    "status": "draft",
    "subject": "Your July statement",
    "preheader": "Everything that moved this month, in one place.",
    "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "from_name": "Acme",
    "from_email": "[email protected]",
    "reply_to": "[email protected]",
    "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "audience": {
      "include": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      },
      "exclude": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      }
    },
    "track_opens": true,
    "track_clicks": true,
    "scheduled_at": "2026-07-14T09:31:02.000Z",
    "send_started_at": "2026-07-14T09:31:02.000Z",
    "send_completed_at": "2026-07-14T09:31:02.000Z",
    "recipient_count": 128,
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/campaigns/{id}campaign:view

Retrieve a campaign

Requires the campaign:view scope (View campaigns).

Path parameters

idrequiredstringThe campaign's id.
Returns
200 Campaign in data
Errors
400401403404429500Error shape
GET /campaigns/{id}
curl https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "campaign",
    "name": "Weekly digest",
    "status": "draft",
    "subject": "Your July statement",
    "preheader": "Everything that moved this month, in one place.",
    "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "from_name": "Acme",
    "from_email": "[email protected]",
    "reply_to": "[email protected]",
    "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "audience": {
      "include": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      },
      "exclude": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      }
    },
    "track_opens": true,
    "track_clicks": true,
    "scheduled_at": "2026-07-14T09:31:02.000Z",
    "send_started_at": "2026-07-14T09:31:02.000Z",
    "send_completed_at": "2026-07-14T09:31:02.000Z",
    "recipient_count": 128,
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/campaigns/{id}campaign:edit

Update a draft campaign

Requires the campaign:edit scope (Create and edit campaigns).

Path parameters

idrequiredstringThe campaign's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

namestring
subjectstring | null
preheaderstring | null
sender_identity_idstring
reply_to"" | string | null
email_document_idstring
audienceobject
includeobject
excludeobject
track_opensboolean
track_clicksboolean
Returns
200 Campaign in data
Errors
400401403404409422429500Error shape
PATCH /campaigns/{id}
curl -X PATCH https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "name": "Newsletter subscribers"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "campaign",
    "name": "Weekly digest",
    "status": "draft",
    "subject": "Your July statement",
    "preheader": "Everything that moved this month, in one place.",
    "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "from_name": "Acme",
    "from_email": "[email protected]",
    "reply_to": "[email protected]",
    "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "audience": {
      "include": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      },
      "exclude": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      }
    },
    "track_opens": true,
    "track_clicks": true,
    "scheduled_at": "2026-07-14T09:31:02.000Z",
    "send_started_at": "2026-07-14T09:31:02.000Z",
    "send_completed_at": "2026-07-14T09:31:02.000Z",
    "recipient_count": 128,
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/campaigns/{id}campaign:delete

Delete a draft or cancelled campaign

Requires the campaign:delete scope (Delete campaigns).

Path parameters

idrequiredstringThe campaign's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /campaigns/{id}
curl -X DELETE https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
post/campaigns/{id}/cancelcampaign:send

Cancel a scheduled or sending campaign

Requires the campaign:send scope (Send and schedule campaigns).

Path parameters

idrequiredstringThe campaign's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
200 Campaign in data
Errors
400401403404409422429500Error shape
POST /campaigns/{id}/cancel
curl -X POST https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID/cancel \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "campaign",
    "name": "Weekly digest",
    "status": "draft",
    "subject": "Your July statement",
    "preheader": "Everything that moved this month, in one place.",
    "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "from_name": "Acme",
    "from_email": "[email protected]",
    "reply_to": "[email protected]",
    "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "audience": {
      "include": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      },
      "exclude": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      }
    },
    "track_opens": true,
    "track_clicks": true,
    "scheduled_at": "2026-07-14T09:31:02.000Z",
    "send_started_at": "2026-07-14T09:31:02.000Z",
    "send_completed_at": "2026-07-14T09:31:02.000Z",
    "recipient_count": 128,
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
post/campaigns/{id}/schedulecampaign:send

Schedule a campaign, or send it now

Requires the campaign:send scope (Send and schedule campaigns).

Path parameters

idrequiredstringThe campaign's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

scheduled_atstringWhen to send, as an ISO 8601 instant. Omit to send now.
Returns
200 Campaign in data
Errors
400401403404409422429500Error shape
POST /campaigns/{id}/schedule
curl -X POST https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID/schedule \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "scheduled_at": "2026-11-01T09:00:00Z"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "campaign",
    "name": "Weekly digest",
    "status": "draft",
    "subject": "Your July statement",
    "preheader": "Everything that moved this month, in one place.",
    "sender_identity_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "from_name": "Acme",
    "from_email": "[email protected]",
    "reply_to": "[email protected]",
    "email_document_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "audience": {
      "include": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      },
      "exclude": {
        "list_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "tag_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ],
        "segment_ids": [
          "cly3k9f2b0000q8n1h4d7g5xz"
        ]
      }
    },
    "track_opens": true,
    "track_clicks": true,
    "scheduled_at": "2026-07-14T09:31:02.000Z",
    "send_started_at": "2026-07-14T09:31:02.000Z",
    "send_completed_at": "2026-07-14T09:31:02.000Z",
    "recipient_count": 128,
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/campaigns/{id}/statsanalytics:view

Retrieve a campaign's engagement totals and rates

Requires the analytics:view scope (View reports and analytics).

Path parameters

idrequiredstringThe campaign's id.
Returns
200 CampaignStats in data
Errors
400401403404429500Error shape
GET /campaigns/{id}/stats
curl https://mintmailer.app/api/v1/campaigns/CAMPAIGN_ID/stats \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "object": "campaign_stats",
    "campaign_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "sent": 128,
    "delivered": 128,
    "opened": 128,
    "unique_opened": 128,
    "clicked": 128,
    "unique_clicked": 128,
    "bounced": 128,
    "soft_bounced": 128,
    "complained": 128,
    "unsubscribed": 128,
    "failed": 128,
    "open_rate": 0.42,
    "click_rate": 0.42,
    "click_to_open_rate": 0.42,
    "bounce_rate": 0.42,
    "hard_bounce_rate": 0.42,
    "complaint_rate": 0.42,
    "unsubscribe_rate": 0.42,
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}

Automations

get/automationsautomation:view

List automations

Requires the automation:view scope (View automations).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
status("draft" | "active" | "paused" | "archived") | ("draft" | "active" | "paused" | "archived")[]
Returns
200 page of Automation in data
Errors
400401403429500Error shape
GET /automations
curl https://mintmailer.app/api/v1/automations \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "automation",
      "name": "Weekly digest",
      "status": "draft",
      "version": 1,
      "allow_reentry": true,
      "definition": {
        "version": 1,
        "entryNodeId": "entryNodeId",
        "nodes": {}
      },
      "activated_at": "2026-07-14T09:31:02.000Z",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
get/automations/{id}automation:view

Retrieve an automation

Requires the automation:view scope (View automations).

Path parameters

idrequiredstringThe automation's id.
Returns
200 Automation in data
Errors
400401403404429500Error shape
GET /automations/{id}
curl https://mintmailer.app/api/v1/automations/AUTOMATION_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "automation",
    "name": "Weekly digest",
    "status": "draft",
    "version": 1,
    "allow_reentry": true,
    "definition": {
      "version": 1,
      "entryNodeId": "entryNodeId",
      "nodes": {}
    },
    "activated_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
post/automations/{id}/activateautomation:edit

Turn an automation on, or resume a paused one

Requires the automation:edit scope (Create, edit and activate automations).

Path parameters

idrequiredstringThe automation's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
200 Automation in data
Errors
400401403404409422429500Error shape
POST /automations/{id}/activate
curl -X POST https://mintmailer.app/api/v1/automations/AUTOMATION_ID/activate \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "automation",
    "name": "Weekly digest",
    "status": "draft",
    "version": 1,
    "allow_reentry": true,
    "definition": {
      "version": 1,
      "entryNodeId": "entryNodeId",
      "nodes": {}
    },
    "activated_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
post/automations/{id}/enrollautomation:edit

Enrol contacts into an active automation

Requires the automation:edit scope (Create, edit and activate automations).

Path parameters

idrequiredstringThe automation's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

contact_idsrequiredstring[]
Returns
200 Enrollment in data
Errors
400401403404409422429500Error shape
POST /automations/{id}/enroll
curl -X POST https://mintmailer.app/api/v1/automations/AUTOMATION_ID/enroll \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "contact_ids": [
    "con_01hxyz"
  ]
}'
Example response
{
  "data": {
    "object": "enrollment",
    "requested": 128,
    "enrolled": 128
  }
}
post/automations/{id}/pauseautomation:edit

Pause an automation, holding everyone inside it

Requires the automation:edit scope (Create, edit and activate automations).

Path parameters

idrequiredstringThe automation's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
200 Automation in data
Errors
400401403404409422429500Error shape
POST /automations/{id}/pause
curl -X POST https://mintmailer.app/api/v1/automations/AUTOMATION_ID/pause \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "automation",
    "name": "Weekly digest",
    "status": "draft",
    "version": 1,
    "allow_reentry": true,
    "definition": {
      "version": 1,
      "entryNodeId": "entryNodeId",
      "nodes": {}
    },
    "activated_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}

Orders

get/ordersorder:view

List orders

Requires the order:view scope (View orders and attributed revenue).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
emailstring
status"paid" | "refunded" | "partially_refunded" | "cancelled"
attributed"true" | "false"
Returns
200 page of Order in data
Errors
400401403429500Error shape
GET /orders
curl https://mintmailer.app/api/v1/orders \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "order",
      "external_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "email": "[email protected]",
      "contact_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "status": "paid",
      "total_cents": 128,
      "refunded_cents": 128,
      "currency": "currency",
      "occurred_at": "2026-07-14T09:31:02.000Z",
      "source": "source",
      "attributed_campaign_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "attributed_automation_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "attributed_node_id": "cly3k9f2b0000q8n1h4d7g5xz",
      "attribution_rule": "attribution_rule",
      "attributed_at": "2026-07-14T09:31:02.000Z",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/ordersorder:edit

Create or update an order

Requires the order:edit scope (Create and update orders).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

external_idrequiredstring
emailrequiredstring
status"paid" | "refunded" | "partially_refunded" | "cancelled"
total_centsrequiredinteger
refunded_centsinteger
currencyrequiredstring
occurred_atrequiredstring
sourcestring | null
Returns
200 or 201 Order in data
Errors
400401403409422429500Error shape
POST /orders
curl -X POST https://mintmailer.app/api/v1/orders \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "external_id": "order_1001",
  "email": "[email protected]",
  "total_cents": 4900,
  "currency": "USD",
  "occurred_at": "2026-11-01T09:00:00Z"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "order",
    "external_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "email": "[email protected]",
    "contact_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "status": "paid",
    "total_cents": 128,
    "refunded_cents": 128,
    "currency": "currency",
    "occurred_at": "2026-07-14T09:31:02.000Z",
    "source": "source",
    "attributed_campaign_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attributed_automation_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attributed_node_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attribution_rule": "attribution_rule",
    "attributed_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/orders/{id}order:view

Retrieve an order

Requires the order:view scope (View orders and attributed revenue).

Path parameters

idrequiredstringThe order's id.
Returns
200 Order in data
Errors
400401403404429500Error shape
GET /orders/{id}
curl https://mintmailer.app/api/v1/orders/ORDER_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "order",
    "external_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "email": "[email protected]",
    "contact_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "status": "paid",
    "total_cents": 128,
    "refunded_cents": 128,
    "currency": "currency",
    "occurred_at": "2026-07-14T09:31:02.000Z",
    "source": "source",
    "attributed_campaign_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attributed_automation_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attributed_node_id": "cly3k9f2b0000q8n1h4d7g5xz",
    "attribution_rule": "attribution_rule",
    "attributed_at": "2026-07-14T09:31:02.000Z",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}

Webhooks

get/webhookswebhook:manage

List webhook endpoints

Requires the webhook:manage scope (Add and remove webhook endpoints).

Query parameters

cursorstringnext_cursor from the previous page, passed back unmodified.
limitintegerRows per page, 1–100. Defaults to 50.
Returns
200 page of Webhook in data
Errors
400401403429500Error shape
GET /webhooks
curl https://mintmailer.app/api/v1/webhooks \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": [
    {
      "id": "cly3k9f2b0000q8n1h4d7g5xz",
      "object": "webhook",
      "url": "url",
      "description": "Everyone who opened something in the last 90 days.",
      "events": [
        "email.delivered"
      ],
      "status": "enabled",
      "disabled_reason": "disabled_reason",
      "consecutive_failures": 128,
      "last_success_at": "2026-07-14T09:31:02.000Z",
      "last_failure_at": "2026-07-14T09:31:02.000Z",
      "secret": "secret",
      "created_at": "2026-07-14T09:31:02.000Z",
      "updated_at": "2026-07-14T09:31:02.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
post/webhookswebhook:manage

Create a webhook endpoint

Requires the webhook:manage scope (Add and remove webhook endpoints).

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

urlrequiredstring
eventsrequired("email.delivered" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "contact.unsubscribed" | "campaign.finished")[]
descriptionstring
Returns
201 Webhook in data
Errors
400401403409422429500Error shape

Outbound event delivery

The JSON body we later POST to your URL — not the create response. See the webhooks guide for every event and how to verify it, or WebhookEvent for the field list.

Example delivery
{
  "id": "evt_01hxyz_email_opened",
  "type": "email.opened",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false
  }
}

Delivery body

idrequiredstringStable source-event id. Delivery is at-least-once — key your idempotency on this.
typerequired"email.delivered" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "contact.unsubscribed" | "campaign.finished"The dotted event name you subscribed to, e.g. email.opened.
occurred_atrequiredstringWhen the event happened, not when we delivered it.
organization_idrequiredstringYour organisation.
datarequiredobjectMessage-event fields. For contact.unsubscribed, data is {contact_id, email, campaign_id?}. For campaign.finished, data is {campaign_id, name, sent, failed, total} — no contact fields.
campaign_idrequiredstringThe campaign that sent the message.
contact_idrequiredstringOur id for the person.
emailrequiredstring | nullThe contact's address — match this to a contact in your system without calling the API back. Null only if the contact was deleted between the event and the emit.
message_recipient_idrequiredstringThis specific send of the message.
machinerequiredbooleanTrue when an open or click came from a scanner or link unfurler rather than a person. Always present on message events, including when false. Machine hits are excluded from every figure in the app.
link_urlstring | nullClicks only — the URL that was clicked.
bounce_typestring | nullBounces only — permanent, transient, or undetermined.
bounce_subtypestring | nullBounces only — provider subtype when available.
diagnostic_codestring | nullBounces only — SMTP diagnostic when available.
POST /webhooks
curl -X POST https://mintmailer.app/api/v1/webhooks \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "url": "https://example.com/webhooks/mintmail",
  "events": [
    "email.opened",
    "email.clicked"
  ]
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "webhook",
    "url": "url",
    "description": "Everyone who opened something in the last 90 days.",
    "events": [
      "email.delivered"
    ],
    "status": "enabled",
    "disabled_reason": "disabled_reason",
    "consecutive_failures": 128,
    "last_success_at": "2026-07-14T09:31:02.000Z",
    "last_failure_at": "2026-07-14T09:31:02.000Z",
    "secret": "secret",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
get/webhooks/{id}webhook:manage

Retrieve a webhook endpoint

Requires the webhook:manage scope (Add and remove webhook endpoints).

Path parameters

idrequiredstringThe webhook's id.
Returns
200 Webhook in data
Errors
400401403404429500Error shape
GET /webhooks/{id}
curl https://mintmailer.app/api/v1/webhooks/WEBHOOK_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY"
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "webhook",
    "url": "url",
    "description": "Everyone who opened something in the last 90 days.",
    "events": [
      "email.delivered"
    ],
    "status": "enabled",
    "disabled_reason": "disabled_reason",
    "consecutive_failures": 128,
    "last_success_at": "2026-07-14T09:31:02.000Z",
    "last_failure_at": "2026-07-14T09:31:02.000Z",
    "secret": "secret",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
patch/webhooks/{id}webhook:manage

Update a webhook endpoint

Requires the webhook:manage scope (Add and remove webhook endpoints).

Path parameters

idrequiredstringThe webhook's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.

Request body

urlstring
events("email.delivered" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "contact.unsubscribed" | "campaign.finished")[]
descriptionstring | null
status"enabled" | "disabled_by_user"
Returns
200 Webhook in data
Errors
400401403404409422429500Error shape
PATCH /webhooks/{id}
curl -X PATCH https://mintmailer.app/api/v1/webhooks/WEBHOOK_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key-per-request" \
  -d '{
  "url": "https://example.com/webhooks/mintmail"
}'
Example response
{
  "data": {
    "id": "cly3k9f2b0000q8n1h4d7g5xz",
    "object": "webhook",
    "url": "url",
    "description": "Everyone who opened something in the last 90 days.",
    "events": [
      "email.delivered"
    ],
    "status": "enabled",
    "disabled_reason": "disabled_reason",
    "consecutive_failures": 128,
    "last_success_at": "2026-07-14T09:31:02.000Z",
    "last_failure_at": "2026-07-14T09:31:02.000Z",
    "secret": "secret",
    "created_at": "2026-07-14T09:31:02.000Z",
    "updated_at": "2026-07-14T09:31:02.000Z"
  }
}
delete/webhooks/{id}webhook:manage

Delete a webhook endpoint

Requires the webhook:manage scope (Add and remove webhook endpoints).

Path parameters

idrequiredstringThe webhook's id.

Headers

Idempotency-KeystringA unique string of your choosing. Retrying a request with the same key returns the first response byte for byte — same status, same ids — instead of doing the work twice. Scoped to this key, this method and this path.
Returns
204 no body
Errors
400401403404409422429500Error shape
DELETE /webhooks/{id}
curl -X DELETE https://mintmailer.app/api/v1/webhooks/WEBHOOK_ID \
  -H "Authorization: Bearer $MINTMAIL_API_KEY" \
  -H "Idempotency-Key: a-unique-key-per-request"

Object reference

Every REST resource carries an object field naming its type, so a client holding one response can tell what it has without inferring from the shape. WebhookEvent is the outbound push body (no object field) — what we POST to your endpoint, distinct from the Webhook subscription resource.

Automation

Fields

idrequiredstring
objectrequired"automation"
namerequiredstring
statusrequired"draft" | "active" | "paused" | "archived"
versionrequiredinteger
allow_reentryrequiredboolean
definitionrequiredobjectThe flow, in the grammar automationDefinitionSchema defines. Read-only in v1.
versionrequiredinteger
entryNodeIdrequiredstring | null
nodesrequiredobject
activated_atrequiredstring | null
created_atrequiredstring
updated_atrequiredstring

Campaign

Fields

idrequiredstring
objectrequired"campaign"
namerequiredstring
statusrequired"draft" | "scheduled" | "dispatching" | "sending" | "testing" | "paused" | "sent" | "cancelled" | "failed"
subjectrequiredstring | null
preheaderrequiredstring | null
sender_identity_idrequiredstring | null
from_namerequiredstring | null
from_emailrequiredstring | null
reply_torequiredstring | null
email_document_idrequiredstring | null
audiencerequiredobject
includerequiredobject
excluderequiredobject
track_opensrequiredboolean
track_clicksrequiredboolean
scheduled_atrequiredstring | null
send_started_atrequiredstring | null
send_completed_atrequiredstring | null
recipient_countrequiredinteger
created_atrequiredstring
updated_atrequiredstring

CampaignStats

Fields

objectrequired"campaign_stats"
campaign_idrequiredstring
sentrequiredinteger
deliveredrequiredinteger
openedrequiredinteger
unique_openedrequiredinteger
clickedrequiredinteger
unique_clickedrequiredinteger
bouncedrequiredinteger
soft_bouncedrequiredinteger
complainedrequiredinteger
unsubscribedrequiredinteger
failedrequiredinteger
open_raterequirednumber | null
click_raterequirednumber | null
click_to_open_raterequirednumber | null
bounce_raterequirednumber | null
hard_bounce_raterequirednumber | null
complaint_raterequirednumber | null
unsubscribe_raterequirednumber | null
updated_atrequiredstring | null

Contact

Fields

idrequiredstring
objectrequired"contact"
emailrequiredstring
first_namerequiredstring | null
last_namerequiredstring | null
statusrequired"subscribed" | "unsubscribed" | "bounced" | "complained" | "pending"
custom_fieldsrequiredobject
opt_in_sourcerequiredstring | null
opt_in_atrequiredstring | null
last_engaged_atrequiredstring | null
timezonerequiredstring | null
created_atrequiredstring
updated_atrequiredstring

CustomField

Fields

idrequiredstring
objectrequired"custom_field"
keyrequiredstring
labelrequiredstring
typerequired"text" | "number" | "date" | "boolean"
created_atrequiredstring
updated_atrequiredstring

Enrollment

Fields

objectrequired"enrollment"
requestedrequiredinteger
enrolledrequiredinteger

Error

Every 4xx and 5xx response has this shape, whatever went wrong.

Fields

errorrequiredobject
typerequired"invalid_request_error" | "authentication_error" | "permission_error" | "rate_limit_error" | "idempotency_error" | "api_error"The coarse class. Switch on this, not on code.
coderequired"parameter_invalid" | "parameter_missing" | "malformed_request" | "api_key_missing" | "api_key_invalid" | "api_key_revoked" | "api_key_expired" | "insufficient_scope" | "resource_missing" | "resource_conflict" | "idempotency_key_in_flight" | "unprocessable" | "rate_limit_exceeded" | "internal_error"The specific reason, for a human and for a log.
messagerequiredstring
paramstringThe offending field, as a dotted path. Present when one field is at fault.
request_idrequiredstringAlso returned in X-Request-Id. Quote it in a support message and we can find exactly this request.

List

Fields

idrequiredstring
objectrequired"list"
namerequiredstring
descriptionrequiredstring | null
created_atrequiredstring
updated_atrequiredstring

MembershipChange

Fields

objectrequired"membership_change"
changedrequiredinteger

Order

Fields

idrequiredstring
objectrequired"order"
external_idrequiredstring
emailrequiredstring
contact_idrequiredstring | null
statusrequired"paid" | "refunded" | "partially_refunded" | "cancelled"
total_centsrequiredinteger
refunded_centsrequiredinteger
currencyrequiredstring
occurred_atrequiredstring
sourcerequiredstring | null
attributed_campaign_idrequiredstring | null
attributed_automation_idrequiredstring | null
attributed_node_idrequiredstring | null
attribution_rulerequiredstring | null
attributed_atrequiredstring | null
created_atrequiredstring
updated_atrequiredstring

Segment

Fields

idrequiredstring
objectrequired"segment"
namerequiredstring
descriptionrequiredstring | null
rulesrequiredobjectThe saved rule tree, in the grammar segmentRulesSchema defines. Pass it back unchanged to leave it alone.
versionrequiredinteger
matchrequired"all" | "any"
groupsrequiredany[]
last_countrequiredinteger | null
last_counted_atrequiredstring | null
created_atrequiredstring
updated_atrequiredstring

Tag

Fields

idrequiredstring
objectrequired"tag"
namerequiredstring
colorrequired"neutral" | "positive" | "warning" | "danger" | "info"
created_atrequiredstring
updated_atrequiredstring

Webhook

A webhook endpoint subscription (URL + events). Not the body we POST to your URL — that is WebhookEvent.

Fields

idrequiredstring
objectrequired"webhook"
urlrequiredstringThe HTTPS URL we POST events to.
descriptionrequiredstring | null
eventsrequired("email.delivered" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "contact.unsubscribed" | "campaign.finished")[]Dotted event names this endpoint is subscribed to.
statusrequired"enabled" | "disabled_by_user" | "disabled_by_failure"
disabled_reasonrequiredstring | null
consecutive_failuresrequiredinteger
last_success_atrequiredstring | null
last_failure_atrequiredstring | null
secretrequiredstring | nullSigning secret. Present only on the create/rotate response; null on every read afterwards.
created_atrequiredstring
updated_atrequiredstring

WebhookEvent

The JSON body we POST to your endpoint URL when a subscribed event happens. Includes the contact's email on message and opt-out events so you can match them to your own records. Not the same as the Webhook resource (the endpoint subscription).

Fields

idrequiredstringStable source-event id. Delivery is at-least-once — key your idempotency on this.
typerequired"email.delivered" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "contact.unsubscribed" | "campaign.finished"The dotted event name you subscribed to, e.g. email.opened.
occurred_atrequiredstringWhen the event happened, not when we delivered it.
organization_idrequiredstringYour organisation.
datarequiredobjectMessage-event fields. For contact.unsubscribed, data is {contact_id, email, campaign_id?}. For campaign.finished, data is {campaign_id, name, sent, failed, total} — no contact fields.
campaign_idrequiredstringThe campaign that sent the message.
contact_idrequiredstringOur id for the person.
emailrequiredstring | nullThe contact's address — match this to a contact in your system without calling the API back. Null only if the contact was deleted between the event and the emit.
message_recipient_idrequiredstringThis specific send of the message.
machinerequiredbooleanTrue when an open or click came from a scanner or link unfurler rather than a person. Always present on message events, including when false. Machine hits are excluded from every figure in the app.
link_urlstring | nullClicks only — the URL that was clicked.
bounce_typestring | nullBounces only — permanent, transient, or undetermined.
bounce_subtypestring | nullBounces only — provider subtype when available.
diagnostic_codestring | nullBounces only — SMTP diagnostic when available.
Example
{
  "id": "evt_01hxyz_email_opened",
  "type": "email.opened",
  "occurred_at": "2026-08-03T10:30:00.000Z",
  "organization_id": "org_01hxyz",
  "data": {
    "campaign_id": "cmp_01hxyz",
    "contact_id": "con_01hxyz",
    "email": "[email protected]",
    "message_recipient_id": "mr_01hxyz",
    "machine": false
  }
}

Everything here is generated from the schemas the API actually validates against. The machine-readable form is at /api/v1/openapi.json.