Mailzzy

Public API

Get an API key
Getting Started

Mailzzy Public API

v1.0

The Mailzzy public API is a JSON REST API authenticated with an API key.

Use it to manage contacts, lists and tags, list campaigns, add contacts to automations, send transactional email, and subscribe to webhooks. This reference covers the API behind the Mailzzy app for Zapier.

Looking for the client-credentials API or the MCP server? See the developer docs.

Base URL

All requests go to this base URL; every path in this reference is relative to it. Requests and responses are JSON, over HTTPS.

Base URL
https://services.softsages.com/crm/api/v1/mailzzy

Authentication

Create a key in Mailzzy under Settings › Client Credentials › Public API & Zapier keys (admins only) and send it in the X-API-Key header on every request:

code
curl https://services.softsages.com/crm/api/v1/mailzzy/me \
  -H "X-API-Key: sk_live_kid_XXXXXXXXXXXXXXXX.YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"

The full key is shown only once, when it is created. A key acts as the user who created it and stops working when it expires, is revoked, or that user is deactivated. Revocation takes effect within about 30 seconds.

Quickstart

1. Check your key. GET /me returns the key and the user it belongs to.

cURL
curl https://services.softsages.com/crm/api/v1/mailzzy/me \
  -H "X-API-Key: <your API key>"

2. Find a list to add contacts to. GET /lists returns your lists (called Groups in the Mailzzy app).

cURL
curl https://services.softsages.com/crm/api/v1/mailzzy/lists \
  -H "X-API-Key: <your API key>"

3. Create or update a contact. POST /contacts creates the contact, or updates the one with that email.

cURL
curl --request POST https://services.softsages.com/crm/api/v1/mailzzy/contacts \
  -H "X-API-Key: <your API key>" \
  -H "Content-Type: application/json" \
  --data '{"email":"ada@example.com","first_name":"Ada","last_name":"Lovelace","list_ids":[12],"tags":["vip"]}'

4. Get notified. POST /webhooks subscribes an HTTPS URL to an event; Mailzzy posts the event to it.

cURL
curl --request POST https://services.softsages.com/crm/api/v1/mailzzy/webhooks \
  -H "X-API-Key: <your API key>" \
  -H "Content-Type: application/json" \
  --data '{"target_url":"https://example.com/mailzzy/webhooks","event_type":"contact.added_to_list","filters":{"list_id":12}}'
Core Concepts

Errors

Every error has the same body, with the HTTP status repeated in code:

json
{ "code": 422, "message": "This contact is blacklisted." }
StatusMeaning
400The request is malformed (missing field, bad limit, bad since, bad cursor).
401The API key is missing, invalid, expired or revoked.
404The resource does not exist or belongs to another account.
409Conflict: a list with that name exists, or an Idempotency-Key was reused with a different body or while the first request is still running.
422The request is well-formed but was refused (blacklisted contact, plan contact limit reached, invalid phone number...).
429Rate limit exceeded.
503Temporarily unavailable; retry after a short wait.

Rate limits

Each key may make about 120 requests per minute (counted per API server, so short bursts above that can pass). Above the limit the API answers 429 with a Retry-After: 60 header.

Pagination

List endpoints return { "data": [...], "next_cursor": "..." }. Pass next_cursor back as cursor to get the next page; it is null on the last page. limit is 1–100 (default 50). Cursors are opaque.

Timestamps

Responses use ISO-8601 with an offset, e.g. 2026-10-05T10:00:00-04:00. The since parameter accepts ISO-8601 with an offset or Z, a date-time without offset (read as UTC), or a plain date.

Idempotency

POST /contacts, POST /lists and POST /transactional-emails accept an Idempotency-Key header (up to 255 characters). Repeating a request with the same key and the same body within 24 hours returns the first response (with Idempotent-Replayed: true) instead of running it again. Use it for retries, especially for transactional email.

Subscription status

Creating or updating a contact never changes its subscription status. A contact who unsubscribed stays unsubscribed: creating or updating it again does not resubscribe it.

Webhooks

Webhooks

Subscribe an HTTPS URL to an event type with POST /webhooks and Mailzzy will POST a JSON event to it whenever that happens — from any source: the Mailzzy app, this API, CSV imports, forms, automations and email activity. The events are listed in the event catalog below.

Every delivery has these headers:

HeaderMeaning
Mailzzy-EventThe event type, e.g. contact.added_to_list
Mailzzy-Event-IdUnique per event; the same on retries — use it to ignore duplicates
Mailzzy-Delivery-IdUnique per delivery attempt chain
Mailzzy-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + "." + body)>

Event catalog

EventWhen it is sent
contact.createdA contact was added (app, API, form or CSV import). Filter: list_id.
contact.updatedA contact's profile fields changed.
contact.unsubscribedA contact unsubscribed; data.source is api, app or link. Filter: campaign_id.
contact.added_to_listA contact was added to a list; data.list says which. Filter: list_id.
contact.removed_from_listA contact was removed from a list. Filter: list_id.
contact.tag_addedA tag was newly added to a contact; data.tag says which. Filter: tag.
form.submittedA sign-up form was submitted; data.fields has the values. Filter: form_id.
campaign.sentA campaign finished sending. Filter: campaign_id.
email.openedA contact opened a campaign email for the first time. Filter: campaign_id.
email.clickedA contact clicked a link in a campaign email for the first time; data.url says which. Filter: campaign_id.
email.bouncedA campaign email hard-bounced. Filter: campaign_id.
contact.tag_removedA tag was removed from a contact; data.tag says which. Filter: tag.
contact.resubscribedA contact that was unsubscribed (or bounced or marked spam) was re-subscribed.
contact.deletedA contact was deleted (archived); data.contact has only id and email.
automation.completedA contact completed an automation; data.automation says which. Filter: automation_id.

Every event has the same envelope; data depends on the event type. An example contact.created body:

Event body
{
  "id": "evt_3eb39a9eafed4ccc9d91a35506fffeae",
  "type": "contact.created",
  "api_version": "2026-10-01",
  "created_at": "2026-10-05T10:00:00-04:00",
  "account": "acme",
  "data": {
    "contact": {
      "id": 123,
      "email": "ada@example.com",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "phone": "+14155550100",
      "address": "12 Example Street",
      "city": "London",
      "state": "England",
      "postal_code": "NW1 2DB",
      "country": "GB",
      "timezone": "Europe/London",
      "status": "subscribed",
      "tags": [
        "vip"
      ],
      "source": "manual",
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  }
}

Verifying signatures

Verify every request: compute HMAC-SHA256 of t + "." + <raw request body> with your webhook secret, compare it in constant time to v1, and reject requests whose t is more than 5 minutes old.

js
// Node.js (Express: use express.raw({ type: "application/json" }) so you get the raw body)
const crypto = require("crypto");
function verify(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 || ""));
}
python
# Python
import hmac, hashlib, time
def verify(secret, header, raw_body: bytes):
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    expected = hmac.new(secret.encode(), parts["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Test vector: secret whsec_test, t=1700000000, body {"id":"evt_1"} → v1=c89214b5b5da833daed6f0b8c5bb6bd58cea9022bd80ccc78230f3942d632925.

Deliveries and retries

Respond with any 2xx within 10 seconds. Anything else (including timeouts, redirects and HTML pages) is retried after about 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h — 8 attempts in total — and then marked failed. Answer 410 Gone to stop a webhook immediately. After 20 failed deliveries in a row with no success for 24 hours, the webhook is paused and its creator is emailed. With Zapier, turn the Zap off and on again to start a new webhook.

Events are delivered at least once and not necessarily in order. email.opened fires on a contact's first open of a campaign and email.clicked on their first click of each link. A CSV import sends per-contact events for its first 5,000 contacts only.

Account

The API key and the user it belongs to.

Who this key belongs to

GET/me
API Key

Use it to test a key. Zapier uses it as the connection test.

Responses

200

OK

The key and its owner.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/me \
  --header 'X-API-Key: <your API key>'
{
  "account": "acme",
  "app": "mailzzy",
  "user": {
    "email": "string",
    "name": "Newsletter"
  },
  "key": {
    "id": "kid_AbCdEf123456",
    "name": "Newsletter",
    "rate_limit_per_min": 120,
    "expires_on": "2026-10-05T10:00:00-04:00"
  },
  "capabilities": [
    "string"
  ]
}
Contacts

Create, update, find, unsubscribe and archive contacts; manage their lists, tags, notes and automations.

List contacts, or find one by email

GET/contacts
API Key

Contacts are returned newest first. Archived (deleted) contacts are never returned. With email, returns at most one contact (an empty data array when there is none) and ignores the other parameters.

Query Parameters

emailstring (email)optional

Find the contact with exactly this email (case-insensitive).

statusContactStatus (enum)optional

One of: subscribed, unsubscribed, bounced, spam.

list_idinteger (int64)optional

Only members of this list.

sincestringoptional

Only contacts created or updated at or after this time.

e.g. 2026-10-05T10:00:00Z

cursorstringoptional

The next_cursor from the previous page.

limitintegeroptional

Default 50. 1–100.

Responses

200

OK

A page of contacts.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "email": "ada@example.com",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "phone": "+14155550100",
      "address": "12 Example Street",
      "city": "London",
      "state": "England",
      "postal_code": "NW1 2DB",
      "country": "GB",
      "timezone": "Europe/London",
      "status": "subscribed",
      "tags": [
        "vip"
      ],
      "source": "manual",
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  ],
  "next_cursor": null
}

Create or update a contact by email

POST/contacts
API Key

If no contact has this email, it is created as subscribed and added to list_ids, subject to the same checks as adding a contact in Mailzzy (valid email, not blacklisted, plan contact limit).

If a contact with this email exists, the fields you send are updated (fields you omit are kept), the contact is added to any of list_ids it is not already in, and tags are added. Its subscription status is not changed, and an unsubscribed, bounced or spam contact is not added to any list.

Adding a contact to a list starts any "added to list" automations, as in Mailzzy.

Headers

Idempotency-Keystringoptional

Makes retries safe for 24 hours. X-Idempotency-Key is also accepted. Up to 255 characters.

Request Body · application/json

first_namestringoptional
last_namestringoptional
phonestringoptional
addressstringoptional
citystringoptional
statestringoptional
postal_codestringoptional
countrystringoptional
timezonestringoptional
tagsarray of stringoptional
emailstring (email)required
list_idsarray of integer (int64)required

Responses

200

OK

An existing contact was updated.

201

Created

The contact was created.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "list_ids": [
    12
  ],
  "tags": [
    "vip"
  ]
}'
Body
{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "list_ids": [
    12
  ],
  "tags": [
    "vip"
  ]
}
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

Delete (archive) a contact

DELETE/contacts/{id}
API Key

Archives the contact, as deleting it in Mailzzy does: it is removed from its lists and tags and no longer returned by the API. Fires contact.deleted. Needs the contact delete permission.

Path Parameters

idintegerrequired

Responses

200

OK

The contact was archived.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request DELETE \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123 \
  --header 'X-API-Key: <your API key>'
{
  "id": 123,
  "status": "archived"
}

Add a note to a contact

POST/contacts/{id}/notes
API Key

Path Parameters

idintegerrequired

Headers

Idempotency-Keystringoptional

Makes retries safe for 24 hours. X-Idempotency-Key is also accepted. Up to 255 characters.

Request Body · application/json

notestringrequired

Trimmed; 1 to 10,000 characters. Up to 10000 characters.

Responses

201

Created

The note was added.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/notes \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "note": "Called about the renewal."
}'
Body
{
  "note": "Called about the renewal."
}
{
  "id": 123,
  "contact_id": 123,
  "note": "string",
  "created_at": "2026-10-05T10:00:00-04:00"
}

Unsubscribe a contact

POST/contacts/{id}/unsubscribe
API Key

Has no effect on a contact that is not subscribed. The change is applied asynchronously.

Path Parameters

idintegerrequired

Responses

200

OK

The contact, shown as unsubscribed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/unsubscribe \
  --header 'X-API-Key: <your API key>'
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

Add a contact to a list

POST/contacts/{id}/lists/{listId}
API Key

Does nothing if the contact is already in the list. Starts "added to list" automations. An unsubscribed, bounced or spam contact, or a blacklisted email, is refused with 422.

Path Parameters

idintegerrequired
listIdinteger (int64)required

Responses

200

OK

The contact.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/lists/12 \
  --header 'X-API-Key: <your API key>'
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

Remove a contact from a list

DELETE/contacts/{id}/lists/{listId}
API Key

Does nothing if the contact is not in the list. Starts "removed from list" automations.

Path Parameters

idintegerrequired
listIdinteger (int64)required

Responses

200

OK

The contact.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request DELETE \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/lists/12 \
  --header 'X-API-Key: <your API key>'
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

Add tags to a contact

POST/contacts/{id}/tags
API Key

Tags are lower-cased; tags that don't exist yet are created.

Path Parameters

idintegerrequired

Request Body · application/json

tagsarray of stringrequired

Responses

200

OK

The contact.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/tags \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "tags": [
    "vip",
    "webinar-2026"
  ]
}'
Body
{
  "tags": [
    "vip",
    "webinar-2026"
  ]
}
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

Remove a tag from a contact

DELETE/contacts/{id}/tags/{tag}
API Key

Path Parameters

idintegerrequired
tagstringrequired

Responses

200

OK

The contact.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request DELETE \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/tags/vip \
  --header 'X-API-Key: <your API key>'
{
  "id": 123,
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": "+14155550100",
  "address": "12 Example Street",
  "city": "London",
  "state": "England",
  "postal_code": "NW1 2DB",
  "country": "GB",
  "timezone": "Europe/London",
  "status": "subscribed",
  "tags": [
    "vip"
  ],
  "source": "manual",
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}
Lists and tags

Contact lists (Groups in the Mailzzy app) and tags.

List contact lists

GET/lists
API Key

All lists, alphabetical, in one page (next_cursor is always null).

Responses

200

OK

The lists.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/lists \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "member_count": 123,
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  ],
  "next_cursor": null
}

Create a contact list

POST/lists
API Key

Headers

Idempotency-Keystringoptional

Makes retries safe for 24 hours. X-Idempotency-Key is also accepted. Up to 255 characters.

Request Body · application/json

namestringrequired

Up to 100 characters.

Responses

201

Created

The new list.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/lists \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Newsletter"
}'
Body
{
  "name": "Newsletter"
}
{
  "id": 123,
  "name": "Newsletter",
  "member_count": 123,
  "created_at": "2026-10-05T10:00:00-04:00",
  "updated_at": "2026-10-05T10:00:00-04:00"
}

List tags

GET/tags
API Key

All tags, alphabetical, in one page.

Responses

200

OK

The tags.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/tags \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "member_count": 123,
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  ],
  "next_cursor": null
}
Automations

List automations and add contacts to them.

Add a contact to an automation

POST/contacts/{id}/automations/{automationId}
API Key

Enrols the contact in an Active automation that uses the Contact added manually trigger (list them with GET /automations?trigger=manually_added). The contact then runs through the automation asynchronously. 422 when the automation is not active or does not use that trigger, or when the contact can't enter it (its re-entry setting, or the automation's entry conditions).

Path Parameters

idintegerrequired
automationIdintegerrequired

Headers

Idempotency-Keystringoptional

Makes retries safe for 24 hours. X-Idempotency-Key is also accepted. Up to 255 characters.

Responses

202

Accepted

The contact was enrolled.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/contacts/123/automations/7 \
  --header 'X-API-Key: <your API key>'
{
  "status": "enrolled",
  "contact_id": 123,
  "automation_id": 123
}

List active automations

GET/automations
API Key

All Active automations, by name. trigger=manually_added returns only those a contact can be added to.

Query Parameters

triggerstringoptional

One of: manually_added.

Responses

200

OK

The automations (one page; next_cursor is always null).

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/automations \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "status": "active",
      "trigger": null
    }
  ],
  "next_cursor": null
}
Campaigns

List campaigns.

List campaigns

GET/campaigns
API Key

Query Parameters

statusstringoptional

Only campaigns in this status. Omit for all. One of: submitted, in_review, in_progress, completed, rejected, failed, draft, ab_test_waiting.

cursorstringoptional

The next_cursor from the previous page.

limitintegeroptional

Default 50. 1–100.

Responses

200

OK

A page of campaigns.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/campaigns \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "subject": "Welcome to Mailzzy",
      "status": null,
      "type": null,
      "sender_email": null,
      "scheduled_at": "2026-10-05T10:00:00-04:00",
      "completed_at": "string",
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00",
      "metrics": {
        "requested": 123,
        "sent": 123,
        "delivered": 123,
        "opened": 123,
        "clicked": 123,
        "unsubscribed": 123,
        "bounced": 123
      }
    }
  ],
  "next_cursor": null
}
Content

Email templates, sign-up forms and sending domains.

List email templates

GET/templates
API Key

Most recently updated first.

Query Parameters

cursorstringoptional

The next_cursor from the previous page.

limitintegeroptional

Default 50. 1–100.

Responses

200

OK

A page of templates.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/templates \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "category": null,
      "subject": "Welcome to Mailzzy",
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  ],
  "next_cursor": null
}

List sign-up forms

GET/forms
API Key

Query Parameters

cursorstringoptional

The next_cursor from the previous page.

limitintegeroptional

Default 50. 1–100.

Responses

200

OK

A page of forms.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/forms \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": 123,
      "name": "Newsletter",
      "status": null,
      "type": null,
      "opt_in_mode": null,
      "public_url": null,
      "views": 123,
      "submissions": 123,
      "created_at": "2026-10-05T10:00:00-04:00",
      "updated_at": "2026-10-05T10:00:00-04:00"
    }
  ],
  "next_cursor": null
}
Transactional email

Send one-off emails to a single recipient.

List verified sending domains

GET/domains
API Key

The account's verified, active sending domains. Pass one as domain when sending a transactional email.

Responses

200

OK

All verified sending domains (not paged).

401

Unauthorized

The API key is missing, invalid, expired or revoked.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request GET \
  --url https://services.softsages.com/crm/api/v1/mailzzy/domains \
  --header 'X-API-Key: <your API key>'
{
  "data": [
    {
      "id": "acme.com",
      "name": "acme.com"
    }
  ],
  "next_cursor": null
}

Send a transactional email

POST/transactional-emails
API Key

Sends a one-off email, such as a receipt or a password reset, to a single recipient. from must be one of your verified senders. The email is queued and sent asynchronously and counts toward your plan's transactional email allowance. Always send an Idempotency-Key so a retry cannot send the email twice.

Headers

Idempotency-Keystringoptional

Makes retries safe for 24 hours. X-Idempotency-Key is also accepted. Up to 255 characters.

Request Body · application/json

tostring (email)required

The single recipient.

fromstring (email)required

A verified sender email of your account.

subjectstringoptional

Required with html; with template_id, defaults to the template's subject.

htmlstringoptional

The HTML body. Not allowed together with template_id.

template_idintegeroptional

Send a saved email template (see GET /templates) instead of html.

variablesobjectoptional

Values for {{KEY}} tokens in the subject and HTML ({{ first_name }} and {{FIRST_NAME}} both match the key first_name). Values are HTML-escaped in the body, not in the subject; tokens without a value are left unchanged.

reply_tostring (email)optional
domainstringoptional

Sending domain (an active domain of your account). Defaults to the domain of from.

Responses

202

Accepted

The email was accepted for delivery.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

429

Too Many Requests

Rate limit exceeded.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/transactional-emails \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "to": "ada@example.com",
  "from": "orders@yourcompany.com",
  "subject": "Your receipt",
  "html": "<p>Thanks for your order!</p>",
  "reply_to": "support@example.com"
}'
Body
{
  "to": "ada@example.com",
  "from": "orders@yourcompany.com",
  "subject": "Your receipt",
  "html": "<p>Thanks for your order!</p>",
  "reply_to": "support@example.com"
}
{
  "status": "accepted",
  "message": null
}
Manage webhooks

Subscribe a URL to an event, and remove the subscription.

Create a webhook

POST/webhooks
API Key

Subscribes an HTTPS URL to one event type. The response contains the signing secret — the only time it is shown. Up to 25 webhooks per account. The URL must be public HTTPS (port 443 or 1024+).

Request Body · application/json

target_urlstring (uri)required

Up to 2048 characters.

event_typeWebhookEventType (enum)required

One of: contact.created, contact.updated, contact.unsubscribed, contact.added_to_list, contact.removed_from_list, contact.tag_added, contact.tag_removed, contact.resubscribed, contact.deleted, form.submitted, campaign.sent, email.opened, email.clicked, email.bounced, automation.completed.

filtersWebhookFiltersoptional

Optional; only events with these values are sent. Supported keys depend on the event type (see the event catalog).

Responses

201

Created

The webhook, with its secret.

400

Bad Request

The request is malformed.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

409

Conflict

Conflict.

422

Unprocessable Entity

The request was refused.

Request
curl --request POST \
  --url https://services.softsages.com/crm/api/v1/mailzzy/webhooks \
  --header 'X-API-Key: <your API key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "target_url": "https://example.com/mailzzy/webhooks",
  "event_type": "contact.added_to_list",
  "filters": {
    "list_id": 12
  }
}'
Body
{
  "target_url": "https://example.com/mailzzy/webhooks",
  "event_type": "contact.added_to_list",
  "filters": {
    "list_id": 12
  }
}
{
  "id": "whk_3f2c...",
  "event_type": "contact.created",
  "target_url": "string",
  "filters": {
    "list_id": 123,
    "form_id": 123,
    "campaign_id": 123,
    "tag": "vip",
    "automation_id": 123
  },
  "status": "active",
  "paused_reason": null,
  "consecutive_failures": 123,
  "last_success_at": "2026-10-05T10:00:00-04:00",
  "last_failure_at": "2026-10-05T10:00:00-04:00",
  "created_at": "2026-10-05T10:00:00-04:00",
  "secret": "whsec_9f8e...",
  "secret_note": "string"
}

Delete a webhook

DELETE/webhooks/{webhookId}
API Key

Also removes its delivery history.

Path Parameters

webhookIdstringrequired

Responses

204

No Content

Deleted.

401

Unauthorized

The API key is missing, invalid, expired or revoked.

404

Not Found

Not found, or not visible to this key.

Request
curl --request DELETE \
  --url https://services.softsages.com/crm/api/v1/mailzzy/webhooks/whk_123 \
  --header 'X-API-Key: <your API key>'
// No response body

© 2026 Mailzzy. All rights reserved.

Back to mailzzy.comContact usPrivacy PolicyTerms of Use