https://api.[tenant].getomneo.com/api/v3.
The three layers
| Layer | What it is |
|---|---|
| Question | A reusable definition: a stable handle, a label, an input type, and its validation, options, and routing. Authored once, referenced by any number of questionnaires. |
| Questionnaire | A form. An ordered set of question slots, optionally owned by another object or used standalone, identified by its purpose. |
| Submission | One fill of a form. See Submitting questionnaires and routing answers. |
Creating a Question
Author a Question independently of any form:201.
Field reference
| Field | Type | Notes |
|---|---|---|
handle* | string | Stable, unique identifier used to reference the question from a questionnaire slot and from a submitted answer. |
label* | string | The question text shown to the customer. |
type* | enum | Input type. One of text, textarea, number, slider, boolean, single_select, multi_select, date, datetime, email, phone, json. |
name | string | Internal human name for the question. |
description | string | Internal description. |
help_text | string | Guidance shown under the label. |
icon | string | Icon reference for rendering. |
image_url | string | Image shown with the question. |
validation | object | Validation rules. A slider requires validation.min and validation.max. |
default_value | any | Pre-filled value. |
options | array | Choice list for single_select, multi_select, and stepped slider inputs. |
live_from | datetime | Start of the active window. Null means live with no lower bound. |
live_to | datetime | End of the active window. Null means live with no upper bound. |
answer_ttl_days | integer | Re-ask cool-down in days. Null means the question is never re-asked once answered. |
link_type | enum | Routing destination. See Link configuration. |
link_target | string | The specific destination within the link_type. |
link_write_policy | enum | Whether 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:
Link configuration
Routing lives on the Question, not on the form. Three fields decide what happens to each answer once it is captured:| Field | Purpose |
|---|---|
link_type | The kind of destination. |
link_target | The specific destination within that type. |
link_write_policy | Whether an existing value is replaced: overwrite_if_answered, only_if_empty, or never_overwrite. |
link_type accepts these destinations:
link_type | Routes the answer to |
|---|---|
none | Nothing. The answer is captured only. |
profile | A Profile field, comms or appearance attribute, or custom attribute (set by link_target). |
transaction | The related transaction. |
transaction_item | A specific transaction line item. |
rating | A new Rating. link_target sets the score type, for example nps, csat, ces, product, place, or staff. |
interaction | An Interaction record. |
appointment | The related appointment. |
connection | A profile Connection. |
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 withGET /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
| Field | Type | Notes |
|---|---|---|
id | integer | The question id. |
handle | string | Stable identifier. Not versioned. |
name | string | Internal human name. Not versioned. |
description | string | Internal description. |
is_system | boolean | True for questions Omneo ships as standard. |
is_active | boolean | Whether the question is available for use. |
meta | object | Free-form metadata. |
link_type | enum | Routing destination. Not versioned. |
link_target | string | Destination within the link_type. Not versioned. |
link_write_policy | enum | Overwrite policy. Not versioned. Null when not set. |
is_live | boolean | Whether the current version is within its live window now. |
current_version | object | The active version’s rendering fields. See below. |
versions | array | Every version, past and current, each with the same shape as current_version. |
created_at | datetime | When the question was first created. |
updated_at | datetime | When the question last changed. |
Version fields
current_version and every entry in versions[] share this shape:
| Field | Type | Notes |
|---|---|---|
id | integer | The version id. Referenced from a submitted answer as question_version_id. |
question_id | integer | The question this version belongs to. |
version | integer | Version number, increasing with each edit. |
label | string | Question text for this version. |
description | string | Internal description for this version. |
help_text | string | Guidance shown under the label. |
icon | string | Icon reference for rendering. |
image_url | string | Image shown with the question. |
type | enum | Input type. |
options | array | Choice list for select and stepped slider inputs. |
validation | object | Validation rules. |
default_value | any | Pre-filled value. |
live_from | datetime | Start of the active window. |
live_to | datetime | End of the active window. |
answer_ttl_days | integer | Re-ask cool-down in days. |
created_at | datetime | When this version was created. |
updated_at | datetime | When this version last changed. |
Reading, updating, and deleting a question
| Operation | Method and path |
|---|---|
| Read one question | GET /questions/{question} |
| List questions | GET /questions |
| Update a question | PUT /questions/{question} |
| Delete a question | DELETE /questions/{question} |
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 anamespace and a handle, so you can attach integration-specific data without changing the question or questionnaire shape.
Create a custom field on a question:
200:
Request fields
| Field | Type | Notes |
|---|---|---|
namespace* | string | Groups related fields. Combined with handle to address the value. |
handle* | string | Identifier within the namespace. |
value* | any | The stored value, typed by type. |
type* | string | The value’s data type. |
name | string | Human-readable label. |
Response fields
| Field | Notes |
|---|---|
name | Human-readable label. |
handle | Identifier within the namespace. |
namespace | Namespace the field belongs to. |
value | The stored value. |
type | The value’s data type. |
custom_fieldable_type | The resource the field is attached to, question or questionnaire. |
is_index | Whether the field is indexed for lookup. |
Managing custom fields
| Operation | Method and path |
|---|---|
| List fields | GET /questions/{question}/custom-fields |
| Add a field | POST /questions/{question}/custom-fields |
| Update a field | PUT /questions/{question}/custom-fields/{customField} |
| Delete a field | DELETE /questions/{question}/custom-fields/{customField} |
/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 apurpose and a nested questions array of slots:
201.
Field reference
| Field | Type | Notes |
|---|---|---|
name* | string | Human name for the form. |
handle | string | Stable identifier for the questionnaire. |
purpose | enum | Context the form is used in. One of booking, general, waitlist, walk_in, pre_visit, post_visit, cancellation, profile_onboarding, interaction, survey. |
description | string | Internal description. |
questionnaireable_type | string | Owner object type, when the form is attached to another object such as an appointment definition. |
questionnaireable_id | string | Owner object id, paired with questionnaireable_type. |
profile_id | uuid | Targets the form at a single Profile. |
questions | array | The ordered question slots. See below. |
pages | array | Optional pages for multi-step forms. |
Ownership
A questionnaire can be owned three ways:| Ownership | How to set it |
|---|---|
| Attached to an object | Set questionnaireable_type and questionnaireable_id, for example an appointment definition that carries its booking questions. |
| Targeted at a Profile | Set profile_id. |
| Global | Set neither. The form floats free and is found by its purpose and handle. |
post_visit forms at once.
Question slots
Each entry inquestions is a slot that pins a question into the form:
| Slot field | Notes |
|---|---|
question_id | The question to include, by id. Use this or question_handle. |
question_handle | The question to include, by handle. |
mapping_key | A key for this slot within the form, used to address the answer and for conditions. |
sort_order | Position in the form. |
is_required | Whether an answer is mandatory. |
visibility_condition | A rule that shows or hides the slot based on earlier answers or profile attributes. |
Pages
Multi-step forms group slots intopages. 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 withGET /questionnaires/{questionnaire} returns its identity, ownership, and the pages[] of the current version, each page carrying its own question slots:
Top-level fields
| Field | Type | Notes |
|---|---|---|
id | integer | The questionnaire id. |
name | string | Human name for the form. |
handle | string | Stable identifier. |
description | string | Internal description. |
questionnaireable_type | string | Owner object type. Null when the form is standalone. |
questionnaireable_id | string | Owner object id, paired with questionnaireable_type. |
profile_id | uuid | Set when the form is targeted at a single Profile. |
purpose | enum | Context the form is used in. |
is_active | boolean | Whether the form is available. |
meta | object | Free-form metadata. |
pages | array | Pages of the current version. See below. |
created_at | datetime | When the form was created. |
updated_at | datetime | When the form last changed. |
Page fields
Each entry inpages[] has this shape:
| Field | Notes |
|---|---|
id | The page id. Set as questionnaire_page_id when placing a slot on this page. |
questionnaire_version_id | The questionnaire version this page belongs to. |
sort_order | Page position in the form. |
title | Page heading. |
description | Page description. |
image_url | Page image. |
section_header | Section grouping label. |
questions | The 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:| Field | Notes |
|---|---|
question_id* | The question to add. |
mapping_key* | Key for the new slot within the form. |
questionnaire_page_id | Page to place the slot on, for a multi-page form. |
sort_order | Position in the form. |
is_required | Whether an answer is mandatory. |
visibility_condition | Show or hide rule. |
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:201 and responds with the questionnaire and its updated pages[].
Request fields
| Field | Type | Notes |
|---|---|---|
title | string | Page heading. |
description | string | Page description. |
image_url | string | Page image. |
section_header | string | Section grouping label. |
sort_order | integer | Page position in the form. |
Managing pages
| Operation | Method and path |
|---|---|
| List pages | GET /questionnaires/{questionnaire}/pages |
| Add a page | POST /questionnaires/{questionnaire}/pages |
| Update a page | PUT /questionnaires/{questionnaire}/pages/{page} |
| Delete a page | DELETE /questionnaires/{questionnaire}/pages/{page} |
questionnaire_page_id to the page id when you add a question slot, as shown above.
Reading, updating, and deleting a questionnaire
| Operation | Method and path |
|---|---|
| Read one questionnaire | GET /questionnaires/{questionnaire} |
| List questionnaires | GET /questionnaires |
| Update a questionnaire | PUT /questionnaires/{questionnaire} |
| Delete a questionnaire | DELETE /questionnaires/{questionnaire} |
Errors
| Status | When |
|---|---|
401 | The bearer token is missing or invalid. |
403 | The token is valid but lacks the scope or permission for the operation. |
404 | The question, questionnaire, page, or custom field does not exist, or a nested resource is not under the parent named in the path. |
422 | Validation failed. Creating a question requires handle, label, and type. |
Related
- Questions and questionnaires concept
- Submitting questionnaires and routing answers
- Working with appointments
- Add question API
- Browse questions API
- Add questionnaire API
- Browse questionnaires API
- Add questionnaire question API
- Add questionnaire page API
- Question custom field API
- Questionnaire custom field API