Skip to main content
The $lettr->audience() service manages everything campaigns send to: contact lists, the contacts themselves, subscription topics, custom properties, and dynamic segments. Each is a sub-service:
All five expose the same CRUD shape — list(), get(), create(), update(), delete() — with a few bulk and relationship helpers on contacts and lists.

Lists

A list is a static collection of contacts.

API Reference

GET /audience/lists

Contacts

A contact is an email address with optional custom properties, optionally attached to a list on creation.
Contact status is one of Subscribed, Unsubscribed, Bounced, Complained, or Unverified.

API Reference

GET /audience/contacts

Double opt-in

Pass a DoubleOptInConfig to send a confirmation email before the contact becomes subscribed:

Bulk create contacts

bulkCreate() takes up to 1000 contacts per request in one of two shapes. forEmails() builds the flat shape, where every address shares the batch-wide lists, properties and topics:
forContacts() addresses each contact individually. Row-level listIds and topics are applied on top of the batch-wide ones, and a row’s properties key overrides the batch-wide value for that key:
AudienceTopicSubscription::optOut() suppresses a topic for that contact in the same request. Useful when a topic’s default subscription is opt-out, which auto-subscribes newly created contacts — a row-level opt-out cancels that instead of needing a second call. A row-level opt-out also beats a batch-level opt-in.
updateExisting defaults to false, which leaves existing contacts’ properties alone (they are still attached to the requested lists). Set it to true to merge properties — submitted keys overwrite, absent keys are preserved — and to let an opt-out drop an existing subscription.

Handling the result

A call that doesn’t throw does not mean every row landed. Rows that fail validation are skipped and reported in errors while the rest of the batch commits — the API still returns 201. Always check hasErrors().
errorCode is a BulkAudienceContactErrorCode enum (or a plain string for a code added server-side): missing_email, invalid_email, invalid_property_value, unknown_property_key, unknown_list, unknown_topic, or invalid_topic_subscription.
alreadyExisted and updated overlap by design — “was the address already in the audience?” versus “did this request change the contact?” — so they don’t sum to the row count. A contact that already existed and got attached to a list is counted in both.

Bulk membership

$result->contactIds() from a bulkCreate() feeds straight into the bulk membership calls, so no id lookup is needed in between. Each processes every combination of contacts × lists (or topics), up to 1000 × 50:
Unsubscribing ignores pairs that don’t exist, so unsubscribed can be lower than totalPairs.

API Reference

POST /audience/contacts/bulk

Single relationships

API Reference

POST /audience/contacts//lists/

Topics

Topics are subscription categories contacts can opt in or out of (e.g. “Product updates”, “Promotions”).

API Reference

GET /audience/topics

Properties

Properties are typed custom fields stored on each contact.

API Reference

GET /audience/properties

Segments

A segment is a dynamic group defined by conditions over contact fields and properties. Conditions are grouped — conditions within a group are AND-ed, and groups are OR-ed together.
Operators include Equals, NotEquals, Contains, StartsWith, EndsWith, GreaterThan, LessThan, Before, After, IsTrue, IsFalse, and their negations.

API Reference

GET /audience/segments

What’s Next

Campaigns

Send to your audience

API Reference

Full audience API reference