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.
The client.audience resource manages everything campaigns send to. Each kind is a sub-resource:
client.audience.contacts; // individual contacts
client.audience.lists; // contact lists
client.audience.topics; // subscription topics
client.audience.properties; // custom contact properties
client.audience.segments; // dynamic segments
All list() methods return paginated data with a pagination object (total, per_page, current_page, last_page).
import { Lettr } from "lettr";
const client = new Lettr(process.env.LETTR_API_KEY!);
// Create (optionally attach to a list and set properties)
const { data: contact } = await client.audience.contacts.create({
email: "jane@example.com",
list_id: "list-uuid",
properties: { first_name: "Jane", plan: "pro" },
});
// List with filters
const { data, error } = await client.audience.contacts.list({
page: 1,
per_page: 50,
search: "jane",
status: "subscribed",
list_id: "list-uuid",
});
if (!error) {
for (const c of data.contacts) console.log(c.email, c.status);
console.log(data.pagination.total);
}
// Get, update, delete
await client.audience.contacts.get("contact-uuid");
await client.audience.contacts.update("contact-uuid", {
status: "unsubscribed",
properties: { plan: "enterprise" },
});
await client.audience.contacts.delete("contact-uuid");
Contact status is "subscribed", "unsubscribed", "bounced", "complained", or "unverified".
API Reference
GET /audience/contacts
Double opt-in
Pass double_opt_in to create the contact as unverified and send a confirmation email — they become subscribed after clicking the link:
await client.audience.contacts.create({
email: "jane@example.com",
double_opt_in: {
from: "hello@example.com",
subject: "Confirm your subscription",
template_slug: "email-confirmation",
redirect_url: "https://example.com/confirmed",
},
});
Bulk operations & membership
// Bulk create
await client.audience.contacts.bulkCreate({
emails: ["a@example.com", "b@example.com"],
list_id: "list-uuid",
});
// Single list / topic membership
await client.audience.contacts.attachList("contact-uuid", "list-uuid");
await client.audience.contacts.detachList("contact-uuid", "list-uuid");
await client.audience.contacts.subscribeTopic("contact-uuid", "topic-uuid");
await client.audience.contacts.unsubscribeTopic("contact-uuid", "topic-uuid");
// Bulk list membership
await client.audience.contacts.bulkAttachLists({
contact_ids: ["c1", "c2"],
list_ids: ["l1", "l2"],
});
await client.audience.contacts.bulkDetachLists({
contact_ids: ["c1"],
list_ids: ["l1"],
});
Lists
const { data: list } = await client.audience.lists.create({ name: "Newsletter" });
console.log(list!.id, list!.name, list!.contacts_count);
await client.audience.lists.list({ page: 1, per_page: 20 });
await client.audience.lists.get("list-uuid");
await client.audience.lists.update("list-uuid", { name: "Weekly digest" });
await client.audience.lists.delete("list-uuid");
// Bulk delete
await client.audience.lists.bulkDelete({ list_ids: ["l1", "l2"] });
API Reference
GET /audience/lists
Segments
A segment is a dynamic group defined by conditions. Groups are joined by OR; conditions within a group by AND.
await client.audience.segments.create({
name: "Pro users at example.com",
list_id: "list-uuid", // optional: restrict to one list
conditions: {
groups: [
{
conditions: [
{ field: "email", operator: "ends_with", value: "@example.com" },
{ field: "plan", operator: "equals", value: "pro" },
],
},
],
},
});
await client.audience.segments.list({ list_id: "list-uuid" });
await client.audience.segments.get("segment-uuid");
await client.audience.segments.delete("segment-uuid");
Operators include equals, not_equals, contains, starts_with, ends_with, is_true, is_false, and others.
API Reference
GET /audience/segments
Topics
await client.audience.topics.create({
name: "Product updates",
description: "Occasional product news",
default_subscription: "opt_in", // "opt_in" | "opt_out" — immutable after creation
visibility: "public", // "public" | "private"
});
await client.audience.topics.list({ per_page: 20 });
await client.audience.topics.get("topic-uuid");
await client.audience.topics.update("topic-uuid", { name: "Product news", visibility: "private" });
await client.audience.topics.delete("topic-uuid");
API Reference
GET /audience/topics
Properties
Custom contact properties have an immutable name and type; only the fallback can be updated.
await client.audience.properties.create({
name: "plan",
type: "string", // "string" | "number" | "boolean" | "date" | "json"
fallback_value: "free",
});
await client.audience.properties.list({ page: 1 });
await client.audience.properties.get("property-uuid");
await client.audience.properties.delete("property-uuid");
API Reference
GET /audience/properties
What’s Next
Campaigns
Send to your audience
API Reference
Full audience API reference