Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api-reference/audience/bulk-delete-audience-lists.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ title: Bulk delete audience lists
openapi: DELETE /audience/lists/bulk
---

Delete up to 50 lists in a single request. All `list_ids` must belong to the authenticated team. Requires the `audience:write` scope and is blocked for sandbox API keys.
Delete up to 50 lists in a single request. All `list_ids` must belong to the authenticated team. If any list has segments scoped to it, nothing is deleted and the response is `409` `list_in_use`. Requires the `audience:write` scope and is blocked for sandbox API keys.
2 changes: 1 addition & 1 deletion api-reference/audience/create-a-contact.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ title: Create a contact
openapi: POST /audience/contacts
---

Create a single contact. If `double_opt_in` is provided the contact is created in `unverified` status and receives a confirmation email — they become `subscribed` only after clicking the confirmation link. Requires the `audience:write` scope and is blocked for sandbox API keys.
Create a single contact. A `list_id` must be a list of your team, otherwise the response is `422` and no contact is created. If `double_opt_in` is provided the contact is created in `unverified` status and receives a confirmation email — they become `subscribed` only after clicking the confirmation link. Requires the `audience:write` scope and is blocked for sandbox API keys.
2 changes: 1 addition & 1 deletion api-reference/audience/delete-an-audience-list.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ title: Delete an audience list
openapi: DELETE /audience/lists/{listId}
---

Permanently delete an audience list. Requires the `audience:write` scope and is blocked for sandbox API keys.
Permanently delete an audience list. A list that segments are scoped to cannot be deleted: the response is `409` `list_in_use`, naming the segments. Requires the `audience:write` scope and is blocked for sandbox API keys.
2 changes: 1 addition & 1 deletion api-reference/campaigns/unschedule-a-campaign.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ title: Unschedule a campaign
openapi: POST /campaigns/{campaignId}/unschedule
---

Cancels a scheduled send, returning the campaign to `draft`. The campaign must currently be `scheduled`. Requires the `campaigns:write` scope. Not available to sandbox keys.
Cancels a scheduled send, returning the campaign to `draft`. Also clears a delivery time staged on a `draft` in the editor, so the draft can then be sent immediately. A draft without a delivery time returns `422` `campaign_not_scheduled`. Requires the `campaigns:write` scope. Not available to sandbox keys.
3 changes: 3 additions & 0 deletions api-reference/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ curl -X POST https://app.lettr.com/api/emails \
| `200` | Success - Email queued for delivery |
| `400` | Bad Request - Domain configuration error |
| `401` | Unauthorized - Invalid or missing API key |
| `409` | Conflict - The resource already exists or is still in use |
| `422` | Unprocessable Entity - Validation failed |
| `429` | Too Many Requests - Rate limit or sending quota exceeded |
| `502` | Bad Gateway - Upstream transmission failed |
Expand All @@ -91,6 +92,8 @@ curl -X POST https://app.lettr.com/api/emails \
| `quota_exceeded` | 429 | Monthly sending quota exceeded. Upgrade your plan to continue sending. |
| `daily_quota_exceeded` | 429 | Daily sending quota exceeded (free tier). Try again tomorrow. |
| `transmission_failed` | 502 | Email transmission to the upstream provider failed. |
| `resource_already_exists` | 409 | The resource already exists, for example a sending domain your team has already added. |
| `list_in_use` | 409 | The audience list cannot be deleted because segments are scoped to it. The message names the segments. |

## Send Email Reference

Expand Down
2 changes: 1 addition & 1 deletion learn/audience/double-opt-in.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ curl -X POST https://app.lettr.com/api/audience/contacts \
}'
```

The API responds immediately. The contact is created with status `unverified`, and the confirmation email is queued for delivery. If you also pass `properties` or `list_id` in the call, they're attached to the contact right away — they don't wait for confirmation.
The API responds immediately. The contact is created with status `unverified`, and the confirmation email is queued for delivery. If you also pass `properties` or `list_id` in the call, they're attached to the contact right away — they don't wait for confirmation. A `list_id` must belong to your team; an unknown one returns `422` and no contact is created.

### Required `double_opt_in` Fields

Expand Down
4 changes: 3 additions & 1 deletion learn/audience/lists.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ You can rename a list at any time from the **Lists** page. Renaming does not aff

Deleting a list removes the list itself and the membership records, but does **not** delete the contacts. The contacts remain in your audience and in any other lists or segments they belong to.

A list that a segment is scoped to cannot be deleted. Deleting it would remove the segment's list restriction and widen the segment to your whole audience. Remove the list from those segments, or delete the segments, first. The API returns `409` with `error_code` `list_in_use` and names the segments; a bulk delete deletes nothing if any of its lists is in use.

<Warning>
Segments reference lists by **name**, not by ID. If you rename a list that a segment uses in its conditions, that segment will silently stop matching anyone from the renamed list until you update the segment. Always check your segments after renaming a list.
</Warning>
Expand All @@ -72,7 +74,7 @@ A contact who belongs to multiple selected lists is only sent the email once. Se

When you create a segment, you can optionally scope it to a single list. The segment then only matches contacts who are members of that list **and** match the conditions. This is useful for further filtering a list — for example, "everyone in the Q4 onboarding list whose `last_login` is older than 30 days" — without affecting other contacts.

See [Segments](/learn/audience/segments#list-scoped-segments) for details.
A list with segments scoped to it cannot be deleted until those segments no longer use it. See [Segments](/learn/audience/segments#list-scoped-segments) for details.

## Lists vs. Topics vs. Segments

Expand Down
6 changes: 6 additions & 0 deletions learn/audience/segments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ Each condition uses an operator that depends on the field type. Lettr supports t

For `topics` and `lists` fields, `equals` means "is a member" and `not_equals` means "is not a member".

<Warning>
Only the fields above are supported, and `topics` and `lists` only take `equals` and `not_equals`. A condition on any other field (for example `city` instead of `properties.city`, or `Email` with a capital E), or `topics`/`lists` with another operator, is rejected when you save the segment; the API returns `422`. A segment saved before this check with such a condition treats it as matching no contacts, so review segments that suddenly match fewer contacts than expected.
</Warning>

`is_empty` and `is_not_empty` need no value. They are the quickest way to find gaps in your data. For example, `language is empty` lists every contact who would receive the primary language of a [multilingual campaign](/learn/multilingual-campaigns/contact-language#finding-contacts-without-a-language) because Lettr has nothing to match.

## AI Segment Builder
Expand All @@ -120,6 +124,8 @@ A segment can optionally be scoped to a single [list](/learn/audience/lists). Wh

List-scoped segments are useful when you want to slice a specific list further without affecting the rest of your audience. For example, a list called "Onboarding Cohort October 2026" can have its own segments for "completed the welcome tour" or "didn't open the first email" — without those segments running over your entire audience.

While a segment is scoped to a list, that list cannot be deleted. Remove the list from the segment first, or delete the segment.

## Renaming Lists and Topics

This is the most common gotcha with segments:
Expand Down
2 changes: 1 addition & 1 deletion learn/domains/sending-domains.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Response with DNS records to configure:
```

<Tip>
Working in an AI-powered editor like Claude Code or Cursor? The [local Lettr MCP server](/learn/mcp/local-setup) can handle this whole flow for you — its `create-domain` and `verify-domain` tools let your assistant add the domain, hand you the exact DNS records, and re-run verification until everything passes.
Working with an AI assistant like Claude, ChatGPT, Claude Code, or Cursor? Both Lettr MCP servers can handle this whole flow for you — the [remote server](/learn/mcp/setup)'s `create_domain` and `verify_domain` tools and the [local server](/learn/mcp/local-setup)'s `create-domain` and `verify-domain` tools let your assistant add the domain, hand you the exact DNS records, and re-run verification until everything passes. On the remote server, `diagnose_sending_domain_dns` also explains what is still wrong with your records.
</Tip>

## DNS Records Configuration
Expand Down
31 changes: 21 additions & 10 deletions learn/mcp/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "MCP for AI Assistants"
description: "Connect AI assistants to Lettr with the Model Context Protocol to send email, manage templates, and monitor delivery in plain language."
---

The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is an open standard that enables AI assistants to securely connect with external services. Lettr provides two MCP servers so AI agents can interact with your email infrastructure — sending messages, managing templates, configuring domains, and monitoring delivery — all through natural language.
The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is an open standard that enables AI assistants to securely connect with external services. Lettr provides two MCP servers so AI agents can interact with your email infrastructure — sending messages, managing templates, configuring domains, running campaigns, managing your audience, and monitoring delivery — all through natural language.

## Why Use MCP?

Expand Down Expand Up @@ -38,14 +38,17 @@ Lettr offers two MCP servers for different workflows. Both give AI assistants ac
| **Transport** | HTTP/SSE | stdio |
| **Supported clients** | Claude.ai, ChatGPT, Cursor, Claude Desktop, GitHub Copilot | Claude Code, Cursor, Claude Desktop |
| **Best for** | Chat-based account management, monitoring, analytics | Developer workflows, coding assistants, CI environments |
| **Unique tools** | Analytics, email events, API logs | Domain CRUD, template delete, domain verification |
| **Tool count** | 77 | 69 |
| **Unique tools** | Analytics, template stats, email event browsing, API logs, sending health check, DNS diagnosis, API keys, tracking/inbound/storage domains, dedicated template send tool | Email event listing with bounce class and transmission filters, API health check, API key validation |
| **Open source** | No | [Yes](https://github.com/lettr-com/lettr-mcp) |

### Which Should I Use?

**Use the remote server** if you want to manage your Lettr account from a web-based AI chat like Claude.ai or ChatGPT, or if you need analytics and event monitoring tools. The remote server authenticates through OAuth so you don't need to manage API keys.
Both servers cover the same core workflows — sending and scheduling email, templates, sending domains, webhooks, campaigns, and audience management. The choice mostly comes down to how you authenticate and where your AI assistant runs.

**Use the local server** if you want email capabilities inside your IDE or CLI during development. The local server is ideal for Claude Code and Cursor workflows where you need to send emails, manage templates, or configure domains as part of your coding process.
**Use the remote server** if you want to manage your Lettr account from a web-based AI chat like Claude.ai or ChatGPT, or if you need analytics, API logs, sending health checks, or DNS diagnosis. The remote server authenticates through OAuth so you don't need to manage API keys.

**Use the local server** if you want email capabilities inside your IDE or CLI during development, authenticated with an API key you control. It's ideal for Claude Code and Cursor workflows, and you can limit what it can do with [restricted API keys](/learn/api-keys/permissions).

<Tip>
Cursor and Claude Desktop work with both servers. The remote server uses OAuth (no API key needed), while the local server uses an API key and runs as a local process. You can use both simultaneously.
Expand All @@ -58,14 +61,22 @@ Both MCP servers give AI assistants tools to work with your email infrastructure
| Capability | Remote | Local |
|---|---|---|
| Send emails (direct and template-based) | Yes | Yes |
| List, view, create, and update templates | Yes | Yes |
| Delete templates and inspect merge tags | No | Yes |
| Schedule emails and cancel scheduled sends | Yes | Yes |
| View sent email history and delivery timelines | Yes | Yes |
| List, view, create, update, and delete templates | Yes | Yes |
| Inspect merge tags, template HTML, folders, and projects | Yes | Yes |
| List sending domains | Yes | Yes |
| Create, verify, and delete domains | No | Yes |
| Create, verify, and delete sending domains | Yes | Yes |
| Diagnose sending domain DNS and check sending health | Yes | No |
| List tracking, inbound, and storage domains | Yes | No |
| List, inspect, create, update, and delete webhooks | Yes | Yes |
| List, send, schedule, and unschedule campaigns | Yes | Yes |
| Manage audience contacts, lists, topics, properties, and segments | Yes | Yes |
| View analytics and template statistics | Yes | No |
| Browse email events and API logs | Yes | No |
| List API keys and webhooks | Yes | Yes |
| Inspect webhook details | No | Yes |
| Browse email events across all messages | Yes | Yes |
| Browse API request logs | Yes | No |
| List API keys | Yes | No |
| Check API health and validate the API key | No | Yes |

## Example Conversations

Expand Down
104 changes: 97 additions & 7 deletions learn/mcp/local-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,29 +113,38 @@ The AI should respond with your verified sending domains. If you see domain info

## Available Tools

The local MCP server provides 14 tools for managing your email infrastructure:
The local MCP server provides 69 tools for managing your email infrastructure:

### Emails

| Tool | Description |
|------|-------------|
|-|-|
| `send-email` | Send a transactional email with HTML, plain text, templates, attachments, tracking, and personalization |
| `schedule-email` | Schedule an email for delivery up to 3 days ahead |
| `get-scheduled-email` | Get the state and details of a scheduled email |
| `cancel-scheduled-email` | Cancel a scheduled email before it is sent |
| `list-emails` | List recently sent emails |
| `get-email-detail` | Get the full delivery timeline of a sent email |
| `list-email-events` | List delivery, bounce, open, and click events across all sent messages |

### Templates

| Tool | Description |
|------|-------------|
| `list-templates` | List email templates with pagination |
|-|-|
| `list-templates` | List email templates with pagination, filtered by project, purpose, or folder |
| `get-template` | Get full template details including HTML content |
| `create-template` | Create a new template with HTML or visual editor JSON |
| `get-template-html` | Get a template's full rendered HTML and merge tags |
| `create-template` | Create a new transactional or campaign template with HTML or visual editor JSON |
| `update-template` | Update template name and/or content (creates new version) |
| `delete-template` | Permanently delete a template and all versions |
| `get-merge-tags` | Discover merge tag variables a template expects |
| `list-folders` | List template folders with their purpose and template count |
| `list-projects` | List the projects available to your team |

### Domains

| Tool | Description |
|------|-------------|
|-|-|
| `list-domains` | List all sending domains and their verification status |
| `create-domain` | Register a new sending domain |
| `get-domain` | Get domain details with DNS records |
Expand All @@ -145,9 +154,90 @@ The local MCP server provides 14 tools for managing your email infrastructure:
### Webhooks

| Tool | Description |
|------|-------------|
|-|-|
| `list-webhooks` | List all webhook configurations |
| `get-webhook` | Get webhook details and delivery status |
| `create-webhook` | Create a webhook subscription |
| `update-webhook` | Update a webhook's name, URL, authentication, events, or enabled state |
| `delete-webhook` | Delete a webhook subscription |

### Campaigns

| Tool | Description |
|-|-|
| `list-campaigns` | List campaigns with engagement stats |
| `get-campaign` | Get campaign details, stats, and content |
| `list-campaign-events` | List engagement events for a campaign |
| `send-campaign` | Immediately send a draft campaign to its audience |
| `schedule-campaign` | Schedule or reschedule a campaign |
| `unschedule-campaign` | Cancel a scheduled send and return the campaign to draft |

### Audience Contacts

| Tool | Description |
|-|-|
| `list-audience-contacts` | List contacts filtered by search, status, list, or segment |
| `get-audience-contact` | Get a contact with its properties, lists, and topics |
| `create-audience-contact` | Create a contact, optionally with double opt-in |
| `bulk-create-audience-contacts` | Import up to 1000 contacts at once |
| `update-audience-contact` | Update a contact's email, status, or properties |
| `delete-audience-contact` | Permanently delete a contact |

### Audience Lists

| Tool | Description |
|-|-|
| `list-audience-lists` | List contact lists with pagination |
| `get-audience-list` | Get a list and its contact count |
| `create-audience-list` | Create a contact list |
| `update-audience-list` | Rename a contact list |
| `delete-audience-list` | Delete a contact list |
| `bulk-delete-audience-lists` | Delete up to 50 lists at once |
| `attach-contact-to-list` | Add a contact to a list |
| `detach-contact-from-list` | Remove a contact from a list |
| `bulk-attach-contacts-to-lists` | Add many contacts to many lists |
| `bulk-detach-contacts-from-lists` | Remove many contacts from many lists |

### Audience Topics

| Tool | Description |
|-|-|
| `list-audience-topics` | List subscription topics with pagination |
| `get-audience-topic` | Get a subscription topic |
| `create-audience-topic` | Create a subscription topic |
| `update-audience-topic` | Update a topic's name, description, or visibility |
| `delete-audience-topic` | Delete a subscription topic |
| `subscribe-contact-to-topic` | Subscribe a contact to a topic |
| `unsubscribe-contact-from-topic` | Unsubscribe a contact from a topic |
| `bulk-subscribe-contacts-to-topics` | Subscribe many contacts to many topics |
| `bulk-unsubscribe-contacts-from-topics` | Unsubscribe many contacts from many topics |

### Audience Properties

| Tool | Description |
|-|-|
| `list-audience-properties` | List custom contact properties |
| `get-audience-property` | Get a custom contact property |
| `create-audience-property` | Define a new custom contact property |
| `update-audience-property` | Update a property's fallback value |
| `delete-audience-property` | Delete a custom contact property |

### Audience Segments

| Tool | Description |
|-|-|
| `list-audience-segments` | List segments with pagination |
| `get-audience-segment` | Get a segment and its conditions |
| `create-audience-segment` | Create a segment from match conditions |
| `update-audience-segment` | Update a segment's name, list, or conditions |
| `delete-audience-segment` | Delete a segment |

### System

| Tool | Description |
|-|-|
| `health-check` | Check the Lettr API health status |
| `auth-check` | Validate the configured API key and return its team ID |

For detailed parameter documentation, see the [Tools Reference](/learn/mcp/tools-reference).

Expand Down
Loading