Email templates
Per (account × key × locale × channel) templates. Source format flexible (MJML / React-Email / HTML / plain / markdown). Compilation deferred to the email renderer.
Schema
{
"email_template": {
"id": "308...",
"key": "order.confirmation",
"locale": "cs",
"channel": "email",
"subject": "Tvoje objednávka {{order.name}}",
"preheader": "Potvrzujeme přijetí objednávky.",
"source_format": "mjml",
"body_source": "<mjml>...</mjml>",
"body_text": null,
"ctx_schema": {
"order": { "id": "string", "name": "string", "total_cents": "integer", ... },
"customer": { "first_name": "string", "email": "string" }
},
"category": "order",
"status": "active",
"is_default": true,
"version": 3
}
}
Upsert a template
curl -X PUT "$API/email_templates.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"key": "order.confirmation",
"locale": "cs",
"channel": "email",
"subject": "Děkujeme za objednávku {{order.name}}",
"preheader": "Brzy ti přijde balíček.",
"source_format": "mjml",
"body_source": "<mjml><mj-body><mj-section><mj-column><mj-text>Hello {{customer.first_name}}!</mj-text></mj-column></mj-section></mj-body></mjml>",
"category": "order",
"is_default": true
}'
Upsert keyed on (account, key, locale, channel) — same key across
locales lives as separate rows. Optimistic concurrency via
expected_version (optional).
Source formats
source_format | Behavior |
|---|---|
mjml | Compiled to HTML by the renderer. Mobile-responsive by default. Recommended. |
html | Raw HTML. You're on your own for inboxing / responsive layout. |
plain | Plain text only. Use for SMS-style minimal emails or fallbacks. |
markdown | Compiled to HTML. (Currently passthrough — full implementation TODO.) |
react_email | Reserved slot for React-Email JSX templates (next iteration). |
Locale fallback
When sending, the system resolves the best template for the customer's locale via:
1. exact match (key, locale, channel)
2. base locale cs-CZ → cs
3. account default 'en'
Want explicit fallback? Set commerce.email.locale_default per
account:
curl -X PUT "$API/settings/commerce.email.locale_default.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{"scope_type":"account","value":"cs"}'
Standard template keys
Recommended keys (none are auto-required, but if present they fire on these events):
| Key | Trigger |
|---|---|
order.confirmation | Order created (after checkout.complete) |
order.paid | Payment status flips to paid |
order.shipped | Fulfillment created |
order.delivered | Carrier reports delivery |
order.cancelled | Order cancelled |
return.requested | Customer files an RMA |
return.completed | Refund issued |
customer.welcome | Customer state enabled |
voucher.issued | Voucher created for this customer |
Variables (Handlebars)
The renderer compiles Handlebars-style variables. Use {{path.to.value}}
for substitution. Helpers shipped:
{{formatMoney cents 'CZK'}}→123.45 CZK{{formatDate isoString}}→ locale date{{upper string}}→ uppercase{{default value 'fallback'}}→ if value is empty
<mj-text>
Ahoj {{default customer.first_name 'Friend'}},
Děkujeme za objednávku {{order.name}} ze dne {{formatDate order.created_at}}.
Celková částka: {{formatMoney order.total_cents 'CZK'}}.
</mj-text>
ctx_schema (AI/MCP introspection)
ctx_schema is a free-form JSON description of expected ctx vars —
useful for the dashboard's template editor (autocomplete) and AI
agents that compose templates programmatically.
Resolve a template (debug)
curl "$API/email_templates/resolve.json?key=order.confirmation&locale=cs-CZ&channel=email" \
-H "Authorization: Bearer $NEVIOS_KEY"
Walks the locale fallback chain and returns whatever was found, or
404.
Endpoints
PUT /admin/2026-01/{handle}/email_templates.json (upsert)
GET /admin/2026-01/{handle}/email_templates.json
GET /admin/2026-01/{handle}/email_templates/resolve.json
DELETE /admin/2026-01/{handle}/email_templates/{id}.json
Next: Notification preferences.