Versioning & git
Keep templates in a repository you already review and deploy from. Connect it once per account; every push becomes an immutable version, and every message records the version and the commit it rendered from.
Repository layout
templates/
welcome.twig body (Twig) — or welcome.liquid
welcome.de-AT.twig welcome for locale de-AT
welcome.de.twig welcome for locale de
welcome.text.twig optional plain-text part
welcome.json optional sidecar
layouts/
base.twig optional; the body replaces {# body #}The file name is the slug. The extension picks the engine; a sidecar that disagrees is an error, not a guess. A retention number above your plan ceiling is lowered to it, never refused. Everything is compile-checked at sync, and one bad file holds back the whole push — a sync is a single transaction.
A send of welcome with locale de-AT looks for welcome.de-AT, then welcome.de-at, then welcome.de, then welcome. The file is that slug plus the extension, so the Twig file is welcome.de-AT.twig and the Liquid file would be welcome.de-AT.liquid. A slug that already names a locale, such as welcome.de, is used as written and does not fall back.
A sidecar is optional, JSON or YAML. These are the keys a sync reads. variables_schema is accepted in place of variables. engine must be twig or liquid and must agree with the extension. layout is a slug under layouts/, and that file must contain exactly one {# body #}.
{
"subject": "Hello {{ name }}",
"name": "Welcome",
"description": "Sent when an account is created.",
"variables": { "required": ["name"] },
"is_sensitive": false,
"content_retention_days": 30,
"engine": "twig",
"layout": "base"
}Connecting a repository
- Templates → Sync from git → paste the SSH clone URL, the branch, and an optional folder inside the repo.
- We generate an ed25519 deploy key. Add the public half to the repository as a read-only deploy key (GitHub: Settings → Deploy keys; GitLab: Settings → Repository → Deploy keys). The private half never leaves our keyring.
- Add the push webhook URL shown once at connect. The token in the URL is the secret; the body is ignored. Without it, changes still arrive on the hourly fetch.
- Press Sync now.
We only ever read. The remote must be a public host — nothing on a private network — and an HTTPS URL is accepted only for a public repository, never with a token in it.
What a sync does
A new version is minted only when the subject, a body, the engine or the variables changed; a metadata-only edit updates the template without a version. Versions are immutable and never deleted. Deleting the file and pushing leaves the template sendable. The sync counts it as an orphan and does not remove it. A push does not retire a template, and the panel and the API have no retire action. A template created in the panel is never overwritten by a file of the same slug; the sync stops and says so.