Template Fields
Fields define what information users enter when creating a matter. Each field has a type that determines how it’s displayed and validated.
Field Definition
Section titled “Field Definition”Every field is an object inside its block’s fields array:
{ "key": "client.given_names", "label": "Given Names", "type": "text", "required": true, "help_text": "Optional help text shown below the field"}| Property | Required | Description |
|---|---|---|
key | Yes | Dot-notation field key (e.g. client.surname). The same key is used in document placeholders ({{ client.surname }}). |
type | Yes | The field type (see below) |
label | No | Label shown to users. Defaults to a humanised version of the key. |
required | No | Whether the field must be filled (default: false) |
default_value | No | Initial value pre-filled into the field |
placeholder | No | Placeholder text shown in an empty input |
help_text | No | Explanatory text shown below the field |
options | No | Array of choices (required for select / radio) |
validation | No | Object with pattern, min_length, max_length, min, max |
visible_when | No | Condition expression — see Conditionals |
computed_from | No | Formula to auto-calculate the value from other fields |
quick_entry | No | Show in Quick Entry mode (default: false) |
reference_key | No | For reference fields — the source key to mirror |
width | No | "full" (default), "half", or "third" for column layouts |
Field Types
Section titled “Field Types”A single-line text input. Use for names, references, and short text.
{ "key": "client.given_names", "label": "Given Names", "type": "text", "required": true}In documents: {{ client.given_names }}
textarea
Section titled “textarea”A multi-line text area. Use for addresses, notes, or longer text. Always renders full-width.
{ "key": "matter.notes", "label": "File Notes", "type": "textarea"}In documents: {{ matter.notes }}
A date picker. Stores dates in ISO format (YYYY-MM-DD).
{ "key": "client.date_of_birth", "label": "Date of Birth", "type": "date"}In documents:
- Raw:
{{ client.date_of_birth }}→ “2026-01-15” - Formatted:
{{ client.date_of_birth | date("%-d %B %Y") }}→ “15 January 2026”
currency
Section titled “currency”A number input formatted as currency.
{ "key": "matter.purchase_price", "label": "Purchase Price", "type": "currency", "required": true}In documents: {{ matter.purchase_price | currency }} → “$150,000.00”. Raw values render as the stored number, so use the currency filter for AUD formatting.
number
Section titled “number”A numeric input (no currency formatting).
{ "key": "estate.number_of_beneficiaries", "label": "Number of Beneficiaries", "type": "number"}In documents: {{ estate.number_of_beneficiaries }}
A phone number input with format validation.
{ "key": "client.phone", "label": "Phone Number", "type": "phone"}In documents: {{ client.phone }}
An email address input with validation.
{ "key": "client.email", "label": "Email Address", "type": "email"}In documents: {{ client.email }}
select
Section titled “select”A dropdown menu with predefined options.
{ "key": "client.state", "label": "State", "type": "select", "options": ["NSW", "VIC", "QLD", "SA", "WA", "TAS", "NT", "ACT"], "required": true}In documents: {{ client.state }}
A set of mutually exclusive radio buttons. Like select, requires an options array.
{ "key": "matter.urgency", "label": "Urgency", "type": "radio", "options": ["Standard", "Urgent", "Emergency"]}checkbox
Section titled “checkbox”A single standalone checkbox. For yes/no fields wired into document conditionals, prefer bool (which the rest of the engine and inverse pipeline understands).
A yes/no toggle. Stored as the strings "true" or "false".
{ "key": "estate.has_will", "label": "Deceased had a Will", "type": "bool"}reference
Section titled “reference”A read-only mirror of another field. See the Reference Fields section below.
Layout Properties
Section titled “Layout Properties”Controls field width for multi-column layouts. When multiple fields share the same row, narrower widths let them sit side by side.
| Value | Width | Use for |
|---|---|---|
"full" | 100% (default) | Addresses, notes, long text |
"half" | 50% | Names, dates, phone numbers |
"third" | 33% | State, postcode, short codes |
"fields": [ { "key": "client.given_names", "label": "Given Names", "type": "text", "width": "half" }, { "key": "client.surname", "label": "Surname", "type": "text", "width": "half" }]quick_entry
Section titled “quick_entry”Mark a field with "quick_entry": true to include it in the Quick Entry panel. Quick Entry mode presents only the most essential fields so users can capture key information fast and fill in remaining details later.
{ "key": "client.surname", "type": "text", "label": "Surname", "required": true, "quick_entry": true}Optional Properties
Section titled “Optional Properties”help_text
Section titled “help_text”Explanatory text shown below the field:
{ "key": "matter.re_line", "label": "Re: Line", "type": "text", "help_text": "Brief description used in folder naming and correspondence"}placeholder
Section titled “placeholder”Placeholder text shown in empty fields:
{ "key": "client.email", "label": "Email", "type": "email",}default_value
Section titled “default_value”Initial value pre-filled in the field:
{ "key": "client.state", "label": "State", "type": "select", "options": ["NSW", "VIC", "QLD", "SA", "WA", "TAS", "NT", "ACT"], "default_value": "NSW"}Field Naming Conventions
Section titled “Field Naming Conventions”Structure
Section titled “Structure”Fields are organised into blocks:
{{ block_name.field_name }}Common block names:
client— Client informationmatter— Matter detailsestate— Estate-specific (for Estates template)property— Property details (for Conveyancing)
Address Verification Fields
Section titled “Address Verification Fields”When an address is verified through Apple MapKit, Certum Draft emits these system-managed keys alongside the address parts. You don’t define them in matter.json, but they’re available in document templates:
| Key | Meaning |
|---|---|
<entity>.address_verified | "true" if the address has been verified via MapKit |
<entity>.address_verified_source | Verification source (e.g. mapkit) |
<entity>.address_verified_at | ISO timestamp of verification |
<entity>.address_verified_fingerprint | Stable hash of the canonical parts |
At render time, if the canonical structured parts (street, suburb, state, postcode) drift from what was verified, the engine emits an orange [DRIFT: ...] marker in the document so the lawyer can review before sending.
Boolean Naming Conventions
Section titled “Boolean Naming Conventions”Boolean fields follow a standard naming pattern:
| Prefix | Meaning | Example |
|---|---|---|
is_* | State or characteristic | property.is_strata, sale.is_auction |
has_* | Presence of something | property.has_pool, client.has_poa |
For “if not” cases in documents, prefer the Jinja not operator over creating helper inverse fields:
{%p if not sale.is_auction %}Private treaty terms...{%p endif %}The render engine blanks the string "false" to "" for all boolean values, which makes {% if x %} and {% if not x %} both behave correctly without relying on hand-built inverse fields. See Conditionals for the full guidance and the safety rules.
Best Practices
Section titled “Best Practices”| Do | Don’t |
|---|---|
client.full_name | clientFullName |
matter.settlement_date | settlementDate |
estate.deceased_name | deceased |
property.is_strata | strata_yn |
client.has_poa | poa_exists |
Use lowercase with underscores. Be descriptive but concise.
Reference Fields
Section titled “Reference Fields”Reference fields display a read-only mirror of a field defined in another block. They’re perfect for creating “checklist” blocks that show all the data needed for a specific letter in one place.
{ "key": "ref.is_strata", "label": "Property is Strata", "type": "reference", "reference_key": "property.is_strata"}| Property | Required | Description |
|---|---|---|
type | Yes | Must be "reference" |
label | Yes | Label shown to users |
reference_key | Yes | The dot-notation key of the source field (e.g., "property.is_strata") |
Reference fields:
- Show the current value of the source field in real time
- Display a Ref badge to distinguish them from editable fields
- Render boolean values as disabled checkboxes for quick visual confirmation
- Include a navigation arrow that jumps to the source block for editing
- Should never be marked as
required— they don’t represent data entry - Don’t affect completion tracking
Example: Letter Checklist Block
Section titled “Example: Letter Checklist Block”{ "name": "Sending Contract Checklist", "description": "Quick reference for the Letter to Client Sending Contract", "workflow_stage": "contract", "collapsed": true, "fields": [ { "key": "ref.is_strata", "label": "Property is Strata", "type": "reference", "reference_key": "property.is_strata" }, { "key": "ref.swimming_pool", "label": "Has Swimming Pool", "type": "reference", "reference_key": "property.swimming_pool" }, { "key": "ref.is_auction", "label": "Sale by Auction", "type": "reference", "reference_key": "sale.is_auction" }, { "key": "ref.agency_name", "label": "Agent", "type": "reference", "reference_key": "agent.agency_name" } ]}Computed Fields
Section titled “Computed Fields”Some fields are calculated from other fields using the computed_from property:
{ "key": "client.full_name", "label": "Full Name", "type": "text", "computed_from": "{client.title} {client.given_names} {client.surname}"}The value is recalculated automatically whenever any of its source fields change (debounced ~150ms).
Computed Functions
Section titled “Computed Functions”In addition to simple interpolation ({field1} {field2}), you can use these functions:
| Function | Description | Example |
|---|---|---|
uppercase() | Converts to uppercase | uppercase({client.surname}) |
lowercase() | Converts to lowercase | lowercase({client.email}) |
join_non_empty() | Joins non-empty values with a separator (last quoted arg) | join_non_empty({client.suburb}, {client.state}, {client.postcode}, " ") |
choose() | 2-arg: choose({flag}, "text"). 3-arg: choose({flag}, "true", "false"). 4-arg: choose({field}, "match", "true", "false"). | choose({property.is_strata}, "Strata", "Torrens") |
scale() | Looks up a value in a named tiered fee schedule (declared under top-level scales) | scale({purchase.price}, "nsw_transfer_duty") |
multiply() | Multiplies a field value by a constant factor | multiply({purchase.price}, 0.1) |
date_add() | Adds days from one field to a date in another field | date_add(matter.exchange_date, matter.settlement_period) |
format_long_au() | Formats an ISO date as “Friday, 4 May 2026” | format_long_au(matter.settlement_date) |
user_override_else() | Returns the manual field if non-empty, otherwise the fallback expression | user_override_else(transaction.settlement_date_manual, date_add(transaction.exchange_date, transaction.settlement_period)) |
{ "key": "purchase.deposit_amount", "label": "Deposit (10%)", "type": "currency", "computed_from": "multiply({purchase.price}, 0.1)"}{ "key": "purchase.transfer_duty", "label": "NSW Transfer Duty", "type": "currency", "computed_from": "scale({purchase.price}, nsw_transfer_duty)"}{ "key": "matter.settlement_date", "label": "Settlement Date", "type": "date", "computed_from": "date_add(matter.exchange_date, matter.settlement_period)"}Auto-Injected Date Variables
Section titled “Auto-Injected Date Variables”Certum Draft automatically provides these date variables in every template context — you do not need to define them as fields:
| Variable | Format | Example |
|---|---|---|
today.date | Full date | ”6 April 2026” |
today.date_long | Full date (same as today.date) | “6 April 2026” |
today.date_short | Short date | ”06/04/2026” |
today.date_iso | ISO format | ”2026-04-06” |
today.day | Day of month | ”6” |
today.month | Month name | ”April” |
today.year | Year only | ”2026” |
Use them in document templates:
This letter is dated {{ today.date_long }}.Common computed fields you’ll define yourself:
full_name— Combines title, given names, and surnameaddress_single_line— Combines street, suburb, state, postcode
Required vs Optional
Section titled “Required vs Optional”Mark fields as required: true when:
- The field is essential for most documents
- Missing data would cause obvious problems
Mark fields as required: false when:
- The field is only needed sometimes
- Not all matters have this information
Example: Complete Client Block
Section titled “Example: Complete Client Block”{ "name": "Client Details", "workflow_stage": "Intake", "fields": [ { "key": "client.title", "label": "Title", "type": "select", "options": ["Mr", "Mrs", "Ms", "Dr", "Prof"], "width": "third" }, { "key": "client.given_names", "label": "Given Names", "type": "text", "required": true, "width": "half", "quick_entry": true }, { "key": "client.surname", "label": "Surname", "type": "text", "required": true, "width": "half", "quick_entry": true }, { "key": "client.full_name", "label": "Full Name", "type": "text", "computed_from": "{client.title} {client.given_names} {client.surname}" }, { "key": "client.date_of_birth", "label": "Date of Birth", "type": "date" }, { "key": "client.street_address", "label": "Street Address", "type": "text", "required": true }, { "key": "client.suburb", "label": "Suburb", "type": "text", "required": true, "width": "half" }, { "key": "client.state", "label": "State", "type": "select", "options": ["NSW", "VIC", "QLD", "SA", "WA", "TAS", "NT", "ACT"], "required": true, "default_value": "NSW", "width": "third" }, { "key": "client.postcode", "label": "Postcode", "type": "text", "required": true, "width": "third" }, { "key": "client.phone", "label": "Phone", "type": "phone" }, { "key": "client.email", "label": "Email", "type": "email" } ]}