Skip to main content
The client.audience service manages everything campaigns send to. Each kind is a sub-service:

Contacts

The list filter uses AudienceContactStatus (Subscribed, Unsubscribed, Bounced, Complained, Unverified), while updates use the narrower UpdateAudienceContactStatus (Subscribed, Unsubscribed).

API Reference

GET /audience/contacts

Double opt-in

Pass a DoubleOptInConfig to create the contact as unverified and send a confirmation email — they become subscribed after clicking the link:

Bulk create contacts

bulk_create() takes up to 1000 contacts per request in one of two shapes. BulkCreateAudienceContactsOptions::new() takes a flat list of addresses that all share the batch-wide lists, properties and topics:
::for_contacts() addresses each contact individually. Row-level list ids and topics are applied on top of the batch-wide ones, and a row’s property key overrides the batch-wide value for that key:
AudienceTopicSubscription::opt_out() 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.
with_update_existing(false) is the default: existing contacts keep their properties (they are still attached to the requested lists). Pass true to merge properties — submitted keys overwrite, absent keys are preserved. It governs properties only: a row-level opt-out drops an existing subscription either way.

Handling the result

An Ok result 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 has_errors().
error_code is a BulkAudienceContactErrorCode: missing_email, invalid_email, invalid_property_value, unknown_property_key, unknown_list, unknown_topic, or invalid_topic_subscription.
already_existed 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.contact_ids() from a bulk_create() feeds straight into the bulk membership calls, so no id lookup is needed in between:
Both topic calls process every contact_ids × topic_ids combination, up to 1000 contacts × 50 topics. Unsubscribing ignores pairs that don’t exist, so unsubscribed can be lower than total_pairs.
bulk_unsubscribe_from_topics() and bulk_detach_from_lists() issue a DELETE with a request body. reqwest handles that, but a proxy in front of your app may not.

API Reference

POST /audience/contacts/bulk

Lists

API Reference

GET /audience/lists

Segments

A segment is a dynamic group defined by conditions. Groups are joined by OR; conditions within a group by AND.
Use SegmentCondition::unary(field, op) for value-less operators like SegmentOperator::IsTrue and SegmentOperator::IsFalse.

API Reference

GET /audience/segments

Topics

API Reference

GET /audience/topics

Properties

Custom contact properties have an immutable name and type; only the fallback can be updated.

API Reference

GET /audience/properties

What’s Next

Campaigns

Send to your audience

API Reference

Full audience API reference