Skip to main content

Core Operations

Endpoints for listing, creating, reading, updating, deleting, and copying Templates, plus reading a Template's owner and the datasets its processors produce.

Every core Template route is gated by the templates license feature (req.assertFeature('templates')). On a tenant whose license lacks that feature, the whole route tree answers 400. Read access is enforced by the read_access model scope rather than a permission, so list and lookup routes return only the Templates the caller may see, and an id the caller cannot see answers 404. The id segment of any /api/templates/{id} route resolves by either the natural id (ownerId:slug) or the UUID.

GET /api/templates

List Templates as a HAL collection.

Authentication: Required

Response:

A HAL collection (rel inf:templates) of the read-access-scoped Templates. This is not a { total, limit, offset, results } envelope despite earlier docs describing it as paginated.

List templatesGET /api/templates
GET /api/templates is a HAL collection (rel inf:templates) of the read-access-scoped templates (each created template plus its working draft), NOT a {total,limit,offset,results} envelope. Gated by the `templates` license feature. The route sorts by name then slug, so each template sits next to its working draft in a stable, alphabetical order.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates"
}
},
"items": [
{
"naturalId": "admin:monthly-report",
"permissions": {
"assignTags": false,
"edit": false,
"share": false,
"delete": false,
"write": false,
"changeOwner": false,
"copy": false,
"rename": false,
"modifyInputSettings": false
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"type": "nunjucks",
"name": "Monthly Report",
"ownerId": "admin",
"slug": "monthly-report",
"description": "Generate monthly sales reports",
"settings": {},
"editingId": null,
"templateFileId": null,
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"files": [],
"inputs": [],
"processors": []
},
{
"naturalId": "admin:monthly-report-2",
"permissions": {
"assignTags": false,
"edit": false,
"share": false,
"delete": false,
"write": false,
"changeOwner": false,
"copy": false,
"rename": false,
"modifyInputSettings": false
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"type": "nunjucks",
"name": "Monthly Report",
"ownerId": "admin",
"slug": "monthly-report-2",
"description": null,
"settings": {},
"editingId": "00000000-0000-4000-8000-000000000001",
"templateFileId": null,
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"files": [],
"inputs": [],
"processors": []
},
{
"naturalId": "admin:scratch-template",
"permissions": {
"assignTags": false,
"edit": false,
"share": false,
"delete": false,
"write": false,
"changeOwner": false,
"copy": false,
"rename": false,
"modifyInputSettings": false
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"type": "nunjucks",
"name": "Scratch Template",
"ownerId": "admin",
"slug": "scratch-template",
"description": null,
"settings": {},
"editingId": null,
"templateFileId": null,
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"files": [],
"inputs": [],
"processors": []
},
"… 1 more items (4 total) — omitted from docs"
],
"start": 0,
"count": 4,
"total": 4
}
Captured from the API examples test suite; ids and timestamps are normalized.

POST /api/templates

Create a Template, optionally with initial files.

Authentication: Required

Pre-blocks: permission.templates.create (designer, plus the templates feature)

Request Body:

The payload is stripUnknown, so unrecognized fields are dropped rather than rejected. type and handler are validated against the registered drivers by the model, so unknown values answer 400. ownerId is server-derived from the caller and cannot be set from the payload.

FieldTypeRequiredDescription
namestringYesTemplate name
descriptionstringNoTemplate description
typestringNoTemplate engine, validated against registered drivers (default nunjucks)
handlerstringNoOutput handler, validated against registered drivers (default pdf)
handlerOptionsobjectNoHandler-specific configuration (default {})
initialFilesarrayNoInitial files to create (default [])

initialFiles array items:

FieldTypeRequiredDescription
rolestringYesFile role: TEMPLATE, ASSET, or DATA
filenamestringYesFilename with extension
primarybooleanNoMark as the primary Template file
contentTypestringNoMIME type
payloadstringNoFile contents as a string

Example Request:

{
"name": "Quarterly Report",
"description": "Generate quarterly sales reports",
"type": "nunjucks",
"handler": "pdf",
"handlerOptions": {
"pageSize": "letter",
"margin": "1in"
},
"initialFiles": [
{
"primary": true,
"role": "TEMPLATE",
"filename": "report.html",
"contentType": "text/html",
"payload": "<html><body><h1>{{ title }}</h1></body></html>"
},
{
"role": "ASSET",
"filename": "styles.css",
"contentType": "text/css",
"payload": "body { font-family: Arial; }"
}
]
}

Response:

The handler creates the Template, writes any initialFiles, creates a draft, and responds 201 Created with the new Template and a Location header (built from the Template's natural id).

Create a templatePOST /api/templates
Requires permission.templates.create (designer + the `templates` feature). Payload is stripUnknown; `type` defaults "nunjucks", `handler` defaults "pdf", `handlerOptions` defaults {}, `initialFiles` defaults []. `ownerId` is server-derived from the caller. The handler creates the template, writes initialFiles, creates a draft, and responds 201 with a Location header. initialFiles items are { role (TEMPLATE|ASSET|DATA, required), filename (required), primary?, contentType?, payload? }.
Request body
{
"name": "Quarterly Report",
"description": "Generate quarterly sales reports",
"type": "nunjucks",
"handler": "pdf",
"handlerOptions": {
"pageSize": "letter",
"margin": "1in"
},
"initialFiles": [
{
"primary": true,
"role": "TEMPLATE",
"filename": "report.html",
"contentType": "text/html",
"payload": "<html><body><h1>{{ title }}</h1></body></html>"
},
{
"role": "ASSET",
"filename": "styles.css",
"contentType": "text/css",
"payload": "body { font-family: Arial; }"
}
]
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report"
},
"inf:draft": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/comments{?sort,limit}",
"templated": true
},
"inf:template-share": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/shares/{principalId}",
"templated": true
},
"inf:template-processors": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/processors"
},
"inf:template-inputs": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/inputs"
},
"inf:template-owner": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/owner"
},
"inf:template-shares": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/shares"
},
"inf:template-files": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/files"
},
"inf:template-file-upload": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/files/_upload"
},
"inf:template-file": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/template-file"
},
"inf:export": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_export"
},
"inf:render": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_render"
},
"inf:render-prompt": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_render-prompt"
},
"inf:template-copy": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_copy"
},
"inf:processor-order": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_processor-order"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/settings"
},
"inf:template-datasets": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/datasets"
},
"inf:input-order": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/_input-order"
},
"inf:favorite": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/favorite"
},
"inf:template-input-locks": {
"href": "https://informer.example.com/api/templates/admin%3Aquarterly-report/input-locks"
}
},
"naturalId": "admin:quarterly-report",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"shared": false,
"name": "Quarterly Report",
"description": "Generate quarterly sales reports",
"type": "nunjucks",
"handler": "pdf",
"handlerOptions": {
"margin": "1in",
"pageSize": "letter"
},
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"ownerId": "admin",
"slug": "quarterly-report",
"settings": {},
"templateFileId": "00000000-0000-4000-8000-000000000002",
"editingId": null,
"folderId": null,
"source": null,
"sourceId": null,
"letterheadId": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/templates-list

List Templates as a flat array. This is the legacy compatibility endpoint.

Authentication: Required

Response:

A flat array (rel inf:templates-list) built by the template.list server method. It excludes drafts (rows where editingId is null) and adds per-row permissions, ownerName, favorite, tags, and naturalId. There is no pagination envelope and no server-side ordering.

List templates (legacy flat list)GET /api/templates-list
GET /api/templates-list is the legacy compatibility endpoint: a flat array (rel inf:templates-list) built by the template.list server method. Excludes drafts (editingId is null) and adds per-row permissions, ownerName, favorite, tags, and naturalId. No pagination envelope, and no server-side ordering (the fixture is sorted by naturalId for stable capture).
Response · 200
[
{
"id": "00000000-0000-4000-8000-000000000001",
"name": "Monthly Report",
"description": "Generate monthly sales reports",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"shared": false,
"ownerId": "admin",
"folderId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:monthly-report",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"ownerName": "acme Administrator",
"tags": []
},
{
"id": "00000000-0000-4000-8000-000000000002",
"name": "Quarterly Report",
"description": "Generate quarterly sales reports",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"shared": false,
"ownerId": "admin",
"folderId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:quarterly-report",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"ownerName": "acme Administrator",
"tags": []
},
{
"id": "00000000-0000-4000-8000-000000000003",
"name": "Scratch Template",
"description": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"shared": false,
"ownerId": "admin",
"folderId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:scratch-template",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"ownerName": "acme Administrator",
"tags": []
}
]
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/templates/{id}

Retrieve a single Template.

Authentication: Required

Pre-blocks: template.lookup(params.id)

Response:

The single Template (rel inf:template), with _links to its files, processors, inputs, and render endpoint.

Get a templateGET /api/templates/00000000-0000-4000-8000-000000000001
GET /api/templates/{id} returns the single template (HAL rel inf:template). The id segment resolves by naturalId (ownerId:slug) OR uuid via the read_access lookup.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001"
},
"inf:draft": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-report/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-report/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-report/comments{?sort,limit}",
"templated": true
},
"inf:template-share": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:template-processors": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/processors"
},
"inf:template-inputs": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs"
},
"inf:template-owner": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/owner"
},
"inf:template-shares": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/shares"
},
"inf:template-files": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/files"
},
"inf:template-file-upload": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/files/_upload"
},
"inf:template-file": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/template-file"
},
"inf:export": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_export"
},
"inf:render": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_render"
},
"inf:render-prompt": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_render-prompt"
},
"inf:template-copy": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_copy"
},
"inf:processor-order": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_processor-order"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/settings"
},
"inf:template-datasets": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/datasets"
},
"inf:input-order": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_input-order"
},
"inf:favorite": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:template-input-locks": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/input-locks"
}
},
"naturalId": "admin:monthly-report",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"type": "nunjucks",
"name": "Monthly Report",
"ownerId": "admin",
"slug": "monthly-report",
"description": "Generate monthly sales reports",
"settings": {},
"editingId": null,
"templateFileId": null,
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"editing": null,
"files": [],
"inputs": [],
"processors": []
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/templates/{id}

Update Template properties.

Authentication: Required

Pre-blocks: template.lookup(params.id), permission.template.write(pre.template)

Request Body:

The payload is stripUnknown. description accepts an empty string and letterheadId accepts null.

FieldTypeDescription
namestringTemplate name
descriptionstringTemplate description (empty string allowed)
typestringTemplate engine
handlerstringOutput handler
handlerOptionsobjectHandler-specific configuration
sharedbooleanShare the Template publicly within the tenant
settingsobjectTemplate settings
letterheadIdstring | nullLetterhead Template id (null clears it)

Example Request:

{
"name": "Updated Monthly Report",
"description": "Enhanced monthly sales reports with charts",
"handlerOptions": {
"pageSize": "legal",
"margin": "0.5in"
}
}

Response:

The handler re-reads through the read_access scope and responds 200 with the updated Template.

Update a templatePUT /api/templates/00000000-0000-4000-8000-000000000001
PUT /api/templates/{id} requires permission.template.write. Payload is stripUnknown; `description` accepts an empty string, `letterheadId` accepts null. Allowed fields: name, description, type, handler, handlerOptions, shared, settings, letterheadId. The handler re-reads through the read_access scope and returns the updated template.
Request body
{
"name": "Updated Monthly Report",
"description": "Enhanced monthly sales reports with charts",
"handlerOptions": {
"pageSize": "legal",
"margin": "0.5in"
}
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001"
},
"inf:draft": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report/comments{?sort,limit}",
"templated": true
},
"inf:template-share": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:template-processors": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/processors"
},
"inf:template-inputs": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs"
},
"inf:template-owner": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/owner"
},
"inf:template-shares": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/shares"
},
"inf:template-files": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/files"
},
"inf:template-file-upload": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/files/_upload"
},
"inf:template-file": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/template-file"
},
"inf:export": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_export"
},
"inf:render": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_render"
},
"inf:render-prompt": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_render-prompt"
},
"inf:template-copy": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_copy"
},
"inf:processor-order": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_processor-order"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/settings"
},
"inf:template-datasets": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/datasets"
},
"inf:input-order": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/_input-order"
},
"inf:favorite": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:template-input-locks": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/input-locks"
}
},
"naturalId": "admin:updated-monthly-report",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"type": "nunjucks",
"name": "Updated Monthly Report",
"ownerId": "admin",
"slug": "updated-monthly-report",
"description": "Enhanced monthly sales reports with charts",
"settings": {},
"editingId": null,
"templateFileId": null,
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {
"margin": "0.5in",
"pageSize": "legal"
},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"files": [],
"inputs": [],
"processors": []
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/templates/{id}

Delete a Template and its files, processors, and inputs.

Authentication: Required

Pre-blocks: template.lookup(params.id), permission.template.delete(pre.template)

Response:

Responds 200 with an empty body (Informer convention), not 204.

Delete a templateDELETE /api/templates/00000000-0000-4000-8000-000000000001
DELETE /api/templates/{id} requires permission.template.delete and removes the template plus its files/processors/inputs. Returns 200 with an EMPTY body (Informer db.remove convention), NOT 204.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

POST /api/templates/{id}/_copy

Create a copy of a Template, deep-copying its files, processors, and inputs.

Authentication: Required

Pre-blocks: template.lookup(params.id), permission.template.copy(pre.template), permission.templates.create

Request Body:

The payload is stripUnknown. progress is omitted before the copy runs.

FieldTypeDescription
namestringName for the copied Template (defaults to the original name)
progressstringProgress-tracking id

Example Request:

{
"name": "Copy of Monthly Report"
}

Response:

Responds 201 Created with the copied Template and a Location header.

Copy a templatePOST /api/templates/00000000-0000-4000-8000-000000000001/_copy
POST /api/templates/{id}/_copy requires BOTH permission.template.copy and permission.templates.create. It deep-copies files, processors, and inputs. Payload is { name?, progress? } (stripUnknown); `progress` is omitted before the copy. Responds 201 with a Location header.
Request body
{
"name": "Copy of Monthly Report"
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2"
},
"inf:draft": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/comments{?sort,limit}",
"templated": true
},
"inf:template-share": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/shares/{principalId}",
"templated": true
},
"inf:template-processors": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/processors"
},
"inf:template-inputs": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/inputs"
},
"inf:template-owner": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/owner"
},
"inf:template-shares": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/shares"
},
"inf:template-files": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/files"
},
"inf:template-file-upload": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/files/_upload"
},
"inf:template-file": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/template-file"
},
"inf:export": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_export"
},
"inf:render": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_render"
},
"inf:render-prompt": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_render-prompt"
},
"inf:template-copy": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_copy"
},
"inf:processor-order": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_processor-order"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/settings"
},
"inf:template-datasets": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/datasets"
},
"inf:input-order": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/_input-order"
},
"inf:favorite": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/favorite"
},
"inf:template-input-locks": {
"href": "https://informer.example.com/api/templates/admin%3Aupdated-monthly-report-2/input-locks"
}
},
"naturalId": "admin:updated-monthly-report-2",
"permissions": {
"assignTags": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"modifyInputSettings": true
},
"id": "00000000-0000-4000-8000-000000000002",
"tenant": "acme",
"type": "nunjucks",
"name": "Copy of Monthly Report",
"ownerId": "admin",
"slug": "updated-monthly-report-2",
"description": "Enhanced monthly sales reports with charts",
"settings": {},
"letterheadId": null,
"handler": "pdf",
"handlerOptions": {
"margin": "0.5in",
"pageSize": "legal"
},
"source": null,
"sourceId": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"editingId": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

POST /api/templates/{id}/_export

Export a Template as a portable package for import into another tenant.

Authentication: Required

Pre-blocks: template.lookup(params.id)

Response:

A downloadable export package containing the Template metadata, files, processors, and inputs.

Not shown

Exporting runs a full Template render (PDF via Puppeteer) through an internal inject and produces a download resource. It is too expensive and non-deterministic to capture as a fixture, so no response is shown here.


POST /api/templates/{id}/_takeover

Take over editing of a Template that is currently being edited by another user.

Authentication: Required

Pre-blocks: template.lookup(params.id), permission.template.write(pre.template)

Response:

Confirms the takeover after the editing draft is reassigned to the caller.

Not shown

Takeover requires a live draft owned by a different user and publishes realtime channel messages, so it is not captured as a fixture.


GET /api/templates/{id}/owner

Get the owner (user or team) of a Template.

Authentication: Required

Pre-blocks: template.lookup(params.id)

Response:

The owner Principal row, with inf:user or inf:team embedded depending on which association matched. For a user-owned Template, inf:user is embedded and the team link is absent.

Get a template ownerGET /api/templates/00000000-0000-4000-8000-000000000001/owner
GET /api/templates/{id}/owner returns the owner Principal with inf:user / inf:team embedded (whichever association matched). For a user-owned template the inf:user entity is embedded and the team link is absent.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/owner"
}
},
"id": "admin",
"userId": "admin",
"teamId": null,
"tenant": "acme",
"_embedded": {
"inf:user": {
"_links": {
"self": {
"href": "https://informer.example.com/api/users/admin"
},
"inf:memberships": {
"href": "https://informer.example.com/api/users/admin/memberships"
},
"inf:avatar-upload": {
"href": "https://informer.example.com/api/users/admin/_upload/{uploadId}/avatar-upload",
"templated": true
},
"inf:password": {
"href": "https://informer.example.com/api/users/admin/password"
},
"inf:feed": {
"href": "https://informer.example.com/api/users/admin/feed"
},
"inf:viewed-feed": {
"href": "https://informer.example.com/api/users/admin/_markFeedViewed"
},
"inf:superuser": {
"href": "https://informer.example.com/api/users/admin/superuser"
}
},
"permissions": {
"changeDomain": false,
"changeProfile": true,
"changePassword": true,
"delete": false,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": true
},
"domain": "local",
"username": "admin",
"displayName": "acme Administrator",
"familyName": "Administrator",
"givenName": "acme",
"middleName": null,
"email": null,
"data": null,
"superuser": true,
"timezone": "America/New_York",
"settings": {
"log": {
"log": false,
"info": false,
"warn": false,
"debug": false,
"error": true,
"remote": false
}
},
"enabled": true,
"source": null,
"sourceId": null,
"lastViewedFeed": null,
"tenant": "acme",
"globalPermissions": {
"ai": false,
"jobCreation": true,
"viewAllTeams": true,
"viewAllUsers": true,
"painlessScriptCreation": true
},
"userFields": {},
"locked": false,
"lockedAt": null,
"loginAttempts": 0,
"passwordSetAt": "2026-01-15T16:20:00.000Z",
"passwordExpiresAt": "2026-01-15T16:20:00.000Z",
"forgotPasswordRequestTime": null,
"mfa": null,
"mfaConfig": {},
"aiMessage": null,
"aiConsent": false,
"hasSharedDatasources": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"initials": "NA",
"colorIndex": 4,
"avatarColor": {
"background": "#81C784",
"text": "#1B5E20"
},
"managesPassword": true
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/templates/{id}/owner

Change the owner of a Template.

Authentication: Required

Pre-blocks: template.lookup(params.id), permission.template.write(pre.template), new-owner Principal lookup (by payload), permission.template.changeOwnerToTeam(pre.template, owner.teamId)

Request Body:

The new owner is resolved by looking up a Principal that matches the posted fields; an unmatched lookup answers 400.

FieldTypeDescription
idstringNew owner Principal id (user or team)

Example Request:

{
"id": "engineering-team"
}

Response:

Responds 200 with the updated Template and a Location header. The handler publishes a template-owner-change realtime message and records a templateAssigned Activity.

Not shown

Changing ownership reassigns to a different Principal and publishes realtime channel messages, so it is not captured as a fixture.


GET /api/templates/{id}/datasets

Get the datasets generated by this Template's processors.

Authentication: Required

Pre-blocks: template.lookup(params.id)

Response:

A read_access Dataset collection of the datasets generated by this Template's processors, filtered by dataset.templateProcessorId and the caller's ownerId, embedding inf:dataset (with inf:field). Datasets relate to a Template through their producing processor; there is no dataset.templateId column. A Template with no processor-backed datasets returns an empty collection.

List a template’s datasetsGET /api/templates/00000000-0000-4000-8000-000000000001/datasets
GET /api/templates/{id}/datasets returns the read_access Dataset collection of the datasets generated by this template’s processors (filtered by dataset.templateProcessorId and the caller’s ownerId), embedding inf:dataset (with inf:field). Datasets relate to a template through their producing processor; there is no dataset.templateId column. A template with no processor-backed datasets returns an empty collection.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/datasets"
}
},
"start": 0,
"count": 0,
"total": 0,
"_embedded": {
"inf:dataset": []
}
}
Captured from the API examples test suite; ids and timestamps are normalized.