Create notification content programmatically using Courier Elemental, from simple title-and-body messages to multi-channel templates with conditionals and loops.
Courier Elemental lets you define notification content as JSON instead of using the visual template designer. This is useful when your content is generated dynamically, managed in code, or needs to differ per channel.This tutorial walks through building a real notification end-to-end: starting with a simple message, then layering in channel-specific content, conditional rendering, and dynamic lists.
The fastest way to use Elemental is the sugar syntax: just title and body. Courier automatically converts this into the full Elemental format behind the scenes.
1
Send with title and body
curl -X POST https://api.courier.com/send \ -H "Authorization: Bearer $COURIER_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "message": { "to": { "email": "jane@example.com" }, "content": { "title": "Your order has shipped", "body": "Hi {{name}}, your order #{{order_id}} is on its way. Expected delivery: {{delivery_date}}." }, "data": { "name": "Jane", "order_id": "ORD-9042", "delivery_date": "Feb 12, 2026" } } }'
This sends an email with the subject “Your order has shipped” and the body text populated with your template variables. No stored template required.
2
Verify delivery
Check the Message Logs in the Courier dashboard to confirm the message was delivered and see the rendered output.
The sugar syntax is ideal for simple messages. For multi-element layouts, channel-specific content, or dynamic logic, use the full Elemental format below.
Full Elemental gives you complete control over the notification structure. Every template requires a version field ("2022-01-01") and an elements array.
1
Build a structured notification
This example creates an order confirmation with a heading, body text, and a call-to-action button.
curl -X POST https://api.courier.com/send \ -H "Authorization: Bearer $COURIER_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "message": { "to": { "email": "jane@example.com" }, "content": { "version": "2022-01-01", "elements": [ { "type": "meta", "title": "Order #{{order_id}} Confirmed" }, { "type": "text", "content": "Hi {{name}}, your order has been confirmed and is being prepared." }, { "type": "action", "content": "Track Your Order", "href": "https://example.com/orders/{{order_id}}" }, { "type": "divider" }, { "type": "text", "content": "Questions? Reply to this email or visit our help center.", "text_style": "subtext" } ] }, "data": { "name": "Jane", "order_id": "ORD-9042" } } }'
Inside a loop, {{$.item}} refers to the current item and {{$.index}} gives the zero-based index.
The format property on text elements supports "markdown" for bold, italic, and link rendering. Use double asterisks (**bold**) or single asterisks (*italic*) in your content strings.
Instead of specifying an email address directly, you can send to a user by their profile ID. Courier looks up their contact details from the stored profile.