Form configuration
A form configuration is a JSON document that defines pages, fields, validation, translations, and integration flags. Instances created later must match this shape.
This guide walks the configuration part by part, then assembles a complete template you can copy and adapt. When you are ready, validate and persist it with the configuration endpoints at the end.
Contract version covered here: 1.0.0.
Mental model
Section titled “Mental model”| Layer | Role |
|---|---|
Structure (pages, fields, options) |
IDs, keys, types, rules — no user-facing copy |
| Translations | All display strings (titles, labels, placeholders, …) |
$ references |
Structure points at translation paths (e.g. $.pages.p1.fields.p1_k1.label) |
Literals must not be hard-coded on pages/fields. Put them under translations, then reference them with $-prefixed paths.
Every id (form, page, field, dropdown option) must be a UUID v4. Stable string **key**s (e.g. p1, p1_k1) are what you use elsewhere (including workflow view field maps).
Part 1 — Document shell
Section titled “Part 1 — Document shell”{ "version": "1.0.0", "id": "12c8aa13-88f6-40de-b7c0-4b1bef48bb51"}| Property | Purpose |
|---|---|
version |
Configuration schema version (semver). Use 1.0.0 for the current contract. |
id |
UUID of this configuration. Generate your own for production; keep it stable across updates. |
Part 2 — Controls, metadata, integrations
Section titled “Part 2 — Controls, metadata, integrations”{ "controls": { "enableLogging": false }, "metadata": { "captureTimestamp": true, "captureTags": true, "captureSummary": true, "captureLocation": false }, "integrations": { "allowSpaceAssociations": true, "allowWorkflowStarts": true }}| Block | Property | Purpose |
|---|---|---|
controls |
enableLogging |
When true, audit logging is enabled for instance updates (as supported by the deployment). |
metadata |
captureTimestamp |
Capture a timestamp with the instance. |
captureTags |
Capture tags (comma-separated string on instances when enabled). | |
captureSummary |
Capture a free-text summary. | |
captureLocation |
Capture location metadata. | |
integrations |
allowSpaceAssociations |
Allow associating filled forms with Spaces. |
allowWorkflowStarts |
Allow starting a workflow from instances of this form. Set true if you will pair with a workflow configuration. |
Part 3 — Translations
Section titled “Part 3 — Translations”Translations hold all human-readable copy. Structure elsewhere only stores $ paths into this tree.
{ "translations": { "defaultLanguage": "en", "en": { "details": { "title": "Field Snapshot", "description": "Capture a summary snapshot of a field inspection." }, "common": { "buttons": { "next": "Next", "back": "Back", "submit": "Submit" } }, "pages": { "p1": { "title": "Site details", "description": "General information about the inspection site.", "fields": { "p1_k1": { "label": "Name", "placeholder": "Enter field name", "tooltip": "Field name", "description": "Short name for this inspection." } } } } }, "fr": { "details": { "title": "Instantané de terrain", "description": "Capturez un résumé d’une inspection de terrain." } } }}| Property | Purpose |
|---|---|
defaultLanguage |
Language code used when resolving $ refs if no other language is selected (must exist as a sibling key, e.g. en). |
Language keys (en, fr, …) |
Open map of locale bundles. Add only the languages you need. |
details |
Form-level title and description. |
common.buttons |
Shared UI button labels. |
pages.<pageKey>... |
Per-page and per-field copy. Page/field keys here must match the key values on structural pages / fields. |
| Dropdown option labels | Live under fields.<fieldKey>.options.<optionKey>.label (see Part 5). |
How $ refs work: a structural property such as "label": "$.pages.p1.fields.p1_k1.label" means “resolve pages.p1.fields.p1_k1.label inside the active language bundle (falling back via defaultLanguage).” The leading $. marks a translation path — do not put the literal string on the field.
Incomplete locale bundles are fine for languages you only partially translate; ensure every $ path you reference exists under defaultLanguage.
Part 4 — Pages and fields (structure)
Section titled “Part 4 — Pages and fields (structure)”Supported field type values: text, textarea, date, dropdown, file.
Common field properties:
| Property | Purpose |
|---|---|
id |
UUID v4 for the field. |
key |
Stable key (used in translations and workflow listFields / detailFields). |
order |
Display order within the page. |
type |
One of the supported types above. |
value |
Default shown in the UI. Empty string = start blank; non-empty = pre-fill. |
label, placeholder, tooltip, description |
$ paths into translations. |
validation |
Regex applied to submitted answers, not to the config file itself. |
minLength / maxLength |
Length bounds for text-like fields. |
format |
For date fields (e.g. YYYY-MM-DD HH:mm:ss). |
visible / editable / required |
UI and submit rules. |
Example page with a text field:
{ "pages": [ { "id": "dce7622a-73c0-466d-8c2c-85362589a754", "key": "p1", "order": 1, "title": "$.pages.p1.title", "description": "$.pages.p1.description", "fields": [ { "id": "28837e41-7f0b-4f01-a2b1-794da82e124b", "key": "p1_k1", "order": 1, "type": "text", "value": "", "label": "$.pages.p1.fields.p1_k1.label", "placeholder": "$.pages.p1.fields.p1_k1.placeholder", "tooltip": "$.pages.p1.fields.p1_k1.tooltip", "description": "$.pages.p1.fields.p1_k1.description", "validation": "^(?!\\s*$).+", "minLength": 1, "maxLength": 120, "visible": true, "editable": true, "required": true } ] } ]}Part 5 — Dropdown options
Section titled “Part 5 — Dropdown options”Dropdown option labels live in translations; the structure lists option id / key / value / $ label refs.
Translations excerpt:
"p1_k3": { "label": "Status", "placeholder": "Select inspection status", "tooltip": "Inspection status", "description": "Current status of the field inspection.", "options": { "status_open": { "label": "Open" }, "status_in_progress": { "label": "In progress" }, "status_closed": { "label": "Closed" } }}Structure excerpt:
{ "type": "dropdown", "value": "open", "validation": "^(open|in_progress|closed)$", "options": [ { "id": "b1b2c3d4-e5f6-4a89-8123-111111111111", "key": "status_open", "order": 1, "value": "open", "label": "$.pages.p1.fields.p1_k3.options.status_open.label" } ]}value on the field is the option value (e.g. open), not the option key.
Part 6 — File fields
Section titled “Part 6 — File fields”When type is file, include a file object:
| Property | Purpose |
|---|---|
accept |
MIME type(s) and/or extensions the picker should allow (string or array). |
maxBytes |
Max size per file in bytes. |
multiple |
Allow more than one attachment. |
maxFiles |
Cap when multiple is true. |
At instance time, file fields are submitted as [], then binaries are uploaded via Media — see Form with file.
{ "type": "file", "value": "", "required": false, "file": { "accept": ["image/jpeg", "image/png", "image/heic"], "maxBytes": 10485760, "multiple": true, "maxFiles": 3 }}Completed example (template)
Section titled “Completed example (template)”Full configuration combining the parts above — all field types, translation $ refs, dropdown options, file metadata, metadata flags, and workflow-friendly integrations. Replace UUIDs with your own before creating in production.
{ "version": "1.0.0", "id": "12c8aa13-88f6-40de-b7c0-4b1bef48bb51", "controls": { "enableLogging": false }, "metadata": { "captureTimestamp": true, "captureTags": true, "captureSummary": true, "captureLocation": false }, "integrations": { "allowSpaceAssociations": true, "allowWorkflowStarts": true }, "translations": { "defaultLanguage": "en", "en": { "details": { "title": "Field Snapshot", "description": "A form to quickly capture a summary snapshot of a field inspection." }, "common": { "buttons": { "next": "Next", "back": "Back", "submit": "Submit" } }, "pages": { "p1": { "title": "Page 1", "description": "General information about the inspection site.", "fields": { "p1_k1": { "label": "Name", "placeholder": "Enter field name.", "tooltip": "Field Name", "description": "Something about a name." }, "p1_k2": { "label": "Date", "placeholder": "Enter today's date", "tooltip": "Today's date", "description": "Something about a date." }, "p1_k3": { "label": "Status", "placeholder": "Select inspection status", "tooltip": "Inspection status", "description": "Current status of the field inspection.", "options": { "status_open": { "label": "Open" }, "status_in_progress": { "label": "In progress" }, "status_closed": { "label": "Closed" } } } } }, "p2": { "title": "Page 2", "description": "Findings and supporting attachments.", "fields": { "p2_k1": { "label": "Summary", "placeholder": "Enter a summary of your findings.", "tooltip": "Summary Findings", "description": "Support field snapshot information and observations." }, "p2_k2": { "label": "Site photo", "placeholder": "Attach photos from the site", "tooltip": "Site photo", "description": "Optional photographic evidence." } } } } }, "fr": { "details": { "title": "Instantané de terrain", "description": "Capturez un résumé d’une inspection de terrain." } } }, "pages": [ { "id": "dce7622a-73c0-466d-8c2c-85362589a754", "key": "p1", "order": 1, "title": "$.pages.p1.title", "description": "$.pages.p1.description", "fields": [ { "id": "28837e41-7f0b-4f01-a2b1-794da82e124b", "key": "p1_k1", "order": 1, "type": "text", "value": "", "label": "$.pages.p1.fields.p1_k1.label", "placeholder": "$.pages.p1.fields.p1_k1.placeholder", "tooltip": "$.pages.p1.fields.p1_k1.tooltip", "description": "$.pages.p1.fields.p1_k1.description", "validation": "^(?!\\s*$).+", "minLength": 1, "maxLength": 120, "visible": true, "editable": true, "required": true }, { "id": "d8c9eb00-3cb5-488c-8c1e-a0fa565212e2", "key": "p1_k2", "order": 2, "type": "date", "value": "", "label": "$.pages.p1.fields.p1_k2.label", "placeholder": "$.pages.p1.fields.p1_k2.placeholder", "tooltip": "$.pages.p1.fields.p1_k2.tooltip", "description": "$.pages.p1.fields.p1_k2.description", "validation": "^(?!\\s*$).+", "format": "YYYY-MM-DD HH:mm:ss", "visible": true, "editable": true, "required": true }, { "id": "a1b2c3d4-e5f6-4a89-a012-3456789abcde", "key": "p1_k3", "order": 3, "type": "dropdown", "value": "open", "label": "$.pages.p1.fields.p1_k3.label", "placeholder": "$.pages.p1.fields.p1_k3.placeholder", "tooltip": "$.pages.p1.fields.p1_k3.tooltip", "description": "$.pages.p1.fields.p1_k3.description", "validation": "^(open|in_progress|closed)$", "visible": true, "editable": true, "required": true, "options": [ { "id": "b1b2c3d4-e5f6-4a89-8123-111111111111", "key": "status_open", "order": 1, "value": "open", "label": "$.pages.p1.fields.p1_k3.options.status_open.label" }, { "id": "c2b3c4d5-e6f7-4b90-9123-222222222222", "key": "status_in_progress", "order": 2, "value": "in_progress", "label": "$.pages.p1.fields.p1_k3.options.status_in_progress.label" }, { "id": "d3c4d5e6-f7a8-4c01-8234-333333333333", "key": "status_closed", "order": 3, "value": "closed", "label": "$.pages.p1.fields.p1_k3.options.status_closed.label" } ] } ] }, { "id": "1d2c8430-2a58-451a-a930-49ab8c219dfa", "key": "p2", "order": 2, "title": "$.pages.p2.title", "description": "$.pages.p2.description", "fields": [ { "id": "542abbf1-efc7-429e-9ca6-69d5d36f521a", "key": "p2_k1", "order": 1, "type": "textarea", "value": "", "label": "$.pages.p2.fields.p2_k1.label", "placeholder": "$.pages.p2.fields.p2_k1.placeholder", "tooltip": "$.pages.p2.fields.p2_k1.tooltip", "description": "$.pages.p2.fields.p2_k1.description", "validation": "^(?!\\s*$).+", "minLength": 1, "maxLength": 4000, "visible": true, "editable": true, "required": true }, { "id": "e4f5a6b7-c8d9-4e12-a345-67890abcdef0", "key": "p2_k2", "order": 2, "type": "file", "value": "", "label": "$.pages.p2.fields.p2_k2.label", "placeholder": "$.pages.p2.fields.p2_k2.placeholder", "tooltip": "$.pages.p2.fields.p2_k2.tooltip", "description": "$.pages.p2.fields.p2_k2.description", "validation": "^(?!\\s*$).+", "visible": true, "editable": true, "required": false, "file": { "accept": ["image/jpeg", "image/png", "image/heic"], "maxBytes": 10485760, "multiple": true, "maxFiles": 3 } } ] } ]}Adapt pages, fields, and copy for your use case — keep the same conventions (UUID ids, $ refs, matching keys).
Validate and create via the API
Section titled “Validate and create via the API”Request bodies wrap your JSON under config (optional top-level id / roles as supported by the API):
{ "id": "12c8aa13-88f6-40de-b7c0-4b1bef48bb51", "config": { }}Replace { } with the full configuration document from above.
| Method | Path | Purpose |
|---|---|---|
POST |
/v0/forms/configurations/validate |
Validate without persisting |
POST |
/v0/forms/configurations |
Create (persists; typically 201) |
PUT |
/v0/forms/configurations/{configurationId} |
Update an existing configuration |
GET |
/v0/forms/configurations/{configurationId} |
Fetch one |
GET |
/v0/forms/configurations |
List (filterable by language / states) |
Suggested order: authenticate → POST .../validate until clean → POST .../configurations to create → continue with Forms (instances) and optionally Form with file.
Exact request/response schemas: API reference.