> ## 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 email campaigns with engagement stats using the campaigns service in the Lettr PHP SDK.

The `$lettr->campaigns()` service gives you read access to your campaigns plus lifecycle actions — send now, schedule, and unschedule. Campaigns are **created and edited in the Lettr dashboard**; the API does not expose create, update, or delete.

Reads require an API key with the `campaigns:read` scope; actions (send, schedule, unschedule) require `campaigns:write`.

<Note>
  `$campaign->status` is a `CampaignStatus` enum for known values, or the raw string for any future status the SDK doesn't yet recognize — so a server-side enum addition can never break deserialization. The same applies to `$event->eventType` (`EventType|string`).
</Note>

## List Campaigns

```php theme={null}
use Lettr\Dto\Campaign\ListCampaignsFilter;
use Lettr\Enums\CampaignStatus;

$response = $lettr->campaigns()->list();

foreach ($response->campaigns as $campaign) {
    echo $campaign->name;               // "Spring Sale"
    echo $campaign->sentCount;          // 124
    echo $campaign->stats->uniqueOpens; // engagement stats are embedded

    if ($campaign->status === CampaignStatus::Sent) {
        echo 'Already delivered';
    }
}

echo $response->pagination->total;
echo $response->hasMore();

// Filter by status and paginate
$response = $lettr->campaigns()->list(
    ListCampaignsFilter::create()->status(CampaignStatus::Sent)->page(2)->perPage(50),
);
```

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

## Get a Campaign

`get()` returns a `CampaignDetail` (a `CampaignSummary` plus the rendered `htmlContent` body):

```php theme={null}
$campaign = $lettr->campaigns()->get('0193e6a8-1f3a-7c2a-b9e2-1aa1d2e5d3f0');

echo $campaign->subject;
echo $campaign->htmlContent; // rendered HTML body — CampaignDetail only
echo $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:

```php theme={null}
use Lettr\Dto\Campaign\ListCampaignEventsFilter;
use Lettr\Enums\EventType;

$cursor = null;

do {
    $response = $lettr->campaigns()->events('0193e6a8-...', ListCampaignEventsFilter::create()
        ->eventType(EventType::Click)
        ->startDate(new DateTimeImmutable('-7 days'))
        ->cursor($cursor)); // null on the first iteration is fine

    foreach ($response->events as $event) {
        echo $event->email;
        echo $event->timestamp;
        echo $event->targetLinkUrl; // for click events
    }

    $cursor = $response->nextCursor;
} while ($response->hasMore());
```

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

## Send Now

```php theme={null}
// Dispatch a draft campaign immediately (asynchronous; transitions to "preparing")
$campaign = $lettr->campaigns()->send('0193e6a8-...');

echo $campaign->id;
```

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

## Schedule / Reschedule

Accepts a `DateTimeInterface` (formatted to ISO-8601 with offset) or a raw string. Calling `schedule()` again on an already-scheduled campaign reschedules it.

```php theme={null}
$campaign = $lettr->campaigns()->schedule(
    '0193e6a8-...',
    new DateTimeImmutable('2026-06-01 09:00:00', new DateTimeZone('+02:00')),
);

// Or pass an ISO-8601 string
$lettr->campaigns()->schedule('0193e6a8-...', '2026-06-02T09:00:00Z');
```

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

## Unschedule

```php theme={null}
// Cancel a scheduled send, returning the campaign to draft
$campaign = $lettr->campaigns()->unschedule('0193e6a8-...');
```

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

## What's Next

<CardGroup cols={2}>
  <Card title="Audience" icon="users" href="/quickstart/php/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>
