Skip to main content

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.

Reach campaigns through Lettr::campaigns(). You get 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.
use Lettr\Laravel\Facades\Lettr;
$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).

List Campaigns

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),
);

API Reference

GET /campaigns

Get a Campaign

get() returns a CampaignDetail (a CampaignSummary plus the rendered htmlContent body):
$campaign = Lettr::campaigns()->get('campaign-uuid');

echo $campaign->subject;
echo $campaign->htmlContent; // rendered HTML body — CampaignDetail only
echo $campaign->stats->clicks;

API Reference

GET /campaigns/

List Campaign Events

Engagement events use cursor-based pagination:
use DateTimeImmutable;
use Lettr\Dto\Campaign\ListCampaignEventsFilter;
use Lettr\Enums\EventType;

$cursor = null;

do {
    $response = Lettr::campaigns()->events('campaign-uuid', 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());

API Reference

GET /campaigns//events

Send / Schedule / Unschedule

use DateTimeImmutable;
use DateTimeZone;

// Dispatch a draft campaign immediately (asynchronous; transitions to "preparing")
$campaign = Lettr::campaigns()->send('campaign-uuid');

// Schedule for future delivery — accepts a DateTimeInterface or an ISO-8601 string.
// Calling schedule() on an already-scheduled campaign reschedules it.
Lettr::campaigns()->schedule(
    'campaign-uuid',
    new DateTimeImmutable('2026-06-01 09:00:00', new DateTimeZone('+02:00')),
);

// Cancel a scheduled send, returning the campaign to draft
Lettr::campaigns()->unschedule('campaign-uuid');
The three action methods always return a non-null CampaignSummary — if the API omits the campaign payload from the action response, the SDK transparently refetches it.

Send

POST /campaigns//send

Schedule

POST /campaigns//schedule

Unschedule

POST /campaigns//unschedule

What’s Next

Audience

Manage the contacts campaigns send to

API Reference

Full campaigns API reference