message.content:
string
required
The Elemental format version. The only supported value is
"2022-01-01".CourierElement[]
required
The elements that make up the notification. Every type is documented below.
title and body instead of a full element tree, and omit version and elements. Courier converts it to full Elemental internally: title becomes a meta element, body becomes a text element.
if/loop/ref, locales, and styling.
Element nesting
Elemental is a tree. The root elements array holds elements, and the container types hold their own elements arrays:
group: conditions and loopschannel: channel-specific contentcolumns: holdscolumnelementslist: holdslist-itemelements
type string. Each section below gives its value, for example "text" for the text element.
Most elements also accept these shared properties:
channels: an array of channel names. The element renders only for the listed channels.if: a condition that controls whether the element renders. Accepts a string expression or a .loop: an expression that repeats the element for each item in an array.ref: a reference identifier for the element.
locales object for multi-language content, covered in . Where a property is central to an element, such as if and loop on group and list, it is listed in that element’s fields below.
Text fields support variables. They resolve against message.data, for example data.first_name.
The elements
Every element also takes
if, loop, ref, and channels. Those four are documented once, in .
Sending a document and storing one differ
A send takes the document above asmessage.content and renders it for every channel it routes to.
Storing the same document on a Template needs its top-level elements wrapped in a channel element. A send accepts a bare element list. The write API does not, and its rejection names a schema path rather than the rule you broke. covers the round trip.