Skip to main content
To capture structured feedback, you author reusable Questions once, then assemble them into a Questionnaire (a form). Each Question also declares where its answers are routed, so a single form can update a Profile, create a Rating, and record an Interaction at the same time. This guide covers authoring both layers. For the model behind them, see Questions and questionnaires. All endpoints are bearer authenticated and live under https://api.[tenant].getomneo.com/api/v3.

The three layers

LayerWhat it is
QuestionA reusable definition: a stable handle, a label, an input type, and its validation, options, and routing. Authored once, referenced by any number of questionnaires.
QuestionnaireA form. An ordered set of question slots, optionally owned by another object or used standalone, identified by its purpose.
SubmissionOne fill of a form. See Submitting questionnaires and routing answers.

Creating a Question

Author a Question independently of any form:
A successful create returns 201.

Field reference

FieldTypeNotes
handle*stringStable, unique identifier used to reference the question from a questionnaire slot and from a submitted answer.
label*stringThe question text shown to the customer.
type*enumInput type. One of text, textarea, number, slider, boolean, single_select, multi_select, date, datetime, email, phone, json.
namestringInternal human name for the question.
descriptionstringInternal description.
help_textstringGuidance shown under the label.
iconstringIcon reference for rendering.
image_urlstringImage shown with the question.
validationobjectValidation rules. A slider requires validation.min and validation.max.
default_valueanyPre-filled value.
optionsarrayChoice list for single_select, multi_select, and stepped slider inputs.
live_fromdatetimeStart of the active window. Null means live with no lower bound.
live_todatetimeEnd of the active window. Null means live with no upper bound.
answer_ttl_daysintegerRe-ask cool-down in days. Null means the question is never re-asked once answered.
link_typeenumRouting destination. See Link configuration.
link_targetstringThe specific destination within the link_type.
link_write_policyenumWhether an existing value is overwritten.

Availability and re-asking

live_from and live_to bound the dates a question is asked. Either can be null, and a null bound means the question stays live on that side, so leaving both null keeps the question always live. answer_ttl_days sets how long an answer stays valid before the same question can be asked again. Set a number of days for facts that go stale, such as a preference you want to refresh each season. Leave it null for stable facts you only need once, such as gender, so the question is never re-asked after it is answered.

Choice and slider inputs

single_select and multi_select questions render their options. A slider needs validation.min and validation.max to define its range:
Routing lives on the Question, not on the form. Three fields decide what happens to each answer once it is captured:
FieldPurpose
link_typeThe kind of destination.
link_targetThe specific destination within that type.
link_write_policyWhether an existing value is replaced: overwrite_if_answered, only_if_empty, or never_overwrite.
link_type accepts these destinations:
link_typeRoutes the answer to
noneNothing. The answer is captured only.
profileA Profile field, comms or appearance attribute, or custom attribute (set by link_target).
transactionThe related transaction.
transaction_itemA specific transaction line item.
ratingA new Rating. link_target sets the score type, for example nps, csat, ces, product, place, or staff.
interactionAn Interaction record.
appointmentThe related appointment.
connectionA profile Connection.
For how link_target is shaped per destination, the write policies, and the observable result of each route, see Routing answers in the concept and Submitting questionnaires and routing answers.
Link configuration is not versioned. It lives on the Question directly, so changing where answers route affects future submissions only. Answers already written keep the destination they were routed to.

Versioning

Questions are versioned. Editing a question’s wording, type, or options creates a new immutable version and advances the question’s current version. Answers already captured stay pinned to the version that was active when they were given, so editing a question never rewrites historical responses.

The question response shape

Reading a question with GET /questions/{question} returns the versioned shape. The rendering fields you sent at the top level on create come back nested under current_version, and every version the question has had is listed in versions[]:
Create and read use different shapes. On create you send the rendering fields (label, type, options, validation, default_value, live_from, live_to, answer_ttl_days, help_text, icon, image_url) at the top level of the request body. On read those same fields come back nested under current_version, because each edit produces a new version. Identity and routing fields (handle, name, is_active, link_type, link_target, link_write_policy) stay at the top level and are never versioned.

Top-level fields

FieldTypeNotes
idintegerThe question id.
handlestringStable identifier. Not versioned.
namestringInternal human name. Not versioned.
descriptionstringInternal description.
is_systembooleanTrue for questions Omneo ships as standard.
is_activebooleanWhether the question is available for use.
metaobjectFree-form metadata.
link_typeenumRouting destination. Not versioned.
link_targetstringDestination within the link_type. Not versioned.
link_write_policyenumOverwrite policy. Not versioned. Null when not set.
is_livebooleanWhether the current version is within its live window now.
current_versionobjectThe active version’s rendering fields. See below.
versionsarrayEvery version, past and current, each with the same shape as current_version.
created_atdatetimeWhen the question was first created.
updated_atdatetimeWhen the question last changed.

Version fields

current_version and every entry in versions[] share this shape:
FieldTypeNotes
idintegerThe version id. Referenced from a submitted answer as question_version_id.
question_idintegerThe question this version belongs to.
versionintegerVersion number, increasing with each edit.
labelstringQuestion text for this version.
descriptionstringInternal description for this version.
help_textstringGuidance shown under the label.
iconstringIcon reference for rendering.
image_urlstringImage shown with the question.
typeenumInput type.
optionsarrayChoice list for select and stepped slider inputs.
validationobjectValidation rules.
default_valueanyPre-filled value.
live_fromdatetimeStart of the active window.
live_todatetimeEnd of the active window.
answer_ttl_daysintegerRe-ask cool-down in days.
created_atdatetimeWhen this version was created.
updated_atdatetimeWhen this version last changed.

Reading, updating, and deleting a question

OperationMethod and path
Read one questionGET /questions/{question}
List questionsGET /questions
Update a questionPUT /questions/{question}
Delete a questionDELETE /questions/{question}
Update a question by sending only the fields you want to change:
Editing any rendering field (label, type, options, validation, default_value, help_text, icon, image_url, live_from, live_to, answer_ttl_days) creates a new version and advances current_version. Editing an identity or routing field (name, is_active, link_type, link_target, link_write_policy) updates it in place with no new version. Delete a question with DELETE /questions/{question}.

Custom fields on questions and questionnaires

Both questions and questionnaires accept custom fields, the same typed-metadata pattern used elsewhere in Omneo (see Custom attributes). A custom field extends the resource with a value addressed by a namespace and a handle, so you can attach integration-specific data without changing the question or questionnaire shape. Create a custom field on a question:
A successful create returns 200:

Request fields

FieldTypeNotes
namespace*stringGroups related fields. Combined with handle to address the value.
handle*stringIdentifier within the namespace.
value*anyThe stored value, typed by type.
type*stringThe value’s data type.
namestringHuman-readable label.

Response fields

FieldNotes
nameHuman-readable label.
handleIdentifier within the namespace.
namespaceNamespace the field belongs to.
valueThe stored value.
typeThe value’s data type.
custom_fieldable_typeThe resource the field is attached to, question or questionnaire.
is_indexWhether the field is indexed for lookup.

Managing custom fields

OperationMethod and path
List fieldsGET /questions/{question}/custom-fields
Add a fieldPOST /questions/{question}/custom-fields
Update a fieldPUT /questions/{question}/custom-fields/{customField}
Delete a fieldDELETE /questions/{question}/custom-fields/{customField}
Questionnaires expose the same collection at /questionnaires/{questionnaire}/custom-fields, with the same request and response shape. The custom_fieldable_type comes back as questionnaire there.

Creating a Questionnaire

A Questionnaire groups questions into an ordered form. Create one with a purpose and a nested questions array of slots:
A successful create returns 201.

Field reference

FieldTypeNotes
name*stringHuman name for the form.
handlestringStable identifier for the questionnaire.
purposeenumContext the form is used in. One of booking, general, waitlist, walk_in, pre_visit, post_visit, cancellation, profile_onboarding, interaction, survey.
descriptionstringInternal description.
questionnaireable_typestringOwner object type, when the form is attached to another object such as an appointment definition.
questionnaireable_idstringOwner object id, paired with questionnaireable_type.
profile_iduuidTargets the form at a single Profile.
questionsarrayThe ordered question slots. See below.
pagesarrayOptional pages for multi-step forms.

Ownership

A questionnaire can be owned three ways:
OwnershipHow to set it
Attached to an objectSet questionnaireable_type and questionnaireable_id, for example an appointment definition that carries its booking questions.
Targeted at a ProfileSet profile_id.
GlobalSet neither. The form floats free and is found by its purpose and handle.
At most one active questionnaire exists per owner and purpose, so an owner cannot have two active post_visit forms at once.

Question slots

Each entry in questions is a slot that pins a question into the form:
Slot fieldNotes
question_idThe question to include, by id. Use this or question_handle.
question_handleThe question to include, by handle.
mapping_keyA key for this slot within the form, used to address the answer and for conditions.
sort_orderPosition in the form.
is_requiredWhether an answer is mandatory.
visibility_conditionA rule that shows or hides the slot based on earlier answers or profile attributes.

Pages

Multi-step forms group slots into pages. Each page carries a title, optional description, image_url, section_header, sort_order, and its own questions array of slots.

Versioning

Questionnaires are versioned like questions. Each change to the slot list creates a new version, and every submission is pinned to the version it was filled under.

The questionnaire response shape

Reading a questionnaire with GET /questionnaires/{questionnaire} returns its identity, ownership, and the pages[] of the current version, each page carrying its own question slots:

Top-level fields

FieldTypeNotes
idintegerThe questionnaire id.
namestringHuman name for the form.
handlestringStable identifier.
descriptionstringInternal description.
questionnaireable_typestringOwner object type. Null when the form is standalone.
questionnaireable_idstringOwner object id, paired with questionnaireable_type.
profile_iduuidSet when the form is targeted at a single Profile.
purposeenumContext the form is used in.
is_activebooleanWhether the form is available.
metaobjectFree-form metadata.
pagesarrayPages of the current version. See below.
created_atdatetimeWhen the form was created.
updated_atdatetimeWhen the form last changed.

Page fields

Each entry in pages[] has this shape:
FieldNotes
idThe page id. Set as questionnaire_page_id when placing a slot on this page.
questionnaire_version_idThe questionnaire version this page belongs to.
sort_orderPage position in the form.
titlePage heading.
descriptionPage description.
image_urlPage image.
section_headerSection grouping label.
questionsThe question slots on this page.

Adding a question slot to an existing questionnaire

To add a slot without rebuilding the form, post to the questionnaire’s questions endpoint:
FieldNotes
question_id*The question to add.
mapping_key*Key for the new slot within the form.
questionnaire_page_idPage to place the slot on, for a multi-page form.
sort_orderPosition in the form.
is_requiredWhether an answer is mandatory.
visibility_conditionShow or hide rule.
A successful create returns 201.

Managing questionnaire pages

Pages group question slots into steps for a multi-step form. Manage them under the questionnaire’s pages endpoint. Add a page:
A successful create returns 201 and responds with the questionnaire and its updated pages[].

Request fields

FieldTypeNotes
titlestringPage heading.
descriptionstringPage description.
image_urlstringPage image.
section_headerstringSection grouping label.
sort_orderintegerPage position in the form.

Managing pages

OperationMethod and path
List pagesGET /questionnaires/{questionnaire}/pages
Add a pagePOST /questionnaires/{questionnaire}/pages
Update a pagePUT /questionnaires/{questionnaire}/pages/{page}
Delete a pageDELETE /questionnaires/{questionnaire}/pages/{page}
Place a slot on a page by setting questionnaire_page_id to the page id when you add a question slot, as shown above.

Reading, updating, and deleting a questionnaire

OperationMethod and path
Read one questionnaireGET /questionnaires/{questionnaire}
List questionnairesGET /questionnaires
Update a questionnairePUT /questionnaires/{questionnaire}
Delete a questionnaireDELETE /questionnaires/{questionnaire}
Editing the slot list or pages creates a new version and advances the current version. In-flight submissions stay pinned to the version they were filled under, so a change never rewrites answers already recorded.

Errors

StatusWhen
401The bearer token is missing or invalid.
403The token is valid but lacks the scope or permission for the operation.
404The question, questionnaire, page, or custom field does not exist, or a nested resource is not under the parent named in the path.
422Validation failed. Creating a question requires handle, label, and type.