> ## 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.

# Campaigns

> List, inspect, send, schedule, and unschedule campaigns and read engagement stats with the client.campaigns resource in the Lettr Python SDK.

The `client.campaigns` resource gives you read access to campaigns plus lifecycle actions — send now, schedule, and unschedule. Campaigns are **authored in the Lettr app**; the API does not expose create, update, or delete.

Reads require an API key with the `campaigns:read` scope; actions require `campaigns:write`.

```python theme={null}
import lettr

client = lettr.Lettr("lttr_your_api_key")
```

## List Campaigns

```python theme={null}
page = client.campaigns.list(status="sent", per_page=50)
for campaign in page.campaigns:
    print(f"{campaign.name}: {campaign.status} — {campaign.stats.unique_opens} opens")
    print(campaign.sent_count)
```

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

## Get a Campaign

`get()` returns a `CampaignDetail` with the rendered `html_content` body. The `list`, `send`, `schedule`, and `unschedule` methods return the base `Campaign`, which does not carry `html_content`.

```python theme={null}
campaign = client.campaigns.get(page.campaigns[0].id)
print(campaign.subject)
print(campaign.html_content)
print(campaign.stats.clicks)
```

<Card title="API Reference" icon="book" href="/api-reference/campaigns/show-a-campaign">
  GET /campaigns/{campaignId}
</Card>

## List Campaign Events

Engagement events use cursor-based pagination:

```python theme={null}
events = client.campaigns.list_events(campaign.id, event_type="open")
for event in events.events:
    print(f"{event.timestamp} {event.event_type} {event.email}")
    print(event.target_link_url)  # for click events

if events.next_cursor:
    more = client.campaigns.list_events(campaign.id, cursor=events.next_cursor)
```

<Card title="API Reference" icon="book" href="/api-reference/campaigns/list-campaign-engagement-events">
  GET /campaigns/{campaignId}/events
</Card>

## Send / Schedule / Unschedule

```python theme={null}
# Dispatch a draft campaign immediately (asynchronous; transitions to "preparing")
client.campaigns.send(campaign.id)

# Schedule for future delivery — ISO 8601 string or a datetime; must be in the future.
# Calling schedule() again on a scheduled campaign reschedules it.
client.campaigns.schedule(campaign.id, scheduled_at="2026-06-01T09:00:00+00:00")

# Cancel a scheduled send, returning the campaign to draft
client.campaigns.unschedule(campaign.id)
```

The action methods return the updated `Campaign`, or `None` if the API omits the payload.

<CardGroup cols={3}>
  <Card title="Send" icon="paper-plane" href="/api-reference/campaigns/send-a-campaign-now">
    POST /campaigns/{id}/send
  </Card>

  <Card title="Schedule" icon="clock" href="/api-reference/campaigns/schedule-a-campaign">
    POST /campaigns/{id}/schedule
  </Card>

  <Card title="Unschedule" icon="ban" href="/api-reference/campaigns/unschedule-a-campaign">
    POST /campaigns/{id}/unschedule
  </Card>
</CardGroup>

## What's Next

<CardGroup cols={2}>
  <Card title="Audience" icon="users" href="/quickstart/python/audience">
    Manage the contacts campaigns send to
  </Card>

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