Theme

Emails API

The email library: author, revise and retire emails, sort out what's actually reusable, and split a shared email off for one holder.

All endpoints need a bearer token (see Overview & auth).

Endpoints

Method & pathWhat it does
GET /api/v1/emailsThe library. Filters below.
POST /api/v1/emailsCreate one. Body: subject, pre_header, from_address, body_markdown, labels[], template_id.
GET /api/v1/emails/:idOne email with its markdown body and everywhere it's used.
PATCH /api/v1/emails/:idUpdate any of the same fields.
DELETE /api/v1/emails/:idArchives it. An email that has been sent is part of the record of what went out, and the send log has to keep pointing at it.
POST /api/v1/emails/forkSplit one holder off a shared email. Body: holder_type (sequence_step or broadcast), holder_id.

Telling reusable content from per-broadcast rows

Every broadcast mints its own email row — that's deliberate, and it means the library fills up with rows that existed for exactly one send. Two questions sort it out, and neither is answerable by search:

GET /api/v1/emails?used_in[]=sequences&used_in[]=flows&used_mode=none
GET /api/v1/emails?used_in[]=broadcasts&used_mode=any
FacetMatches an email that…
broadcastsa broadcast points at
sequencesa sequence step points at
flowsa flow reaches at all — a send_email step naming it, or a start_sequence step pointing at a sequence that contains it
flows_one_offa flow's own send_email step names directly

used_mode is any (in any of them, the default), all (in all of them) or none (in none of them). Filtering happens server-side before any limit. Unknown facets are ignored rather than filtering everything away.

Every row also carries where_used, so you can see what editing an email would reach without asking a second question. Other filters: ?q= searches subject and pre-header, ?label= matches a label, ?archived=1 includes archived rows, ?limit= caps at 200.

The email-source contract

Anywhere an email is attached to something — a sequence step, a broadcast, or either one's replace-email endpoint — the request carries email_source. It is required, with no default.

ValueWhat it means after the fact
scratch A blank new row in the library. Nothing else points at it, so nothing else is affected by it.
shared The library email named by email_id, itself. One source: a later edit reaches every send that uses it, all its opens and clicks accrue to the one email, and anyone who received it anywhere counts as having received it everywhere.
copy An independent copy of it, subject kept. Edits stay here, its stats start at zero, and everyone who already received the original counts as not having received this one — so they're eligible again.

Those consequences are the whole reason the choice exists, which is why there is no default: sharing and forking are opposite answers to "what does my next edit change", and picking one for the caller means they find out which way we picked after the send.

A broadcast never shares

POST /api/v1/broadcasts and its replace-email endpoint accept only scratch and copy. shared is refused with 422, on the server, rather than trusted to a UI that only offers two options. What one broadcast sent should stay what it sent — a shared row would mean editing a sequence step could silently rewrite the record of a send that already went out.

Forking: the repair

When something is shared that should have been a copy, POST /api/v1/emails/fork splits that one holder onto a row of its own. Every other holder keeps the original. Three consequences, all at once: edits stop reaching everywhere else, the copy's stats start at zero, and everyone who received the original counts as not having received this one.

POST /api/v1/emails/fork
{ "holder_type": "sequence_step", "holder_id": 12 }

A copy made for one holder keeps the subject. Only the library's own Duplicate prepends "Copy of" — there, two identical rows in a list nobody can tell apart is the actual problem. Attached to a step, the subject is what recipients see, and nobody means to send them "Copy of".

Errors

StatusWhen
401Missing or revoked token.
404No such email.
422Validation failed, or an email source that would be a guess. The message names the three choices and what each means.

See also: Sequences API · Broadcasts API · Emails, for humans