DocgenTry it

Twig templating

Docgen templates are HTML + Twig. Twig is a battle-tested templating language from the Symfony ecosystem with a well-documented security model. Docgen runs every template in a strict sandbox — no PHP function passthrough, no file includes from arbitrary paths, no attribute() magic. Templates run as data.

Syntax basics

<h1>Hello {{ name }}</h1>

{% if subscriber.active %}
  <p>Welcome back, {{ subscriber.first_name }}.</p>
{% endif %}

{% for line in invoice.lines %}
  <tr>
    <td>{{ line.description }}</td>
    <td>{{ line.amount|number_format(2) }}</td>
  </tr>
{% endfor %}

Three core constructs:

  • {{ expr }} — print an expression, auto-escaped for HTML by default.
  • {% tag %} — control-flow tags like if, for, set.
  • expr|filter — apply a filter, eg. upper, number_format(2), date("Y-m-d").

What the sandbox allows

Tagsif, for, else, elseif, set, spaceless, apply

Filtersescape / e, raw, length, lower, upper, title, capitalize, trim, join, split, default, number_format, date, replace, striptags, nl2br, first, last, reverse, sort, keys, merge, slice, abs, round, format, url_encode

Functionsrange, cycle, max, min, date

Anything not on the list is refused at render time with a clear error message. If you need a filter that's missing, file an issue — we can usually add it after a security review.

Auto-escaping

Output is HTML-escaped by default. To render literal HTML (eg. you've sanitized upstream), use the raw filter:

{{ rich_text|raw }}

Be careful — rawbypasses XSS protection. If the rendered document is going to a recipient who didn't supply the data, you almost certainly want auto-escaping on.

Comments

{# This is a Twig comment. It does NOT appear in the rendered output. #}

What templates can't do

  • Make HTTP requests (the sandbox has no network primitives).
  • Read or write files (no include, no source beyond the template body itself).
  • Call arbitrary PHP functions.
  • Reference other templates — each render is one body, no composition. Composition is on the v2 roadmap.

Size cap

Templates are capped at DOCGEN_TEMPLATE_BODY_MAX_BYTES(default 256 KB). If your template is bigger, you're probably embedding base64 images — upload them via POST /v1/assets (coming in v2) and reference them by ID instead.

Next

Merge-field discovery — how the API tells you which variables your template expects before you submit data.