Audiences

Audiences are the recipient lists for newsletters. These endpoints let you sync an audience programmatically, for example by wiring your own signup form or app to it. Adds are single opt-in and run the same hygiene as an import: invalid and role addresses are rejected, and anyone suppressed or unsubscribed is skipped. Each add returns a per-row outcome and never reveals why an address was skipped.

Last updated

The audience object

{ "object": "audience", "id": "aud_abc123", "name": "Newsletter", "description": null, "member_count": 1240, "subscribed_count": 1198, "consent_source": "Website signup form", "created_at": "2026-07-02T10:00:00.000Z", "updated_at": "2026-07-02T10:00:00.000Z" }
FieldTypeDescription
namestringAudience name, up to 200 characters.
member_countintegerSubscribers of any status.
subscribed_countintegerSubscribers currently receiving newsletters.
consent_sourcestringWhere and how these people opted in.

The subscriber object

{ "object": "subscriber", "id": "audmem_abc123", "audience_id": "aud_abc123", "email_address": "jane@example.com", "display_name": "Jane Doe", "status": "subscribed", "merge_fields": { "plan": "pro" }, "consent_source": "Website signup form", "created_at": "2026-07-02T10:00:00.000Z", "updated_at": "2026-07-02T10:00:00.000Z" }

status is one of subscribed, unsubscribed, bounced, complained, suppressed, or transactional_only. merge_fields holds up to 50 string, number, boolean, or null values keyed by field name.

Create an audience

POST /v1/audiences

Scope: audiences:write. Body: { name, description?, consent_source }. consent_source is a required attestation of where and how these people opted in. Returns the audience object with a 201.

List, get, update, and delete audiences

GET /v1/audiences GET /v1/audiences/:id PATCH /v1/audiences/:id DELETE /v1/audiences/:id

List supports cursor and limit pagination. Update accepts { name?, description? }. Delete returns 204 and removes the audience's subscribers; newsletters you already sent keep their history.

Add a subscriber

POST /v1/audiences/:id/subscribers

Scope: audiences:write. This is the endpoint your signup form calls. Body:

{ "email_address": "jane@example.com", "display_name": "Jane Doe", "merge_fields": { "plan": "pro" } }

Returns a per-row outcome rather than the subscriber, so a suppressed or invalid address never errors the request:

{ "email_address": "jane@example.com", "outcome": "created" }

outcome is one of created, updated, skipped_not_mailable, skipped_invalid, skipped_cap, or skipped_quota. The returned email_address is the normalized (trimmed, lowercased) form of what you sent.

Re-adding an existing subscriber merges instead of overwriting: a provided display_name replaces the stored one (omitting it keeps it), merge_fields keys you send are merged into the stored object, and consent is re-attested. To replace fields wholesale, use the update endpoint below.

Add subscribers in bulk

POST /v1/audiences/:id/subscribers/batch

Add up to 1000 subscribers in one call. Body: { subscribers: [ ... ] } where each entry has the same shape as a single add. Returns { results: [ ... ] } with one outcome per row, in order. Request bodies are capped at 1 MB, so very large merge_fields payloads may need smaller batches.

Limits

Each audience holds up to 10,000 subscribed members. Net-new adds also count against a monthly ingest quota: 5,000 on Solo, 25,000 on Pro, and 100,000 on Team. Re-adds of existing subscribers are free. Adds over the cap return skipped_cap; adds over the quota return skipped_quota.

Quota admission is per call: if the remaining quota cannot admit every net-new address in a batch, the whole batch of net-new addresses is returned as skipped_quota. Retry with a smaller batch to use what remains. Audience ingest is not available during the free trial, so every net-new add returns skipped_quota until the trial converts.

List and look up subscribers

GET /v1/audiences/:id/subscribers GET /v1/audiences/:id/subscribers/:subscriber_id GET /v1/audiences/:id/subscribers/by-email/:email

List supports cursor, limit, a status filter, and an exact email filter. The by-email lookup expects a URL-encoded address.

Update, unsubscribe, and remove

PATCH /v1/audiences/:id/subscribers/:subscriber_id POST /v1/audiences/:id/subscribers/:subscriber_id/unsubscribe DELETE /v1/audiences/:id/subscribers/:subscriber_id

Update accepts { display_name?, merge_fields? }. Unsubscribe writes an organization-wide opt-out so future newsletters skip the address, and returns the updated subscriber. Delete returns 204; prefer unsubscribe to preserve opt-out history.