formType: "intake"
or formType: "checkup". Client actions are documented separately under
Intakes and Check-ups.
All writes require an
Idempotency-Key header. Company ownership and creator
attribution come from the OAuth token. These endpoints do not accept client
answers, ownership IDs, objectives, measurements, media URLs or AI metadata.
Localized text
Form names and descriptions, section titles and descriptions, question names, choice labels, and linear-scale endpoint labels are language maps:{ "nl": "Wat is je doel?", "en": "What is your goal?" }.
This contract applies to intake and check-up templates.
defaultLanguage is required when creating a form. Every required text field
and every non-empty optional text map must include that language. Keys use valid
BCP 47 tags such as nl, en, en-GB, or zh-Hant. Keys are canonicalized
on write (en-gb becomes en-GB); duplicate canonical keys are rejected.
Each text field supports up to 25 languages with non-empty string values.
Reads return all stored languages. Display the exact requested language when
available, otherwise the field’s defaultLanguage value. Optional fields may
be empty objects. The API does not select languages from headers or profiles,
generate translations, or translate historical answers. Internal editors, apps,
assignment summaries and submitted answers retain their existing behavior;
this contract prepares Public API template authoring only.
{ "optionId": "...", "label": { ... } }.
Retain optionId when changing its labels or position through the Public API;
it identifies the option independently of its text and language. Omit it for
new options. IDs are scoped to a question, and duplicate or foreign IDs are
rejected. Default-language labels must also be unique within a question while
internal answers still use source text. These endpoints do not accept answers;
existing submission endpoints retain their historical answer format.
For Linear Scale questions, startLabel and endLabel are language maps in
linearScale. The numeric endpoints remain numbers. Question/section IDs,
types, required flags and numeric configuration are language-independent.
Updating localized text
UsePATCH /public/v1/forms/{formId}:
- Omitted top-level fields preserve their current values.
- A supplied text map replaces that field’s complete map. For example,
{"name":{"nl":"Intake","en":"Assessment"}}retains exactly these two languages forname. Include all languages you want to keep. - Use
{}to clear an optional text field. Required text cannot be empty. Plain strings,nullmaps andnulllanguage entries are rejected. sections, when supplied, replaces all sections and questions. Include complete text maps and existing section/question/option IDs for retained items; omit IDs for new items. Omitted section descriptions or scale endpoint labels in this replacement are cleared.- Changing
defaultLanguagerequires every retained non-empty text map to contain the new language. The selected text becomes the source string used by internal forms.
400 PUBLIC_API_INVALID_FORM_LOCALIZATION.
Invalid or foreign item IDs return 400 PUBLIC_API_INVALID_FORM_ITEM_ID.
Existing internal forms
A form without a declared source language returnsdefaultLanguage: null and
its text under und, for example "name": {"und":"Intake"}. Its options
return optionId: null until saved through the Public API. GET requests do not
allocate IDs or change existing data. Do not guess the source language.
The first Public API update must declare the source language. For example,
{"defaultLanguage":"nl"} labels the existing source text as Dutch and saves
option IDs, without translating any text. Subsequent reads return regular nl
maps and persisted IDs. und is reserved for read responses and is rejected
in write payloads. If supplying sections during this first update, replace
und with the declared language and omit null option IDs.
Internal editing does not manage these translations yet. If an internal edit
changes a source string, Public API reads return only the updated source text
for that field, avoiding stale translations. An internal choice whose source
label no longer matches a stored option has no option ID until its next Public
API save. Internal duplication follows
the existing internal behavior and produces a form without public localization.
Create a form
forms:write. The OAuth client must have a coach attribution
context. The request creates an unassigned template; use the intake or check-up
assignment endpoint to assign it to a client.
name, formType, and defaultLanguage are required. description and
sections are optional.
Each section requires title and a questions array; its description is
optional. Each question requires name and type. The optional required
field defaults to false, and order defaults to the question’s position.
Numeric configuration accepts localized comma decimals and returns canonical
numbers. Integer fields still require whole numbers. Unknown fields and invalid
question configuration return
400. Omit section, question and option IDs on creation.
Returns 201 with data.form, using the same fields as Get form detail below.
Update a form
forms:write. Send at least one of name, description,
formType, sections, or defaultLanguage. Omitted fields
retain their current values.
sections replaces the complete sections and questions array.
Include existing sectionId, questionId, and optionId values from Get form detail to
retain those items, and omit IDs for new items. Question IDs must belong to the
specified section; duplicate or foreign IDs are rejected.
The formType cannot change. A form with any existing answers returns
400 FORM_ALREADY_HAS_ANSWERS_CANNOT_EDIT. Archived, deleted and inaccessible
templates return 404. Internal objectives, measurements, media and AI metadata
remain unchanged. Returns 200 with data.form.
Archive a form
forms:write. Omit the body or send {}. Other body fields are
rejected. Archiving excludes the template from template reads and prevents new
intake and check-up assignments. Existing client assignments and answers remain
available. Repeating this action keeps the form archived. It can archive a form
that already has answers; it does not delete it.
Returns 200 with:
List forms
forms:read
Query parameters:
Response fields:
Form sections, question definitions, objective definitions, and media are not
included in this metadata endpoint.
Get form detail
forms:read
This endpoint returns a sanitized form structure for integrations that need to
render supported questions. It does not return objectives, medical/nutrition
blocks, measurement configuration, form media, AI metadata, coach IDs, or raw
model fields.
Response fields: