Inputs
Endpoints for managing a Template's inputs. Inputs define the parameters a user supplies when rendering a Template (a report title, a date range, a region, and so on).
Every input route runs template.ensureTemplates, which asserts the
templates license feature, and resolves the parent Template through the
read_access model scope, so a caller only ever operates on inputs of a
Template it may see. Read routes (list, get) need only an authenticated user;
the write routes layer on a Template permission as noted per endpoint.
Input model
Each input is a row owned by its Template. Its key columns:
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Input id |
templateId | string (UUID) | Owning Template id |
name | string | Variable name used in the Template and in lock/default maps |
label | string | null | Display label shown to users |
driver | string | Input-driver id (see below) |
dataType | string | Registered dataType-driver id (for example keyword_text) |
defn | object | null | Driver-specific configuration |
defaultValue | any | null | Default value |
help | string | null | Help text shown to users |
required | boolean | Whether a value is required (default false) |
multiple | boolean | Whether multiple values are allowed (default false) |
index | integer | Position in the input list (server-assigned) |
editorComponent | object | Server-derived editor descriptor keyed by the input driver |
createdAt / updatedAt | date | Timestamps |
driver and dataType are registered driver idsdriver is an input-driver id from the input driver manager, not a loose
name. Valid values include mdMultiInput, mdSelect, mdRadioGroup,
mdDatepicker, mdCheckbox, mdSwitch, and mdSlider. dataType is a
registered dataType-driver id such as keyword_text. The model validates
both against the registered driver keys, so values like text, select, or
string answer 400.
GET /api/templates/{id}/inputs
List a Template's inputs.
Authentication: Required
Pre-blocks: template.lookup(params.id)
Response:
A HAL collection embedding inf:template-input, queried for this templateId.
Each embedded input carries the columns described above.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs"
}
},
"start": 0,
"count": 3,
"total": 3,
"_embedded": {
"inf:template-input": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000002"
}
},
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "report_title",
"label": "Report Title",
"help": "Enter the title for this report",
"defaultValue": "Monthly Report",
"required": true,
"multiple": false,
"index": 0,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000003"
}
},
"editorComponent": {
"mdSelect": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"driver": "mdSelect",
"dataType": "keyword_text",
"defn": null,
"name": "region",
"label": "Region",
"help": null,
"defaultValue": null,
"required": false,
"multiple": false,
"index": 1,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000004"
}
},
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000004",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "scratch_input",
"label": "Scratch Input",
"help": null,
"defaultValue": null,
"required": false,
"multiple": false,
"index": 2,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
]
}
}
POST /api/templates/{id}/inputs
Add an input to a Template.
Authentication: Required
Pre-blocks: template.lookup(params.id), permission.template.write(pre.template) (Designer)
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
dataType | string | Yes | Registered dataType-driver id (for example keyword_text) |
driver | string | Yes | Input-driver id (for example mdMultiInput, mdSelect, mdDatepicker) |
name | string | Yes | Variable name used in the Template |
label | string | Yes | Display label for users |
defn | object | No | Driver-specific configuration |
help | string | null | No | Help text ("" or null allowed) |
defaultValue | any | No | Default value |
required | boolean | No | Mark as required (default false) |
multiple | boolean | No | Allow multiple values (default false) |
index is server-assigned to the current input count, so any index sent in
the payload is ignored.
Example Request:
{
"dataType": "keyword_text",
"driver": "mdMultiInput",
"name": "customer_name",
"label": "Customer Name",
"required": false,
"help": "Optional customer filter"
}
Response:
Responds 201 Created with the created input and a Location header.
{
"dataType": "keyword_text",
"driver": "mdMultiInput",
"name": "customer_name",
"label": "Customer Name",
"required": false,
"help": "Optional customer filter"
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000002"
}
},
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"dataType": "keyword_text",
"driver": "mdMultiInput",
"name": "customer_name",
"label": "Customer Name",
"required": false,
"help": "Optional customer filter",
"multiple": false,
"templateId": "00000000-0000-4000-8000-000000000001",
"index": 3,
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"defn": null,
"defaultValue": null
}
GET /api/templates/{id}/inputs/{input}
Get a single input.
Authentication: Required
Pre-blocks: template.lookup(params.id), then an input lookup scoped to the Template id and input id (a missing id answers 404)
Response:
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000002"
}
},
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "report_title",
"label": "Report Title",
"help": "Enter the title for this report",
"defaultValue": "Monthly Report",
"required": true,
"multiple": false,
"index": 0,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
PUT /api/templates/{id}/inputs/{input}
Update an input's configuration.
Authentication: Required
Pre-blocks: template.lookup(params.id), permission.template.write(pre.template) (Designer)
Request Body:
The payload is stripUnknown. Note that the update payload differs from the
create payload: name is required, dataType is not accepted here (it is
dropped), and driver/label accept null.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Variable name |
driver | string | null | No | Input-driver id |
defn | object | null | No | Driver-specific configuration |
label | string | null | No | Display label |
help | string | null | No | Help text ("" allowed) |
defaultValue | any | null | No | Default value |
required | boolean | No | Mark as required (default false) |
multiple | boolean | No | Allow multiple values (default false) |
dataType cannot be changed heredataType is dropped from the update payload. Omitting required or multiple
resets them to false rather than preserving the prior value.
Example Request:
{
"name": "report_title",
"label": "Custom Report Title",
"defaultValue": "Q1 Report",
"required": false
}
Response:
Responds 200 with the updated input.
{
"name": "report_title",
"label": "Custom Report Title",
"defaultValue": "Q1 Report",
"required": false
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/inputs/00000000-0000-4000-8000-000000000002"
}
},
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "report_title",
"label": "Custom Report Title",
"help": "Enter the title for this report",
"defaultValue": "Q1 Report",
"required": false,
"multiple": false,
"index": 0,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
DELETE /api/templates/{id}/inputs/{input}
Remove an input from a Template.
Authentication: Required
Pre-blocks: template.lookup(params.id), permission.template.edit(pre.template) (derives from template.write)
Response:
Responds 200 with an empty body (Informer convention), not 204. Runs in a
database transaction.
POST /api/templates/{id}/_input-order
Reorder a Template's inputs by writing each input's index.
Authentication: Required
Pre-blocks: template.lookup(params.id), permission.template.write(pre.template) (Designer)
Request Body:
An object with an inputs array, not a bare array of ids. Each item sets
the index for one input by id.
| Field | Type | Required | Description |
|---|---|---|---|
inputs | array | Yes | Items of { id, name?, index } |
inputs[].id | string | Yes | Input id |
inputs[].index | integer | Yes | New position |
inputs[].name | string | No | Input name (optional) |
Each item's index is written with the unique-index constraint deferred, so a
swap does not trip mid-update.
Example Request:
{
"inputs": [
{ "id": "00000000-0000-4000-8000-000000000002", "index": 0 },
{ "id": "00000000-0000-4000-8000-000000000003", "index": 1 }
]
}
Response:
Responds 200 with an empty body.
{
"inputs": [
{
"id": "00000000-0000-4000-8000-000000000002",
"index": 0
},
{
"id": "00000000-0000-4000-8000-000000000003",
"index": 1
}
]
}
GET /api/templates/{id}/input-locks
Get a Template's input locks and defaults.
Authentication: Required
Pre-blocks: template.lookup(params.id)
Response:
Returns { settings: { inputLocks, inputDefaults } }, not a flat { locks }
map. Locks pin values that users cannot change at render time; defaults pre-fill
the inputs but remain editable. Each map is conventionally shaped
{ params: { ... } }.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/00000000-0000-4000-8000-000000000001/input-locks"
}
},
"settings": {
"inputLocks": {},
"inputDefaults": {}
}
}
PUT /api/templates/{id}/input-locks
Set a Template's input locks and defaults.
Authentication: Required
Pre-blocks: template.lookup(params.id), permission.template.modifyInputSettings(pre.template) (Member-Plus)
Request Body:
Both inputLocks and inputDefaults objects are required. Each is
conventionally shaped { params: { <inputName>: <value> } }.
| Field | Type | Required | Description |
|---|---|---|---|
inputLocks | object | Yes | Locked values, keyed by input name under params |
inputDefaults | object | Yes | Default values, keyed by input name under params |
This route requires modifyInputSettings (Member-Plus), not template.write.
Example Request:
{
"inputLocks": { "params": { "region": "north" } },
"inputDefaults": { "params": { "report_title": "Monthly Report" } }
}
Response:
The two maps are merged into template.settings (other settings are preserved)
and the full updated Template is returned with a Location header, 200.
{
"inputLocks": {
"params": {
"region": "north"
}
},
"inputDefaults": {
"params": {
"report_title": "Monthly Report"
}
}
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report"
},
"inf:draft": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/comments{?sort,limit}",
"templated": true
},
"inf:template-share": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/shares/{principalId}",
"templated": true
},
"inf:template-processors": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/processors"
},
"inf:template-inputs": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/inputs"
},
"inf:template-owner": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/owner"
},
"inf:template-shares": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/shares"
},
"inf:template-files": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/files"
},
"inf:template-file-upload": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/files/_upload"
},
"inf:template-file": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/template-file"
},
"inf:export": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_export"
},
"inf:render": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_render"
},
"inf:render-prompt": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_render-prompt"
},
"inf:template-copy": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_copy"
},
"inf:processor-order": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_processor-order"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/settings"
},
"inf:template-datasets": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/datasets"
},
"inf:input-order": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/_input-order"
},
"inf:favorite": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/favorite"
},
"inf:template-input-locks": {
"href": "https://informer.example.com/api/templates/admin%3Amonthly-sales-report/input-locks"
}
},
"naturalId": "admin:monthly-sales-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 Sales Report",
"ownerId": "admin",
"slug": "monthly-sales-report",
"description": null,
"settings": {
"inputLocks": {
"params": {
"region": "north"
}
},
"inputDefaults": {
"params": {
"report_title": "Monthly Report"
}
}
},
"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,
"inputs": [
{
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "customer_name",
"label": "Customer Name",
"help": "Optional customer filter",
"defaultValue": null,
"required": false,
"multiple": false,
"index": 3,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
},
{
"editorComponent": {
"mdSelect": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"driver": "mdSelect",
"dataType": "keyword_text",
"defn": null,
"name": "region",
"label": "Region",
"help": null,
"defaultValue": null,
"required": false,
"multiple": false,
"index": 0,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
},
{
"editorComponent": {
"mdMultiInput": {}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000004",
"driver": "mdMultiInput",
"dataType": "keyword_text",
"defn": null,
"name": "report_title",
"label": "Custom Report Title",
"help": "Enter the title for this report",
"defaultValue": "Q1 Report",
"required": false,
"multiple": false,
"index": 1,
"templateId": "00000000-0000-4000-8000-000000000001",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
],
"processors": [],
"files": []
}