Skip to content

Lists

A list is a group of contacts you can target with a campaign. Each campaign points to exactly one list, and a list can contain any number of active contacts. Lists are independent of each other: a contact can belong to multiple lists at the same time, and removing them from one list does not affect them in others or delete them from the system.

FieldTypeDescription
idstringSlug identifier for the list.
namestringDescriptive name.
key_idstringAPI key the list belongs to.
contact_countintegerNumber of contacts in the list.
sendable_countintegerHow many can be sent to: active and, if the list requires confirmation, already confirmed.
pending_countintegerActive but pending confirmation (double opt-in lists only).
healthinteger | nullList health, 0-100. null if the list is empty.
deliverable_pctinteger | null% of the list that can receive: active and not suppressed.
suppressed_pctinteger | null% of the list with a live suppression on your account.
engaged_pctinteger | null% that opened, out of those who received in the last 90 days. null if nobody received anything in the window.
sent_windowintegerHow many contacts of the list received something in the last 90 days.
created_atstringCreation date (ISO 8601).

Every list carries a 0-100 score that combines deliverability (60%) and engagement (40%). Deliverability weighs more because it is the one that costs you reputation: sending to addresses that don’t exist or that already complained is what makes your mail start landing in spam.

Suppressed is not the same as unsubscribed. sendable_count looks at the contact’s status; suppressed_pct looks at your account’s suppressions, which include hard bounces, complaints and whatever you imported from another provider. That’s why a list can say “1,000 sendable” and have 200 that will never receive — that gap is what the score makes visible.

Two things the score deliberately does not do:

  • If nobody received anything in the last 90 days, engaged_pct is null, not 0. A list that isn’t used isn’t sick: there’s no data. The score is then computed from deliverability alone and the panel shows “no sends”. What you want to catch is the stale list that is still being used.
  • An empty list does not score 100. It scores nothing (null): there is nothing to measure.

Engagement is measured with human opens. Apple Mail Privacy Protection preloads and corporate scanners fetch the pixel as soon as the mail arrives, with nobody reading it, and counting those would inflate the number precisely on the worst lists.

SignalWhat it meansWhat to do
High suppressed_pctA good share of the list can no longer receiveClean the list: those contacts only dilute your metrics
Low engaged_pct with recent sendsThey still receive you but don’t read youRe-engagement campaign, and lower the frequency — see campaigns
engaged_pct is nullThe list hasn’t been used in 90 daysIf you’re reactivating it, start with a re-confirmation instead of blasting it
GET /v1/bulk/lists

Returns an array with all lists in your account, including the contact_count for each one.


POST /v1/bulk/lists

Body:

{ "name": "Newsletter Q3 2026" }

Returns 201 with the created list, including its automatically generated id.


GET /v1/bulk/lists/{id}

Returns the list details along with its paginated contacts.

Query parameters:

ParameterDescription
limitMaximum number of contacts to return.
offsetOffset for pagination.
statusFilter contacts by status.

PATCH /v1/bulk/lists/{id}

Body:

{ "name": "Newsletter Q4 2026" }

DELETE /v1/bulk/lists/{id}

Deletes the list. Returns 204 No Content. If the list is referenced by an active campaign, returns 409 Conflict.


POST /v1/bulk/lists/{id}/contacts

Body:

{ "emails": ["ana@empresa.com", "pedro@cliente.io"] }

The emails must correspond to contacts that already exist in your account. Returns 200 with the number of contacts added.


DELETE /v1/bulk/lists/{id}/contacts/{email}

Removes the contact from this list. Returns 204 No Content. The contact continues to exist in the system and in any other list it belongs to.


POST /v1/bulk/lists/{id}/duplicate

Creates a copy of the list with all its contacts. Useful for creating derived segments without starting from scratch. Returns 201 with the new list.


POST /v1/bulk/lists/delete

Atomic deletion of multiple lists. Body:

{ "ids": ["newsletter-q3-abc123", "promo-verano-xyz"] }

Response:

{
"requested": 2,
"deleted": 1,
"not_found": [],
"forbidden": [],
"in_use": ["promo-verano-xyz"]
}

Lists referenced by a campaign are reported in in_use and are not deleted. The remaining ones are deleted, even within the same request.

Every list can have a public form where people subscribe themselves. It’s what you point an ad at, or what you embed on your site.

Check the status

GET /v1/bulk/lists/{id}/signup-form

Enable or reconfigure

PUT /v1/bulk/lists/{id}/signup-form

Optional body:

FieldTypeDescription
tagsarrayTags applied to everyone who comes in through this form. Useful for knowing which ad each person came from.
redirect_urlstringWhere to send them after subscribing. Empty = our thank-you page.
regeneratebooleanRotates the form’s token.

The response carries:

FieldDescription
activoWhether the form is accepting sign-ups.
urlPage hosted by us, ready to use.
snippetReady-to-paste HTML for your own site.
tokenThe form’s public identifier.
doble_optinWhether this list requires confirmation.

Turn it off

DELETE /v1/bulk/lists/{id}/signup-form

A sign-up through this form does fire sequences with list_join, unlike a bulk import. See the Ad leads — from the dashboard guide.

You can require contacts to confirm their subscription before receiving campaigns from a list — it protects your sending reputation and is the standard (Mailchimp-style) way to record explicit consent.

PUT /v1/bulk/lists/{id}/confirmation

Body:

{
"require_confirmation": true,
"confirm_from_email": "noreply@tuempresa.com",
"confirm_from_name": "Your Company",
"confirm_subject": "Confirm your subscription",
"confirm_intro": "Thanks for subscribing. Confirm your email to start receiving our emails."
}

confirm_from_email must belong to a verified domain on your account (same rule as a campaign’s from). Turning on require_confirmation for a list that already has members automatically marks those existing members as confirmed (they aren’t asked to confirm retroactively) — only contacts you add after that go through the confirmation flow.

While a list requires confirmation, every new contact added via POST /v1/bulk/lists/{id}/contacts automatically receives an email with a one-click confirmation link (public endpoint GET /confirm-subscription?token=...). A contact who hasn’t confirmed stays in a pending state and is excluded from campaign sends to that list until they confirm.


POST /v1/bulk/lists/{id}/contacts/{email}/resend-confirmation

Resends the confirmation email. Returns 400 if the list doesn’t require confirmation, and 429 if you already resent it less than 5 minutes ago (anti mail-bomb protection).

{ "resent": true }
Ventana de terminal
# 1. Create the list
curl -X POST https://api.mailerdash.com/v1/bulk/lists \
-H "Authorization: Bearer $MAILERDASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Newsletter Q3 2026"}'
# 2. Add contacts (use emails already registered as contacts)
curl -X POST https://api.mailerdash.com/v1/bulk/lists/newsletter-q3-2026-abc123/contacts \
-H "Authorization: Bearer $MAILERDASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"emails": ["ana@empresa.com", "pedro@cliente.io"]}'

For the full request/response schema and error codes, see the bulk API reference.