Template examples
Each example shows the input, the expected result, and the template to use. Comments in the results explain what the template does; they are not part of the output.
| Symbol | Meaning |
|---|---|
| ✅ | Value preserved |
| ♻️ | Input value reused |
| ➕ | Value added |
| ✨ | Value transformed |
| 🧹 | Field or list item omitted |
| 🛟 | Fallback to null |
| 🔢 | Value calculated |
| 🔍 | Value validated |
| 🛑 | Error stops processing |
Send an order confirmation
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"customer": "{{name:string}}",
"total": "{{total:number}}",
"paid": "{{paid:boolean}}",
"items": "{{items:string[]}}",
"quantities": "{{quantities:number[]}}",
"currency": "USD"
}
Restrict form fields to static values
Use in [...] for one value and [...] after the type for multiple values. A field is mandatory unless ?? omit makes it optional. For multiple values, || throw also rejects an empty array.
Static values are comma-separated and are not limited to strings. The rating below accepts only one to five stars. Numbers also work for multiple values (number[1, 2, 3]), and boolean static values work for one value (boolean in [true, false]).
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"requiredColor": "{{requiredColor:string in [black, white, green]}}",
"optionalColor": "{{optionalColor:string in [black, white, green] ?? omit}}",
"rating": "{{rating:number in [1, 2, 3, 4, 5]}}",
"requiredColors": "{{requiredColors:string[black, white, green] || throw}}",
"optionalColors": "{{optionalColors:string[black, white, green] ?? omit}}"
}
Describe a consumer-owned form
Add a final @ name suffix when a UI consumer should collect or present a variable in a particular way. The name is opaque to payload-vars: consumers define their own vocabulary. A lowercase category and optional style—such as choice, date.picker, or text.multiline—is a useful convention.
{
"title": "Approval request",
"sections": [
{
"title": "Request details",
"content": {
"Plan": "{{plan:string}}",
"Description": "{{description:string ?? omit @ text.multiline}}",
"Billing period": "{{period:string in [monthly, annual] @ choice}}",
"Extensions": "{{extensions:string[reporting, audit log, single sign-on] || throw @ choice}}",
"Needed from": "{{neededFrom:string @ date.picker}}",
"Rating": "{{rating:number in [1, 2, 3, 4, 5] ?? omit @ rating.stars}}"
}
}
]
}
The sections structure and labels belong to the consumer. Payload-vars only exposes paths and contracts. Before any payload exists, variables() provides values such as:
{
name: 'extensions',
type: 'string[]',
allowedValues: ['reporting', 'audit log', 'single sign-on'],
valueFallback: { operator: '||', action: 'throw' },
interaction: 'choice',
paths: ['$.sections[0].content.Extensions']
}
A GitHub-renderable sketch of one possible consumer UI:
Plan
Business (read-only)
Description
[Add reporting and audit-log extensions…]Billing period
◉ Monthly
○ Annual
Extensions
- Reporting
- Audit log
- Single sign-on
Needed from
2026-11-01Rating
★ ★ ★ ★ ☆
The consumer flow is: construct the template, call variables(), interpret interaction using the consumer’s own dictionary, collect ordinary payload data, and call render(payload). Interaction hints never change validation; static options still come from allowedValues, while a consumer may also source dynamic options itself.
Keep a place for a missing delivery note
?? null keeps empty text, zero, and false.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"nickname": "{{nickname:string ?? null}}",
"discount": "{{discount:number ?? null}}",
"paid": "{{paid:boolean ?? null}}",
"note": "{{note:string ?? null}}",
"instructions": "{{instructions:string ?? null}}"
}
Store unanswered form fields as null
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"nickname": "{{nickname:string || null}}",
"age": "{{age:number || null}}",
"subscribed": "{{subscribed:boolean || null}}"
}
Leave out an optional delivery note
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"name": "{{name:string}}",
"note": "{{note:string ?? omit}}",
"instructions": "{{instructions:string ?? omit}}"
}
Leave blank profile fields out of an update
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"name": "{{name:string}}",
"nickname": "{{nickname:string || omit}}"
}
Require a stock count, even when it is zero
A missing count fails; a supplied 0 is allowed.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"stock": "{{stock:number ?? throw}}"
}
Require acceptance of the terms
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"accepted": "{{accepted:boolean || throw}}"
}
Keep missing daily readings in their original positions
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"readings": "{{readings:number[ ?? null ]}}"
}
Mark blank survey answers as unanswered
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"answers": "{{answers:string[ || null ]}}"
}
Remove missing readings but keep zero readings
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"readings": "{{readings:number[ ?? omit ]}}"
}
Remove blank product tags
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"tags": "{{tags:string[ || omit ]}}"
}
Require a reading for every day
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"readings": "{{readings:number[ ?? throw ]}}"
}
Reject a guest list with a blank name
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"guests": "{{guests:string[ || throw ]}}"
}
Accept optional tag lists and clean their contents
Use || omit when an explicitly empty list should be omitted. Use ?? omit when an empty list should remain [] and only a missing or nullish list should be omitted.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"tags": "{{tags:string[ || omit ] ?? omit}}",
"savedTags": "{{savedTags:string[] || omit}}",
"suggestedTags": "{{suggestedTags:string[] ?? null}}",
"extraTags": "{{extraTags:string[] ?? omit}}"
}
Reuse the customer name for delivery
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"customer": {
"name": "{{name:string}}"
},
"delivery": {
"recipient": "{{name:string}}",
"note": "{{note:string ?? omit}}"
}
}
Build a packing slip without an optional note
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
[
"{{name:string}}",
"{{note:string ?? omit}}",
"{{total:number}}"
]
Return just the cleaned customer name
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
"{{name:string > text.trim}}"
Clean an email address and extract its domain
> changes the value; ! checks it. Read the steps from left to right.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"domain": "{{email:string > text.trim ! email.email > email.domain ! email.domain}}"
}
Reject an invalid contact email
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"email": "{{email:string ! email.email}}"
}
Clean product tags before checking for duplicates
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"tags": "{{tags:string[ > text.trim > style.upperCase || omit ] ! collection.unique}}"
}
Normalize delivery dates and keep free-text instructions
? applies the next > only when the check passes; other values stay unchanged.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"delivery": "{{delivery:string[ ? date.dateonly > date.isodatetime ]}}"
}
Normalize a delivery date, or trim the delivery instructions
~ handles values that fail the check.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"delivery": "{{delivery:string ? date.dateonly > date.isodatetime ~ text.trim}}"
}
Trim a name only when it needs cleaning
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"name": "{{name:string ? text.trim ~ text.trim}}"
}
Calculate a shift length from the original timestamps
$.start and $.end read the input JSON. No hours input is needed.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"hours": "{{hours:number = date.interval($.start,$.end) > date.msToHours}}"
}
Calculate a stay from dates already cleaned by the template
Bare paths such as stay.start read the template’s finished values.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"stay": {
"start": "{{arrival:string > date.isodatetime}}",
"end": "{{departure:string > date.isodatetime}}"
},
"hours": "{{hours:number = date.interval(stay.start,stay.end) > date.msToHours}}"
}
Use a cleaned start date with an original end timestamp
> core.omit hides the helper field while keeping its value available to functions.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"start": "{{start:string > date.isodatetime > core.omit}}",
"hours": "{{hours:number = date.interval(start,$.end) > date.msToHours}}"
}
Calculate time between two scheduled stops
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"stops": [
"{{first:string}}",
"{{last:string}}"
],
"hours": "{{hours:number = date.interval(stops[0],stops[1]) > date.msToHours}}"
}
Leave a zero-length appointment duration unset
A function result can use a fallback too.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"hours": "{{hours:number = date.interval($.start,$.end) > date.msToHours || null}}"
}
Turn imported tags into a list and count them
Split comma-separated tags into a list, then count them. This example requires the custom functions catalog.splitTags and catalog.count to be available in your application.
| Input JSON | Expected Result |
|---|---|
|
|
Template to use:
{
"tags": "{{tags:string[] = catalog.splitTags($.tags)}}",
"tagCount": "{{tagCount:number = catalog.count(tags)}}"
}
See Syntax for the full template rules.