---
title: Lettr API Integration on Truto
slug: lettr
category: Email
canonical: "https://truto.one/integrations/detail/lettr/"
---

# Lettr API Integration on Truto



**Category:** Email  
**Status:** Generally available

## MCP-ready AI tools

Truto exposes 71 tools for Lettr that AI agents can call directly.

- **lettr_audience_contact_lists_bulk_create** — Bulk attach contacts to lists (POST /api/audience/contacts/lists/bulk). Attach every combination of `contact_ids × list_ids` (up to 1000 contacts × 50 lists). Existing pairs are reported in `already_attached`. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_ids, list_ids.
- **lettr_audience_contact_lists_bulk_delete** — Bulk detach contacts from lists (DELETE /api/audience/contacts/lists/bulk). Detach every combination of `contact_ids × list_ids` (up to 1000 contacts × 50 lists). Pairs that were not attached are reported in `not_present`. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_ids, list_ids.
- **create_a_lettr_audience_contact_list** — Attach contact to list (POST /api/audience/contacts/{contactId}/lists/{listId}). Add a contact to a list. Returns `201` if the contact was newly attached, or `200` if the contact was already in the list. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_id, list_id.
- **delete_a_lettr_audience_contact_list_by_id** — Detach contact from list (DELETE /api/audience/contacts/{contactId}/lists/{listId}). Remove a contact from a list. Idempotent — returns `204` whether the pair existed or not. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id, contact_id.
- **lettr_audience_contact_topics_bulk_create** — Bulk subscribe contacts to topics (POST /api/audience/contacts/topics/bulk). Subscribe every combination of `contact_ids × topic_ids` (up to 1000 contacts × 50 topics). Pairs that already exist are reported in `already_subscribed`. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_ids, topic_ids.
- **lettr_audience_contact_topics_bulk_delete** — Bulk unsubscribe contacts from topics (DELETE /api/audience/contacts/topics/bulk). Remove every combination of `contact_ids × topic_ids`. Pairs that did not exist are ignored. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_ids, topic_ids.
- **create_a_lettr_audience_contact_topic** — Subscribe contact to topic (POST /api/audience/contacts/{contactId}/topics/{topicId}). Subscribe a contact to a topic. Returns `201` if the subscription is new, or `200` if the contact was already subscribed. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: contact_id, topic_id.
- **delete_a_lettr_audience_contact_topic_by_id** — Unsubscribe contact from topic (DELETE /api/audience/contacts/{contactId}/topics/{topicId}). Unsubscribe a contact from a topic. Idempotent — returns `204` whether the subscription existed or not. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id, contact_id.
- **list_all_lettr_audience_contacts** — List audience contacts (GET /api/audience/contacts). List contacts with pagination and filtering. Requires the `audience:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_audience_contact** — Create a contact (POST /api/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. Required: email.
- **lettr_audience_contacts_bulk_create** — Bulk create contacts (POST /api/audience/contacts/bulk). Create up to 1000 contacts in a single request. Send `contacts` to give each row its own properties, lists and topics, or the legacy `emails` array when the whole batch shares one property map.
- **get_single_lettr_audience_contact_by_id** — Show a contact (GET /api/audience/contacts/{contactId}). Retrieve a single contact. Requires the `audience:read` scope. Required: id.
- **update_a_lettr_audience_contact_by_id** — Update a contact (PATCH /api/audience/contacts/{contactId}). Partially update a contact. If no fields are provided the contact is returned unchanged. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: id.
- **delete_a_lettr_audience_contact_by_id** — Delete a contact (DELETE /api/audience/contacts/{contactId}). Permanently delete a contact. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id.
- **list_all_lettr_audience_lists** — List audience lists (GET /api/audience/lists). Returns all audience lists for the authenticated team. Requires the `audience:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_audience_list** — Create an audience list (POST /api/audience/lists). Create a new audience list. The name must be unique within the team. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: name.
- **lettr_audience_lists_bulk_delete** — Bulk delete audience lists (DELETE /api/audience/lists/bulk). Delete up to 50 lists in a single request. All `list_ids` must belong to the authenticated team. If any list has segments restricted 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. Required: list_ids.
- **get_single_lettr_audience_list_by_id** — Show an audience list (GET /api/audience/lists/{listId}). Retrieve a single audience list. Requires the `audience:read` scope. Required: id.
- **update_a_lettr_audience_list_by_id** — Update an audience list (PATCH /api/audience/lists/{listId}). Partially update an audience list. If no fields are provided the existing list is returned unchanged. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: id.
- **delete_a_lettr_audience_list_by_id** — Delete an audience list (DELETE /api/audience/lists/{listId}). Permanently delete an audience list. A list that segments are restricted to cannot be deleted (`409` `list_in_use`): remove the restriction from those segments or delete them first. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id.
- **list_all_lettr_audience_properties** — List audience properties (GET /api/audience/properties). List the team's custom contact properties. Requires the `audience:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_audience_property** — Create a property (POST /api/audience/properties). Create a new property that contacts can store. The `name` and `type` fields are immutable after creation — to change them, delete the property and create a new one. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: name, type.
- **get_single_lettr_audience_property_by_id** — Show a property (GET /api/audience/properties/{propertyId}). Retrieve a single property. Requires the `audience:read` scope. Required: id.
- **update_a_lettr_audience_property_by_id** — Update a property (PATCH /api/audience/properties/{propertyId}). Update the property's fallback value. The `name` and `type` fields cannot be changed (they would orphan data on existing contacts). If the request body contains no recognized fields, the property is returned unchanged with a `200` response. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: id.
- **delete_a_lettr_audience_property_by_id** — Delete a property (DELETE /api/audience/properties/{propertyId}). Permanently delete a property. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id.
- **list_all_lettr_audience_segments** — List audience segments (GET /api/audience/segments). List segments with pagination. Requires the `audience:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_audience_segment** — Create a segment (POST /api/audience/segments). Create a segment defined by condition groups (conditions within a group are joined by OR; groups are joined by AND). Requires the `audience:write` scope and is blocked for sandbox API keys. Required: name, conditions.
- **get_single_lettr_audience_segment_by_id** — Show a segment (GET /api/audience/segments/{segmentId}). Retrieve a single segment. Requires the `audience:read` scope. Required: id.
- **update_a_lettr_audience_segment_by_id** — Update a segment (PATCH /api/audience/segments/{segmentId}). Partially update a segment. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: id.
- **delete_a_lettr_audience_segment_by_id** — Delete a segment (DELETE /api/audience/segments/{segmentId}). Permanently delete a segment. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id.
- **list_all_lettr_audience_topics** — List audience topics (GET /api/audience/topics). List topics with pagination. Requires the `audience:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_audience_topic** — Create a topic (POST /api/audience/topics). Create a topic. The `default_subscription` field is set at creation and cannot be changed later. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: name.
- **get_single_lettr_audience_topic_by_id** — Show a topic (GET /api/audience/topics/{topicId}). Retrieve a single topic. Requires the `audience:read` scope. Required: id.
- **update_a_lettr_audience_topic_by_id** — Update a topic (PATCH /api/audience/topics/{topicId}). Partially update a topic. The `default_subscription` field is immutable. Requires the `audience:write` scope and is blocked for sandbox API keys. Required: id.
- **delete_a_lettr_audience_topic_by_id** — Delete a topic (DELETE /api/audience/topics/{topicId}). Permanently delete a topic. Requires the `audience:write` scope and is blocked for sandbox API keys. Lettr answers 204 with no body. Required: id.
- **list_all_lettr_auth_check** — Validate API Key (GET /api/auth/check). Validate the provided API key and return associated team information. Use this endpoint to verify API key validity in client libraries.
- **list_all_lettr_campaign_events** — List campaign engagement events (GET /api/campaigns/{campaignId}/events). Returns engagement events (opens, clicks, bounces, etc.) for a campaign, with optional filtering by type, recipient email, and date range. Uses cursor-based pagination: keep requesting with the returned `next_cursor` until it is `null`. Truto pages with the cursor (limit = page size, at most 100) until next_cursor is null. Required: campaign_id.
- **create_a_lettr_campaign_schedule** — Schedule a campaign (POST /api/campaigns/{campaignId}/schedule). Schedules a campaign for future delivery, or reschedules an already-scheduled campaign to a new time. The campaign transitions to (or stays) `scheduled` and is dispatched automatically at the given time. Requires the `campaigns:write` scope. Not available to sandbox keys. Required: campaign_id, scheduled_at.
- **lettr_campaign_schedules_cancel** — Unschedule a campaign (POST /api/campaigns/{campaignId}/unschedule). Cancels a scheduled send, returning the campaign to `draft`. Also clears a delivery time staged on a `draft` in the web editor, so the draft can then be sent with the send endpoint. The campaign must be `scheduled`, or a `draft` with a staged delivery time. Requires the `campaigns:write` scope. Not available to sandbox keys. Required: campaign_id.
- **list_all_lettr_campaigns** — List campaigns (GET /api/campaigns). Returns a paginated list of campaigns for the authenticated team, each with embedded engagement stats. Requires the `campaigns:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_campaign** — Create a campaign (POST /api/campaigns). Creates a draft campaign. Give the content as `html_content` (optionally with the editor's `json_content`) or as a `template_id`, whose HTML is copied onto the campaign. Every list, segment, topic and template must belong to your team. The sender domain is checked when the campaign is sent, not here; language override senders are checked here and must use a verified sending domain. idempotency_key is sent as the Idempotency-Key header.
- **get_single_lettr_campaign_by_id** — Show a campaign (GET /api/campaigns/{campaignId}). Retrieve a single campaign with embedded stats and rendered HTML content. Requires the `campaigns:read` scope. Required: id.
- **lettr_campaigns_send** — Send a campaign now (POST /api/campaigns/{campaignId}/send). Immediately dispatches a draft campaign. The campaign must be a draft with a subject, sender email, and content. Sending is asynchronous; the campaign transitions to `preparing`. Requires the `campaigns:write` scope. Not available to sandbox keys. Required: campaign_id.
- **list_all_lettr_domains** — List Domains (GET /api/domains). Retrieve all sending domains registered with your account. Returns domains with their current status, verification state, and timestamps.
- **create_a_lettr_domain** — Create Domain (POST /api/domains). Register a new sending domain with your account. The domain will be created with SparkPost and stored as approved by default, unless global domain reputation marks it for review or blacklist. Adding a domain your team already has returns `409` and leaves its DNS records and verification status unchanged. Required: domain.
- **get_single_lettr_domain_by_id** — Get Domain (GET /api/domains/{domain}). Retrieve details of a single sending domain including DNS records and tracking domain configuration. Required: id.
- **delete_a_lettr_domain_by_id** — Delete Domain (DELETE /api/domains/{domain}). Delete a sending domain. This removes the domain from both SparkPost and the Lettr system. The domain will no longer be available for sending emails. Lettr answers 204 with no body. Required: id.
- **lettr_domains_verify** — Verify Domain (POST /api/domains/{domain}/verify). Verify a domain's DNS records (DKIM and CNAME) with SparkPost. This triggers a verification check and returns the current status of DNS records. Required: domain.
- **list_all_lettr_email_events** — List Email Events (GET /api/emails/events). Retrieve email events (deliveries, bounces, opens, clicks, etc.) for your account. Events are returned in reverse chronological order. If no `from` date is provided, defaults to the last 10 days. Truto pages with the cursor (limit = page size, at most 100) until next_cursor is null. Lists (events, recipients) are sent comma-separated.
- **create_a_lettr_email** — Send Email (POST /api/emails). Send a transactional email with optional attachments, tracking, and personalization. At least one of `html` or `text` content must be provided. Supply `Idempotency-Key` for safe retries using SparkPost native transmission idempotency. Keys are namespaced per Lettr API key and retained by SparkPost for 24 hours. idempotency_key is sent as the Idempotency-Key header. Required: from, to.
- **list_all_lettr_emails** — List Sent Emails (GET /api/emails). Retrieve a paginated list of sent emails. Supports filtering by recipient email and date range. Uses cursor-based pagination. Truto pages with the cursor (limit = page size, at most 100) until next_cursor is null.
- **get_single_lettr_email_by_id** — Get Email Detail (GET /api/emails/{requestId}). Retrieve all events for a specific sent email by its request ID. Returns delivery, bounce, open, click, and other events in reverse chronological order. If no `from` date is provided, defaults to the last 10 days. Required: id.
- **list_all_lettr_folders** — List Folders (GET /api/folders). Retrieve a paginated list of the folders in a project, so a template can be filed into the right one. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **list_all_lettr_health** — Health Check (GET /api/health). Check the health status of the API. This endpoint does not require authentication.
- **list_all_lettr_projects** — List Projects (GET /api/projects). Retrieve a paginated list of projects for the authenticated team. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_scheduled_email** — Schedule Email (POST /api/emails/scheduled). Schedule a transactional email for future delivery. Accepts the same payload as `POST /emails` with an additional required `scheduled_at` field. The email must be scheduled at least 5 minutes in the future and within 30 days. Required: from, to, scheduled_at.
- **list_all_lettr_scheduled_emails** — List Scheduled Emails (GET /api/emails/scheduled). List the scheduled emails of your team, newest first. Requires the `emails:read` scope. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **get_single_lettr_scheduled_email_by_id** — Get Scheduled Email (GET /api/emails/scheduled/{transmissionId}). Retrieve a scheduled email by the `request_id` returned when it was scheduled (`sch_...`). Required: id.
- **delete_a_lettr_scheduled_email_by_id** — Cancel Scheduled Email (DELETE /api/emails/scheduled/{transmissionId}). Cancel a scheduled email before it is injected into SparkPost, and return the cancelled email. Required: id.
- **list_all_lettr_template_html** — Get Template HTML (GET /api/templates/html). Retrieve the HTML content and merge tags for a template's active version. Requires `project_id` and template `slug` as query parameters. Required: project_id, slug.
- **list_all_lettr_template_merge_tags** — Get Template Merge Tags (GET /api/templates/{slug}/merge-tags). Retrieve the merge tags (variables) for a template version. By default, returns merge tags for the active version. Use the `version` parameter to get merge tags for a specific version. Required: slug.
- **list_all_lettr_templates** — List Templates (GET /api/templates). Retrieve a paginated list of email templates for a project. If `project_id` is not provided, templates from the team's default project will be returned. Truto pages with page / per_page (limit = page size, at most 100) until the last page.
- **create_a_lettr_template** — Create Template (POST /api/templates). Create a new email template with HTML or Topol editor JSON content. Automatically creates and publishes a template version with extracted merge tags. Required: name.
- **get_single_lettr_template_by_id** — Get Template (GET /api/templates/{slug}). Retrieve a single email template by its slug. If `project_id` is not provided, the template will be looked up in the team's default project. Required: id.
- **delete_a_lettr_template_by_id** — Delete Template (DELETE /api/templates/{slug}). Permanently delete an email template and all its versions. If `project_id` is not provided, the template will be looked up in the team's default project. Required: id.
- **update_a_lettr_template_by_id** — Update Template (PUT /api/templates/{slug}). Update an existing email template's name and/or content. If content (html or json) is provided, a new active version will be created with extracted merge tags. If `project_id` is not provided, the template will be looked up in the team's default project. Required: id.
- **list_all_lettr_webhooks** — List Webhooks (GET /api/webhooks). Retrieve all webhooks configured for your account. Returns webhooks with their current status, event types, and delivery information.
- **create_a_lettr_webhook** — Create Webhook (POST /api/webhooks). Create a new webhook to receive event notifications at the specified URL. Required: name, url, auth_type, events_mode.
- **get_single_lettr_webhook_by_id** — Get Webhook (GET /api/webhooks/{webhookId}). Retrieve details of a single webhook including its status, event types, and delivery information. Required: id.
- **update_a_lettr_webhook_by_id** — Update Webhook (PUT /api/webhooks/{webhookId}). Update an existing webhook. Only the fields provided will be updated (partial update). You can change the name, target URL, authentication, events, or active status. Required: id.
- **delete_a_lettr_webhook_by_id** — Delete Webhook (DELETE /api/webhooks/{webhookId}). Delete a webhook. This removes the webhook from SparkPost and it will no longer receive event notifications. Required: id.

## How it works

1. **Link your customer's Lettr account.** Use Truto's frontend SDK; we handle every OAuth and API key flow so you don't need to create the OAuth app.
2. **Authentication is automatic.** Truto refreshes tokens, stores credentials securely, and injects them into every API request.
3. **Call Truto's API to reach Lettr.** The Proxy API is a 1-to-1 mapping of the Lettr API.
4. **Get a unified response format.** Every response uses a single shape, with cursor-based pagination and data in the `result` field.

## Use cases

- **Embed Lettr as your native email engine** — Let your users connect their Lettr account to power both marketing campaigns and transactional sends directly from your SaaS, without making them context-switch into Lettr's dashboard.
- **Sync customer data into Lettr audiences** — Keep your SaaS's contact records continuously in sync with Lettr audience lists, topics, and segments so marketers always send to accurate, up-to-date subscriber states.
- **Trigger lifecycle and transactional emails** — Fire scheduled or immediate emails from product events — onboarding, order shipped, appointment reminders — and safely cancel them if conditions change before send time.
- **Pipe engagement events back into your product** — Pull open, click, bounce, and delivery events from Lettr into your CRM timeline, lead scoring engine, or analytics dashboard to close the loop on email performance.
- **Offer white-label domain provisioning** — Programmatically create and verify sending domains on behalf of your users so they can start sending from their own domain without ever logging into Lettr.

## What you can build

- **Bulk contact sync** — Use bulk contact creation and bulk topic/list assignment to push thousands of subscribers into Lettr in a single pass during initial onboarding or scheduled CDP syncs.
- **Template-aware email composer** — Fetch a user's Lettr templates and their required merge tags to auto-generate a mapping UI where your SaaS fields are bound to Lettr template variables.
- **Scheduled send with cancellation** — Queue emails up to 30 days in advance via scheduled emails and cancel them by ID if a downstream event (purchase, cancellation, status change) makes the send obsolete.
- **Campaign dispatch from your UI** — Create a Lettr campaign, target it to a segment or list, and trigger send — all from inside your own product's campaign builder.
- **Engagement event ingestion** — Register Lettr webhooks or poll email and campaign event endpoints to stream opens, clicks, and bounces into your contact timelines in near real time.
- **Domain onboarding wizard** — Guide users through adding a sending domain, then call the verify endpoint to confirm DNS setup without leaving your onboarding flow.

## FAQs

### How do end users authenticate their Lettr account?

Users connect their Lettr account via Truto's managed auth flow. Truto handles credential storage and token lifecycle so you never touch the raw API keys in your application code.

### Can I sync large audiences without hitting rate limits?

Yes. Lettr exposes bulk endpoints for contacts, contact lists, and contact topics, letting you create or delete records in batches rather than one call per contact, which is the recommended path for initial syncs and large daily updates.

### How do I know which variables a Lettr template needs?

You can list a template's merge tags via the template merge tags endpoint. This lets you dynamically render a mapping UI so users can bind your SaaS data fields to the exact variables their Lettr template expects.

### Can I cancel a scheduled email before it sends?

Yes. Scheduled emails can be retrieved and deleted by ID before they're dispatched, which is useful for cart recovery, appointment reminders, or any workflow where the triggering condition may reverse.

### How fresh is engagement data (opens, clicks, bounces)?

You can either register a webhook to receive events as they happen, or poll the email events and campaign events endpoints on a schedule. Both endpoints support cursor-based pagination for reliable incremental ingestion.

### Does the integration support provisioning sending domains for my users?

Yes. You can create a domain, fetch its DNS requirements, and trigger verification programmatically, so users can complete domain setup inside your product rather than logging into Lettr directly.
