> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lettr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Audience

> Manage audience contacts, lists, subscription topics, custom properties, and dynamic segments with the Lettr Rust SDK.

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

```rust theme={null}
use lettr::Lettr;

let client = Lettr::new("your-api-key");

client.audience.contacts;    // individual contacts
client.audience.lists;       // contact lists
client.audience.topics;      // subscription topics
client.audience.properties;  // custom contact properties
client.audience.segments;    // dynamic segments
```

## Contacts

```rust theme={null}
use std::collections::HashMap;
use lettr::audience::contacts::{
    CreateAudienceContactOptions, ListAudienceContactsOptions, UpdateAudienceContactOptions,
    AudienceContactStatus, UpdateAudienceContactStatus,
};

// Create (optionally attach to a list and set properties)
let options = CreateAudienceContactOptions::new("jane@example.com")
    .with_list_id("list-uuid")
    .with_properties(HashMap::from([
        ("first_name".to_string(), "Jane".to_string()),
        ("plan".to_string(), "pro".to_string()),
    ]));
let contact = client.audience.contacts.create(options).await?;
println!("{} {} {:?}", contact.id, contact.email, contact.status);

// List with filters
let page = client.audience.contacts.list(
    ListAudienceContactsOptions::new()
        .page(1)
        .per_page(50)
        .search("jane")
        .status(AudienceContactStatus::Subscribed)
        .list_id("list-uuid"),
).await?;

// Get, update, delete
client.audience.contacts.get("contact-uuid").await?;
client.audience.contacts.update(
    "contact-uuid",
    UpdateAudienceContactOptions::new().with_status(UpdateAudienceContactStatus::Unsubscribed),
).await?;
client.audience.contacts.delete("contact-uuid").await?;
```

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

<Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-contacts">
  GET /audience/contacts
</Card>

### Double opt-in

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

```rust theme={null}
use lettr::audience::contacts::{CreateAudienceContactOptions, DoubleOptInConfig};

let options = CreateAudienceContactOptions::new("jane@example.com")
    .with_double_opt_in(DoubleOptInConfig::new(
        "hello@example.com",
        "Confirm your subscription",
        "email-confirmation",
        "https://example.com/confirmed",
    ));
client.audience.contacts.create(options).await?;
```

### Bulk operations & membership

```rust theme={null}
use lettr::audience::contacts::{BulkCreateAudienceContactsOptions, BulkContactListMembershipOptions};

// Bulk create
client.audience.contacts.bulk_create(
    BulkCreateAudienceContactsOptions::new(vec![
        "a@example.com".to_string(),
        "b@example.com".to_string(),
    ]).with_list_id("list-uuid"),
).await?;

// Single list / topic membership
client.audience.contacts.attach_to_list("contact-uuid", "list-uuid").await?;
client.audience.contacts.detach_from_list("contact-uuid", "list-uuid").await?;
client.audience.contacts.subscribe_to_topic("contact-uuid", "topic-uuid").await?;
client.audience.contacts.unsubscribe_from_topic("contact-uuid", "topic-uuid").await?;

// Bulk list membership (cartesian product of contact_ids × list_ids)
let options = BulkContactListMembershipOptions::new()
    .with_contact_ids(vec!["c1".to_string(), "c2".to_string()])
    .with_list_ids(vec!["l1".to_string(), "l2".to_string()]);
client.audience.contacts.bulk_attach_to_lists(options).await?;
```

## Lists

```rust theme={null}
use lettr::audience::lists::{CreateAudienceListOptions, UpdateAudienceListOptions, BulkDeleteAudienceListsOptions};

let list = client.audience.lists.create(CreateAudienceListOptions::new("Newsletter")).await?;
println!("{} {} {}", list.id, list.name, list.contacts_count);

client.audience.lists.get("list-uuid").await?;
client.audience.lists.update(
    "list-uuid",
    UpdateAudienceListOptions::new().with_name("Weekly digest"),
).await?;
client.audience.lists.delete("list-uuid").await?;

// Bulk delete
client.audience.lists.bulk_delete(
    BulkDeleteAudienceListsOptions::new(vec!["l1".to_string(), "l2".to_string()]),
).await?;
```

<Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-lists">
  GET /audience/lists
</Card>

## Segments

A segment is a dynamic group defined by conditions. Groups are joined by **OR**; conditions within a group by **AND**.

```rust theme={null}
use lettr::audience::segments::{
    CreateAudienceSegmentOptions, SegmentConditionsInput, SegmentConditionGroup,
    SegmentCondition, SegmentOperator,
};

let conditions = SegmentConditionsInput::new(vec![
    SegmentConditionGroup::new(vec![
        SegmentCondition::new("email", SegmentOperator::EndsWith, "@example.com"),
        SegmentCondition::new("plan", SegmentOperator::Equals, "pro"),
    ]),
]);

client.audience.segments.create(
    CreateAudienceSegmentOptions::new("Pro users at example.com", conditions)
        .with_list_id("list-uuid"),
).await?;

client.audience.segments.get("segment-uuid").await?;
client.audience.segments.delete("segment-uuid").await?;
```

Use `SegmentCondition::unary(field, op)` for value-less operators like `SegmentOperator::IsTrue` and `SegmentOperator::IsFalse`.

<Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-segments">
  GET /audience/segments
</Card>

## Topics

```rust theme={null}
use lettr::audience::topics::{CreateAudienceTopicOptions, AudienceTopicDefaultSubscription, AudienceTopicVisibility};

client.audience.topics.create(
    CreateAudienceTopicOptions::new("Product updates")
        .with_description("Occasional product news")
        .with_default_subscription(AudienceTopicDefaultSubscription::OptIn)  // immutable after creation
        .with_visibility(AudienceTopicVisibility::Public),
).await?;

client.audience.topics.get("topic-uuid").await?;
client.audience.topics.delete("topic-uuid").await?;
```

<Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-topics">
  GET /audience/topics
</Card>

## Properties

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

```rust theme={null}
use lettr::audience::properties::{CreateAudiencePropertyOptions, AudiencePropertyType};

client.audience.properties.create(
    CreateAudiencePropertyOptions::new("plan", AudiencePropertyType::String)  // String, Number, Boolean, Date, Json
        .with_fallback_value("free"),
).await?;

client.audience.properties.get("property-uuid").await?;
client.audience.properties.delete("property-uuid").await?;
```

<Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-properties">
  GET /audience/properties
</Card>

## What's Next

<CardGroup cols={2}>
  <Card title="Campaigns" icon="paper-plane" href="/quickstart/rust/campaigns">
    Send to your audience
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/audience/list-audience-lists">
    Full audience API reference
  </Card>
</CardGroup>
