Appearance
Templates
A template is the design of your mail — layout, text, images, logo, return address and optional QR configuration. Campaigns reference one by id.
Templates are authored in the web app
The only manual step in an otherwise fully automated integration.
The reason
Output is paper: once printed there is no edit, no recall, no refund. So a template is built in the web app's editor — which shows exactly what will print, including the zones a postal carrier needs left clear — and approved before any campaign uses it.
There is no templates:create permission, and template mutation endpoints reject API keys with 403 Forbidden: API keys cannot access this resource. That is the control keeping unreviewed layouts off paper, not an oversight to work around.
The API gives you discovery: templates:read, so your integration can find the ids it needs.
| Operation | API |
|---|---|
| Create, update, delete a template | Web app only |
| List your templates | GET /api/v1/templates |
| Read one template | GET /api/v1/templates/:id |
Authoring a template
- Web app → Templates → Create.
- Lay out the front. The editor marks reserved areas — the destination address block, the postage band and the return-address area. Content must stay out of them or the mail cannot be processed.
- Add a logo, images, and a return address if you want them.
- Insert placeholders where each recipient's details should appear (name, street, post code, post town, country, plus any custom field on the list). Every letter is personalised from these.
- Optionally set a default QR destination.
- Enable a back page if you want double-sided print.
- Save, and check the preview.
Discovering ids from your integration
ts
const res = await fetch(`${BASE}/api/v1/templates?search=summer`, {
headers: { "x-api-key": KEY },
});
const { data } = await res.json();
const templateId = data[0].id;Only templates you authored are returned; internal per-campaign snapshots never are.
Pin the id, don't search at send time
Resolve it once and store the id in configuration. Matching on name at send time means a rename in the web app silently breaks sending — or worse, matches a different template.
What a campaign inherits
templateId inherits everything, with a few overrides:
| Aspect | Inherited | Override |
|---|---|---|
| Layout and text | Always | — |
| Back page | Always | — |
| Images | Always | Send images_N + imagesManifest (multipart) |
| Logo | Yes | logo part, or skipTemplateLogo: true |
| Return address text | Yes | returnAddress |
| Return-address logo | Yes | returnAddressLogo part, or skipTemplateReturnLogo: true |
| QR configuration | Yes | qrCode object |
skipTemplateLogo and skipTemplateReturnLogo are only valid alongside templateId; sending them otherwise is a 400.
Editing a template later
Templates are mutable in the web app, but campaigns already sent are frozen. Each campaign snapshots the content at create time, so:
- Editing a template never changes mail already printed.
- Editing it does change every future campaign built from it.
If you need two variants at once, create two templates.
mode: editor or pdf
GET /api/v1/templates/:id reports mode:
mode | Meaning |
|---|---|
editor | Designed in the editor. frontContentUrl points at the layout document |
pdf | Backed by a PDF uploaded in the web app |
Both are usable as a campaign's templateId. This is separate from sending a pdf part at campaign time — see PDF campaigns.
Asset URLs expire
frontContentUrl, backContentUrl, logoUrl, returnAddressLogoUrl and each images[].url are short-lived presigned links. Use them immediately; never store or forward them. Re-request the template for fresh ones.
A template with no usable content
A template saved with empty content fails at campaign create with 400 Template has no content to inherit rather than producing a blank letter. Open it in the web app and save real content.
Next
- Campaigns — how a template becomes mail
- Campaign from a saved list
- Field reference: Templates