Template language
Values, loops, conditions and filters: the language of the editor's Code view.
Templates are HTML with values written in — the language of the editor's Code view, a subset of Twig. A value the data does not give prints empty, and is named in the ReflowPDF-Missing-Variables header (or missing_variables of the JSON response). Output is HTML-escaped unless it passes through |raw.
Values#
<h1>Invoice {{ invoice.number }}</h1>
<p>{{ customer.name|upper }} · {{ invoice.date|date('F j, Y') }}</p>
<p>Total: {{ total|currency('USD') }}</p>
<p>{{ note|default('Thank you for your business.') }}</p>
<p>{{ paid ? 'Paid' : 'Due ' ~ invoice.due }}</p>Loops and conditions#
<table>
{% for item in items %}
<tr class="{{ loop.index % 2 == 1 ? 'odd' : '' }}">
<td>{{ loop.index }}</td>
<td>{{ item.description }}</td>
<td>{{ (item.quantity * item.price)|number_format(2) }}</td>
</tr>
{% else %}
<tr><td colspan="3">No items.</td></tr>
{% endfor %}
</table>
{% if balance > 0 %}
<p class="due">Balance due: {{ balance|currency('EUR') }}</p>
{% elif balance == 0 %}
<p>Paid in full.</p>
{% endif %}
{% set subtotal = 0 %}
{# a comment: not printed #}{% elif %} may also be written {% elseif %}, as Twig spells it.
| Inside a loop | Value |
|---|---|
loop.index, loop.index0 | the item's number from 1, from 0 |
loop.first, loop.last | whether it is the first, the last |
loop.length | how many items |
Operators#
- Comparison
==,!=,<,>,<=,>=; logicand,or,not(or&&,||,!). - Arithmetic
+,-,*,/,%,**(a power:2 ** 10); text joined with~. in(a value in a list or text),starts with,ends with; ranges1..5.- Choice
a ? b : c,b if a else c;a ?: b(a when it is true, that is not empty and not zero; else b);a ?? b(a when it is there and not null, else b). - Tests
isandis not:odd,even,empty,defined,null,iterable,divisible by(3),same as(x)—{{ loop.index is odd ? "shade" : "" }}.
A template that does not read (an expression, a tag or a filter the language cannot parse) is not printed half-read: the API answers 400 template_error with each place, the editor marks it.
Arithmetic takes numbers, and what stands for none: an absent value, null, "", true/false. Text that is no number is said where it is (template_error), never printed as 0: "Total: " ~ subtotal + tax adds tax to the text, as Twig reads it.
A fill has a budget: 1,000,000 loop iterations (a range counts its length before it is made: 1..10000000 stops at once) and 20,000,000 characters, of the output and of any one text a value grows to. A document of real size is far below — a table of 10,000 rows of 20 cells is 200,000 iterations; past it, template_error names the place.
Filters#
| Filter | What it does |
|---|---|
currency(code = "EUR", decimals = 2) | A number as money: {{ 1250|currency("USD") }} → $1,250.00. Symbols for USD, EUR, GBP, JPY, RUB, CHF, PLN, CAD, AUD; other codes are written before the number. |
number_format(decimals = 0, point = ".", thousands = ",") | A number with grouped thousands. |
date(format = "Y-m-d") | A date in PHP date() codes (d j m n Y y F M D l S H i s), in UTC: ISO text (2026-06-18, 2026-06-18 14:30, with or without its zone) or Unix seconds. A date written without a zone prints as written, the same in the editor, the engine and the API. |
default(value) | The value when absent, null or empty. |
upper, lower, capitalize, title, trim | Letter case and spaces. |
length, first, last, reverse, sort, join(sep), slice(start, length), keys, values | Lists and texts. |
abs, round(precision = 0) | Numbers. |
replace({"from": "to"}), striptags, nl2br | Text. |
escape (e), raw | Escaping: output is escaped unless raw (trusted HTML only). |
Printing the language as text#
{% verbatim %}Write {{ name }} to print a value.{% endverbatim %}