> ## 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 the Lettr Node.js SDK and its result-based client

The `client.campaigns` resource gives you read access to 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 require `campaigns:write`.

## List Campaigns

```typescript theme={null}
const { data, error } = await client.campaigns.list({ status: "sent", page: 1, per_page: 50 });

if (!error) {
  for (const campaign of data.campaigns) {
    console.log(campaign.name);              // "Spring Sale"
    console.log(campaign.sent_count);        // 124
    console.log(campaign.stats.unique_opens);
    console.log(campaign.status);            // "draft" | "scheduled" | "sent" | ...
  }
  console.log(data.pagination.total);
}
```

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

## Get a Campaign

`get()` returns the campaign detail including the rendered `html_content` body:

```typescript theme={null}
const { data, error } = await client.campaigns.get("campaign-uuid");

if (!error) {
  console.log(data.subject);
  console.log(data.html_content); // rendered HTML body
  console.log(data.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:

```typescript theme={null}
let cursor: string | null = null;

do {
  const { data, error } = await client.campaigns.listEvents("campaign-uuid", {
    event_type: "click",
    start_date: "2026-05-01",
    cursor: cursor ?? undefined,
  });
  if (error) break;

  for (const event of data.events) {
    console.log(event.email, event.timestamp, event.target_link_url);
  }

  cursor = data.next_cursor;
} while (cursor !== null);
```

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

## Send / Schedule / Unschedule

```typescript theme={null}
// Dispatch a draft campaign immediately (asynchronous; transitions to "preparing")
await client.campaigns.send("campaign-uuid");

// Schedule for future delivery — ISO-8601 timestamp.
// Calling schedule() again on a scheduled campaign reschedules it.
await client.campaigns.schedule("campaign-uuid", { scheduled_at: "2026-06-01T09:00:00Z" });

// Cancel a scheduled send, returning the campaign to draft
await client.campaigns.unschedule("campaign-uuid");
```

Action methods resolve to a `CampaignActionResponse` with a `message` and an optional `data` (the updated `CampaignSummary`).

<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/nodejs/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>
