Coming from Sailthru
Edit in CMSIf you’re moving to Letterhead from Sailthru and you have reporting built on its API, this article maps what you’re calling today onto the Letterhead API, field by field.
What’s covered here: the three reads teams most often depend on — list statistics, per-campaign statistics, and profile data. Sailthru’s other APIs, such as those for sending, templates, or purchase events, aren’t mapped yet. If you rely on one of those, tell us which and we’ll extend this guide.
This is about reading data. If you’d rather keep Sailthru as your sending provider for now and use Letterhead only to build newsletters, that’s a different setup — see Create newsletters in Letterhead while sending through your own ESP.
How the concepts line up
Section titled “How the concepts line up”Most field-level questions answer themselves once the nouns match up.
| In Sailthru | In Letterhead | What changes |
|---|---|---|
| Site | Company | An API key is scoped to a company and covers every newsletter in it. |
| List — the newsletter itself | Newsletter (channel) | Identified by a short text slug rather than a numeric ID. |
| List — a saved query | Segment | A live query over your audience, not a stored copy of it. Defined once for the whole company. |
| Blast | Newsletter edition | Identified by a unique ID rather than a numeric one. |
| Profile | Contact | Identified by the email address itself. |
Two things that change in your code
Section titled “Two things that change in your code”There’s no export job to request and poll. Sailthru’s pattern of requesting an export, polling until it’s ready, then downloading a CSV has no counterpart, because there’s nothing to wait for. Newsletter and audience statistics are ordinary requests that answer immediately, and bulk contact reads page through results with a cursor. Letterhead does offer emailed CSV exports, covered at the end, but none of the reporting below needs one.
Email addresses come back in the clear. Contact records carry the actual address. If your Sailthru exports request hashed addresses, you can drop the hashing parameter and whatever you do downstream to match those hashes against your own records — Letterhead identifies a contact by the address itself.
Lists that are newsletters
Section titled “Lists that are newsletters”Sailthru needs three calls per list — inventory, last send time, statistics. In Letterhead each of these answers for every newsletter at once.
Inventory
Section titled “Inventory”GET /api/v3/channels returns every newsletter in your company. Each one carries the slug you’ll use
everywhere else, its title, and its type.
The newsletter’s creation date isn’t part of this response.
Last send time
Section titled “Last send time”There’s no “last send” field on a newsletter. Read it from the editions list instead, which covers every newsletter in one request rather than one request per list:
GET /api/v3/letters?allChannels=true&orderBy=publicationDate&asc=falseEach edition carries its publication date, title, newsletter, unique ID, and status. Add
channels[]=<slug> to narrow to particular newsletters.
Audience statistics
Section titled “Audience statistics”Two endpoints cover what stat=list returns, and between them they go further:
GET /api/v3/metrics/portfolio-health— the latest snapshot for every newsletter: total subscribers, new subscribers, unsubscribes, net growth, cleaned addresses, and the five engagement groups described below.POST /api/v3/metrics/audience— the same audience over a date range you choose, with a daily series and a comparison against the previous period. PassgroupBy: "channel"for a per-newsletter breakdown.
| Sailthru statistic | Letterhead |
|---|---|
email_count | totalSubscribers, or totalAudienceMembers for everyone including unsubscribed |
active_count | activeSubscribers |
engaged_count | loyalistsCount plus newAndEngagedCount |
passive_count | casualCount |
disengaged_count | fadingCount, or totalDisengaged if you want the status rather than the behavior |
dormant_count | ghostsCount |
new_count | newSubscribers |
optout_count | unsubscribes for a chosen window, totalUnsubscribes for all time |
hardbounce_count | Hard-bounced addresses move to a cleaned state, so totalCleaned is the newsletter-level figure. Exact bounce counts are per edition — see below. |
lists_count | singleNewsletterCount is the inverse: subscribers who read only this newsletter. For genuine cross-newsletter membership, use GET /api/v3/contacts/overlap. |
Two more rollups have no Sailthru equivalent and may save you some assembly:
GET /api/v3/contacts/overview returns company-wide totals plus how many newsletters are growing,
holding steady, or need attention, and GET /api/v3/contacts/metrics/groups breaks subscribers down
by group and newsletter with growth and health for each.
Lists that are segments
Section titled “Lists that are segments”Where a Sailthru list is really a saved query, the equivalent is a segment. Segments are defined once
at company level and evaluated live, so “engaged openers” is one segment you ask about per newsletter
rather than a query you maintain separately on every list. Add ?channel=<slug> to any read below to
scope it to a single newsletter.
| What you want | Endpoint |
|---|---|
| The segments that exist, and which newsletters they apply to | GET /api/v3/contacts/segments |
| One segment, including its live definition | GET /api/v3/contacts/segments/{segmentId} |
| How many contacts are in it right now | GET /api/v3/contacts/segments/{segmentId}/count |
| Who’s in it, paged | POST /api/v3/contacts/segments/{segmentId}/preview |
| Its engagement over time | GET /api/v3/contacts/segments/{segmentId}/engagement-timeline |
| The same figures for your whole audience, as a baseline | GET /api/v3/contacts/engagement-timeline |
The engagement timelines return, for each day, how many contacts were delivered to, how many opened,
how many clicked, and how many bounced, along with the rates those imply. Append /csv to either
timeline endpoint for the same data as a file.
Reading a segment’s definition alongside its count is worth doing: it lets you record what a number actually counted, which is something a stored list membership can’t tell you later.
The five engagement groups
Section titled “The five engagement groups”Letterhead classifies subscribers by how they’ve engaged with recent editions, without anyone having to define a rule. These groups are the closest equivalent to Sailthru’s engagement levels, and you can use them anywhere a segment is accepted.
| Group | Who’s in it |
|---|---|
| Loyalists | Opened at least three of the last five editions |
| New & Engaged | Joined in the last 30 days and engaging |
| Casual | Opens intermittently — also where subscribers sit when a newsletter is too new to judge |
| Fading | Engagement declining across recent editions |
| Ghosts | Hasn’t opened any of the last ten editions |
Counts for these come from GET /api/v3/metrics/portfolio-health, which returns them for every
newsletter in a single request. GET /api/v3/contacts/metrics/groups gives each group as a share of
the newsletter’s audience, with an up, down, or steady trend.
Older accounts may also see a newsletter-level segment list at /api/v3/audience/segments. That one
exists for setups that send through an outside provider — if you’re sending with Letterhead, build
against the company-level segment endpoints above.
Blast statistics
Section titled “Blast statistics”This is where the most work disappears. Sailthru makes you list campaigns and then fetch statistics one campaign at a time; Letterhead returns identity and performance in the same rows.
POST /api/v3/letters/metrics takes a page number, a sort direction, a date range, and an optional
list of newsletters. The envelope’s total is the number of published editions matching your filter, so
paging is straightforward. If you only care about one newsletter,
POST /api/v3/letters/metrics-by-channel does the same with a single authorization step.
| Sailthru field | Letterhead |
|---|---|
blasts[].blast_id | uniqueId |
blasts[].name | title |
blasts[].list | channel, plus segmentNames and suppressedSegmentNames when the edition was sent to particular segments |
blasts[].start_time | publicationDate |
count | accepted, with delivered alongside it |
open_total | opens, with opensUnique and opensUniqueConfirmed |
confirmed_opens | opensUniqueConfirmed |
beacon | prefetchedOpensLegacy |
estopens | projectedOpenRate — a rate rather than a count |
click_total | clicks, with clicksUnique, realClickRate, and nhiClicks |
hardbounce | hardBounces, with hardBounceRate |
softbounce | softBounces, with softBounceRate |
optout | unsubscribed |
subject | title is the edition’s title. For subject-line performance specifically, use GET /api/v3/letters/subject-line-performances. |
Two counts you may be used to seeing folded together
Section titled “Two counts you may be used to seeing folded together”Letterhead separates two populations that most providers mix into their totals, so you can report on real readers if you want to:
prefetchedOpensLegacyis opens recorded because a mail app fetched the tracking image on the reader’s behalf, rather than because a person opened the message.nhiClicksis clicks from security scanners and other automated systems rather than people.
Both are reported separately instead of being rolled into opens and clicks, so your open and click
rates can be computed either way.
Going further than Sailthru did
Section titled “Going further than Sailthru did”A few reads have no equivalent in what you’re replacing:
POST /api/v3/metrics— company-wide totals with a daily series and a previous-period comparison.GET /api/v3/letters/{uniqueId}/linksandGET /api/v3/letters/{uniqueId}/click-links— per-link click detail for a single edition.POST /api/v3/metrics/clicks/topicsandPOST /api/v3/metrics/clicks/topic-share— clicks grouped by subject, and how much you publish on a subject against how much readers click it.GET /api/v3/links— every link you’ve sent, deduplicated across editions.GET /api/v3/letters/{uniqueId}/opens-by-hour— the open curve for one edition.GET /api/v3/health/insights— deliverability signals and recommendations per newsletter.
Profile data
Section titled “Profile data”Sailthru’s request, poll, download, aggregate sequence becomes a single loop.
POST /api/v3/contacts/browse pages through your audience with a cursor: make the request, use the
cursor it returns to ask for the next page, and repeat until it’s exhausted. You can filter by
newsletter, subscription status, tag, custom field, segment, date added, or an explicit list of
addresses, and sort by name, email, status, or date added.
POST /api/v3/contacts/search is the lighter keyword-and-tag search over the same data.
These are the columns most Sailthru profile exports carry. If yours includes something not listed, it’s most likely a custom variable, which maps to a custom field.
| Sailthru column | Letterhead |
|---|---|
Profile Id | The email address is the identifier; there’s no separate profile ID |
Email Hash | email, unhashed |
Domain | Split it from the email address — it isn’t stored separately |
Profile Created Date | createdAt |
Signup | Each subscription carries its own createdAt, so you get one per newsletter rather than one per profile |
Engagement | Not a field on the contact. GET /api/v3/contacts/{email}/engagement returns that contact’s deliveries, unique opens, unique clicks, bounces, and the rates those imply. For whole cohorts, use the engagement groups above. |
| Custom variables such as date of birth, gender, or source | customFields, which you can also filter on when browsing |
Each contact also carries first and last name, tags, and a list of subscriptions, each with its newsletter, status, and dates.
Detail you couldn’t get before
Section titled “Detail you couldn’t get before”GET /api/v3/contacts/{email}— the full record.GET /api/v3/contacts/{email}/activity— that contact’s event history: opens, clicks, bounces with a reason, and more.GET /api/v3/contacts/{email}/last-active— when they last engaged.GET /api/v3/contacts/{email}/suppressions— why they’re being held back, if they are.
If you’d rather have a file
Section titled “If you’d rather have a file”POST /api/v3/contacts/export accepts the same filters as browsing, runs in the background, and
emails you a CSV: first and last name, email, your custom fields, tags, and one column per newsletter
showing membership. It doesn’t include engagement or date-added columns — browse for those.
POST /api/v3/reports/export emails a clicks, engagement, or growth report across the newsletters and
date range you choose.
What doesn’t carry over
Section titled “What doesn’t carry over”| Sailthru field | Where it stands |
|---|---|
pv | Letterhead reports on the email itself, so there’s no on-site pageview figure. |
spam per campaign | Not returned by the edition statistics endpoint. |
spam_count per list | Not available as a per-newsletter figure over the API. Deliverability signals per newsletter come from GET /api/v3/health/insights. |
source_count | Source isn’t a built-in dimension. Store it as a custom field, then filter and count on it when browsing contacts. |
Domain | Derive it from the email address. |
| List creation date | Not part of the newsletter list response. |
| Per-list last send time | Derive it from the editions list — one request covers every newsletter. |
Next steps
Section titled “Next steps”- Using the Letterhead API — authentication and what you can build
- Generate & manage API keys
- Ensuring successful newsletter delivery during ESP migration — the deliverability side of the move: domains, authentication, and warming up your sending
- API reference — the source of truth for request and response formats
Still can’t find what you need? Contact support.