Skip to content

Survey Presentation Format

The Survey Presentation Format is the JSON contract for conducting a live survey session step by step. Each question arrives as a self-contained document carrying everything a client needs to render it — caption, input control specification, and the valid options — while the QML engine keeps flow logic, branching, and answer validation on the server.

A Questionnaire is the verified template; a Survey is one respondent's session through it. The Presentation Format always describes a Survey: the next question for this respondent, computed from their previous answers.

Framework-Agnostic by Design

The format deliberately contains no HTML, CSS, or component references:

  1. Your UI components: Render each control with your own framework — React, Vue, Angular, native mobile, or a terminal
  2. Your styling: Questions naturally adopt your application's look and feel
  3. Server-side logic: Branching, skip logic, and postcondition validation stay in the verified QML engine — a client cannot render its way into an invalid path
  4. One round-trip per question: Submitting an answer returns the next step folded into the response

Askalot's own survey runner (SirWay) is a client of this same item model — the format is not a side export but the way surveys are actually conducted.

The Flow Loop

Driving a survey is a three-call state machine on the REST API:

Method Endpoint Purpose
GET /api/v1/surveys/{id}/current-step Current question + options + status. Initializes the session on first call.
POST /api/v1/surveys/{id}/responses Submit an answer; the next step is folded into the response.
POST /api/v1/surveys/{id}/finish Explicitly complete the survey (idempotent).

The same three operations are available as MCP tools (get_survey_current_item, submit_survey_response, finish_survey) — see the MCP Survey Tools reference.

Authentication is the standard REST credential — the X-Api-Token header (token setup).

GET current-step ──► render item ──► POST responses ──► render `next`
                                          └── status == "completed" ──► done

Informational Comment items are processed automatically on the server — clients only ever receive answerable questions.

The Step Document

GET /api/v1/surveys/{id}/current-step returns:

{
  "survey_id": "c154e81f-4c19-4998-9ffc-df6fee50561f",
  "status": "in_progress",
  "control_type": "switch",
  "required": true,
  "message": null,
  "item": {
    "id": "q_question_switch",
    "kind": "Question",
    "text": null,
    "survey_id": "c154e81f-4c19-4998-9ffc-df6fee50561f",
    "extras": {
      "title": "Do you agree to participate in this survey?",
      "blockId": "block2",
      "input": { "control": "Switch", "true": "Yes", "false": "No" },
      "outcome": null,
      "visited": false
    }
  },
  "options": [
    { "value": true, "text": "Yes" },
    { "value": false, "text": "No" }
  ]
}
Field Meaning
status "in_progress" or "completed". When completed, item is null and message explains why.
item.id The item's QML identifier — echo it back when submitting the answer.
item.kind "Question", "QuestionGroup", or "MatrixQuestion" — determines the shape of the outcome you submit.
item.extras.title The question caption to display.
item.text Optional longer descriptive text below the caption.
item.extras.input The raw QML input control specification (control name plus its configuration — labels, ranges, etc.).
control_type Lowercased control discriminator for the renderer: radio, dropdown, checkbox, switch, slider, range, editbox, textarea.
options Render-ready options, pre-extracted from the control (see below).
required Whether an answer is required to advance.

Answers Are Numeric Codes

Askalot represents answers as numbers everywhere except open text (the textarea control). A choice control's labels map integer answer codes to display strings — e.g. {1: "Hourly", 2: "Daily", 3: "Weekly"} — and the step document delivers them as options pairs ({"value": <code>, "text": <label>}). Your UI shows the text; what you submit is the code. Numeric inputs (editbox, slider, range) submit the number itself, and switch is the code 1/0 (delivered as true/false in the options fold — booleans are accepted as their numeric equivalents).

JSON serialization can turn codes into strings on the wire (the example below shows "value": "0" for label key 0); the engine coerces numeric strings back to numbers on submission, but prefer sending real numbers.

Options by Control Type

The options array is pre-folded into a renderable shape per control:

control_type options shape
radio, dropdown, checkbox [{ "value": <integer answer code>, "text": <label> }, ...]
slider [{ "type": "range", "min": 0, "max": 100, "step": 1 }]
switch [{ "value": true, "text": "Yes" }, { "value": false, "text": "No" }]
editbox, range, textarea [] — read the bounds (min/max, numeric controls) or text config from item.extras.input

Submitting Answers

POST /api/v1/surveys/{id}/responses with the item id and the outcome:

{ "item_id": "q_question_switch", "outcome": true }

The outcome shape follows the item kind. Values are the numeric answer codes described above — free text only for the textarea control:

Item kind / control Outcome shape Example
Question (radio, dropdown, slider, range, editbox) A single number — the answer code (choice controls) or the value itself (numeric controls) 2, 42
Question with switch control 1/0 (true/false accepted) true
Question with checkbox control Bitmask integer — sum of the selected answer codes (codes are powers of 2) 5 (codes 1 + 4)
Question with textarea control Free text string "We mostly use it on weekends"
QuestionGroup Array of numbers, one per entry in questions — every sub-question shares the group's single control, so all values come from the same code space [1, 3, 2]
MatrixQuestion Nested array of numbers, rows × columns — one shared control for every cell [[1, 2], [3, 1]]

The response folds in the next step, so one round-trip per question is enough:

{
  "survey_id": "c154e81f-4c19-4998-9ffc-df6fee50561f",
  "status": "in_progress",
  "output": null,
  "next": {
    "control_type": "radio",
    "item": {
      "id": "q_question_radio",
      "kind": "Question",
      "extras": {
        "title": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris?",
        "input": { "control": "Radio", "labels": { "0": "Option 0", "1": "Option 1" } }
      }
    },
    "options": [
      { "value": "0", "text": "Option 0" },
      { "value": "1", "text": "Option 1" }
    ],
    "required": true,
    "status": "in_progress"
  }
}

When the submission completes the survey, status is "completed" and next is null.

Server-Side Validation

Postconditions written in the QML (e.g. children must be fewer than household members) are evaluated on submission. A rejected answer returns an error envelope whose detail carries the question's hint message, and the flow does not advance — re-render the current item with the hint. The client never needs to replicate validation rules; they live with the questionnaire's formal definition.

Initialize before submitting

The session state is created lazily by the first GET /current-step call. Submitting a response to an uninitialized survey returns an error asking you to read the current step first.

Typical Embedding Pattern

  1. Create Surveys for your respondents via the REST API (POST /api/v1/surveys) or via a Campaign
  2. Your backend proxies the three flow calls with its API token (keep the token server-side — never ship it to a browser)
  3. Your frontend renders each step document with its own components and posts outcomes back
  4. On status: "completed", close the session; responses are immediately available to the data pipeline

If you don't need custom rendering, Askalot's hosted survey runner (SirWay) already serves every survey at a magic link — the Presentation Format is for when the survey must live inside your product experience.

Next Steps

  • REST API


    Authentication, entity CRUD, and the full endpoint reference

    REST API

  • MCP Survey Tools


    The same flow loop for AI agents

    Survey Tools

  • QML Syntax


    The verified questionnaire language behind every survey

    QML Guide