Skip to main content
The questionnaire report contains the structured form a user was shown, the path they took through any conditional branches, and the answer for each visible item. It is returned per node, so multi-instance workflows (for example, one questionnaire per UBO) carry one entry per occurrence.
Didit KYC questionnaire report showing structured answers, sections and element types

Overview

Each questionnaire response describes:
  • The questionnaire version the user saw (title, description, languages, version metadata, sections).
  • The visible items for the path the user actually took through the form’s graph — items hidden by conditional logic are dropped from the response.
  • The answer for every visible interactive item, in the shape that matches its element_type.
  • A single status for the response as a whole.
Layout elements are reshaped rather than answered: each SECTION_HEADER becomes a section boundary (its title and description become the section’s title/description), while HEADING, PARAGRAPH, and SEPARATOR stay in items[] without an answer key so the report keeps the same visual structure the user saw.

Where it appears

The questionnaire report appears as the plural array questionnaire_responses[] in GET /v3/session/{sessionId}/decision/, for both KYC and KYB sessions, whenever a questionnaire feature ran. The field is null until at least one questionnaire instance has started. Each entry carries a node_id so multi-instance workflows can disambiguate which graph step produced it.
GET /v3/session/{sessionId}/decision/
  ──▶ { "questionnaire_responses": [ { node_id, questionnaire_id, title, status, sections, … }, … ] }

Item shape

See Questionnaire response in the Data Models reference for the canonical schema.
interface QuestionnaireResponse {
  questionnaire_id: string;          // UUID of the questionnaire version that was answered
  title: string;                     // Questionnaire name, as set in the Console
  description: string | null;
  languages: string[];               // Supported language codes
  default_language: string;          // Default language code
  is_active: boolean;
  is_simple_questionnaire: boolean;  // true = flat list, false = branching graph
  questionnaire_group_id: string;    // UUID shared by all versions of the same questionnaire
  version: number;                   // Version number within the group
  published_at: string | null;       // ISO 8601 — when this version was published
  status: "Approved" | "In Review" | "Not Finished";
  sections: Array<{
    title: string | null;            // From the SECTION_HEADER that opens the section
    description: string | null;
    items: QuestionnaireItem[];
  }>;
  node_id: string | null;            // Workflow graph node that ran this questionnaire
}

interface QuestionnaireItem {
  uuid: string;                      // Form element UUID
  value: string;                     // Stable node id of the element within the questionnaire graph
  element_type:
    | "SHORT_TEXT" | "LONG_TEXT"
    | "DROPDOWN" | "SINGLE_CHOICE" | "MULTIPLE_CHOICE"
    | "NUMBER" | "EMAIL" | "PHONE" | "ADDRESS" | "COUNTRY"
    | "DATE_PICKER" | "TIME"
    | "CONSENT"
    | "FILE_UPLOAD" | "IMAGE"
    | "REPEATABLE_GROUP"
    | "HEADING" | "PARAGRAPH" | "SEPARATOR";   // layout-only — no answer key
  is_required: boolean;
  title: string | null;              // Localized
  description: string | null;        // Only populated on HEADING / PARAGRAPH text blocks
  placeholder: string | null;        // Localized
  choices: Array<{                   // DROPDOWN / SINGLE_CHOICE / MULTIPLE_CHOICE
    label: string;                   // Localized
    value: string;                   // Stable across languages
    requires_text_input?: boolean;   // Selecting this option triggers a free-text follow-up
  }> | null;
  max_files: number | null;          // FILE_UPLOAD / IMAGE upload cap (1–5)
  required_if: {                     // Conditional requirement rule, or null
    rules: Array<{ field: string; operator: string; value?: unknown }>;
    logic: "and" | "or";
  } | null;
  repeatable_config: {               // REPEATABLE_GROUP only, or null
    min_items?: number;
    max_items?: number;
    item_label?: string;             // Localized
    fields: Array<object>;           // Sub-field definitions (value, element_type, title, …)
  } | null;
  answer?: Answer | null;            // Omitted on HEADING / PARAGRAPH / SEPARATOR; null when unanswered
}
SECTION_HEADER elements never appear in items[] — they open a new section and supply its title and description.

Element types

Element typeAnswer shapeNotes
SHORT_TEXT, LONG_TEXT{ value: string }Free text.
EMAIL, DATE_PICKER, TIME{ value: string }Typed text variants.
NUMBER{ value: number }JSON number — validated server-side as numeric.
COUNTRY{ value: string }ISO 3166-1 alpha-3 code (e.g. "ESP"), validated server-side.
PHONE{ value: { countryCode, callingCode, number } }Structured phone object.
ADDRESS{ value: { street, streetExtraInfo, city, state, postalCode, country } }Structured address object.
DROPDOWN, SINGLE_CHOICE{ value: string, text?: string }value is the choice value; text is filled when the picked choice has requires_text_input: true.
MULTIPLE_CHOICE{ value: string[], text?: string }Array of choice values.
CONSENT{ value: boolean }JSON boolean.
FILE_UPLOAD, IMAGE{ files: string[] }Each entry is a pre-signed URL.
REPEATABLE_GROUP{ items: Array<{ [fieldValue]: Answer }> }One object per repetition, keyed by each sub-field’s value with its own answer object.
HEADING, PARAGRAPH, SEPARATOR(no answer key)Pure layout — kept in items[] for structure.
A visible interactive item the user never answered is returned with "answer": null.

Conditional visibility

When a questionnaire defines a graph (conditional logic), only items on the path the user actually took are included. An item hidden by a branch the user did not follow does not appear in sections[].items — even if it exists in the template. Sections left with no visible items are dropped entirely.

Status values

The response-level status is one of three values. Internally, the base status (Approved, or In Review when the workflow forces manual review) is combined with any matching custom status rules using the platform-wide precedence Declined > In Review > Approved; a questionnaire-level Declined outcome is then mapped to In Review so operators handle the final disposition during review.
StatusMeaning
Not FinishedThe user has not submitted the questionnaire yet.
In ReviewSubmitted and waiting on manual review (the workflow forces manual review, or a status rule escalated the response).
ApprovedSubmitted and accepted.

Warnings

Questionnaires emit a single warning code, produced when a custom status rule configured on the questionnaire node matches an answer:
TagDescription
CUSTOM_STATUS_RULE_TRIGGEREDA workflow status rule evaluated a questionnaire answer and changed (or confirmed) the feature status.
The warning’s additional_data carries field, operator, rule_value, actual_value, target_status, and score when the rule defines one. Its log_type follows the rule’s target status: error for Declined, warning for In Review, information otherwise. Unlike other features, the questionnaire entry does not embed a warnings[] array — triggered-rule logs are recorded on the session under feature: "QUESTIONNAIRE" and surface in the Console review screen (see also the Business Verification warnings listing; the same code applies to KYC sessions).

Example — Source-of-funds questionnaire

{
  "questionnaire_responses": [
    {
      "questionnaire_id": "9f7485e0-b00b-4d56-9d3e-7859b68d1213",
      "title": "Source of Funds",
      "description": "Reply to this questionnaire to help us understand the source of funds.",
      "languages": ["en"],
      "default_language": "en",
      "is_active": true,
      "is_simple_questionnaire": true,
      "questionnaire_group_id": "2b6a9d40-13a8-4b1e-9a6c-3f1d2e4b5a60",
      "version": 1,
      "published_at": "2025-11-02T09:14:55.000000Z",
      "status": "Approved",
      "sections": [
        {
          "title": null,
          "description": null,
          "items": [
            {
              "uuid": "618636d9-7d5c-41ce-b8d0-1ab2a4be20db",
              "value": "question_1",
              "element_type": "DROPDOWN",
              "is_required": true,
              "title": "What is your primary source of funds?",
              "description": null,
              "placeholder": null,
              "choices": [
                { "label": "Salary", "value": "salary" },
                { "label": "Business Income", "value": "business_income" },
                { "label": "Savings", "value": "savings" },
                { "label": "Investments", "value": "investments" },
                { "label": "Inheritance/Gift", "value": "inheritance_gift" },
                { "label": "Other", "value": "other", "requires_text_input": true }
              ],
              "max_files": 1,
              "required_if": null,
              "repeatable_config": null,
              "answer": { "value": "salary" }
            },
            {
              "uuid": "2d16b527-72be-42e0-8e96-b164b818386c",
              "value": "question_2",
              "element_type": "LONG_TEXT",
              "is_required": true,
              "title": "Provide details of the primary source.",
              "description": null,
              "placeholder": null,
              "choices": null,
              "max_files": 1,
              "required_if": null,
              "repeatable_config": null,
              "answer": { "value": "Software engineer at Acme Ltd since 2018." }
            },
            {
              "uuid": "1bf8a2a3-14ee-48a8-bb3d-175481aae4aa",
              "value": "question_3",
              "element_type": "SINGLE_CHOICE",
              "is_required": true,
              "title": "Will any funds originate from third parties?",
              "description": null,
              "placeholder": null,
              "choices": [
                { "label": "Yes", "value": "yes", "requires_text_input": true },
                { "label": "No", "value": "no" }
              ],
              "max_files": 1,
              "required_if": null,
              "repeatable_config": null,
              "answer": { "value": "yes", "text": "One-off gift from parents, EUR 8,000." }
            },
            {
              "uuid": "a90a073d-e098-404c-bbce-5130d8b12a13",
              "value": "question_4",
              "element_type": "FILE_UPLOAD",
              "is_required": true,
              "title": "Upload a proof of funds document",
              "description": null,
              "placeholder": null,
              "choices": null,
              "max_files": 3,
              "required_if": null,
              "repeatable_config": null,
              "answer": {
                "files": [
                  "https://<media-host>/.../payslip-jul.pdf",
                  "https://<media-host>/.../payslip-aug.pdf"
                ]
              }
            }
          ]
        }
      ],
      "node_id": "feature_questionnaire"
    }
  ]
}

Example — Not finished

{
  "questionnaire_responses": [
    {
      "questionnaire_id": "9f7485e0-b00b-4d56-9d3e-7859b68d1213",
      "title": "Source of Funds",
      "description": "Reply to this questionnaire to help us understand the source of funds.",
      "languages": ["en"],
      "default_language": "en",
      "is_active": true,
      "is_simple_questionnaire": true,
      "questionnaire_group_id": "2b6a9d40-13a8-4b1e-9a6c-3f1d2e4b5a60",
      "version": 1,
      "published_at": "2025-11-02T09:14:55.000000Z",
      "status": "Not Finished",
      "sections": [
        {
          "title": null,
          "description": null,
          "items": [
            {
              "uuid": "618636d9-7d5c-41ce-b8d0-1ab2a4be20db",
              "value": "question_1",
              "element_type": "DROPDOWN",
              "is_required": true,
              "title": "What is your primary source of funds?",
              "description": null,
              "placeholder": null,
              "choices": [
                { "label": "Salary", "value": "salary" },
                { "label": "Other", "value": "other", "requires_text_input": true }
              ],
              "max_files": 1,
              "required_if": null,
              "repeatable_config": null,
              "answer": null
            }
          ]
        }
      ],
      "node_id": "feature_questionnaire"
    }
  ]
}
When the user has reached the questionnaire step but not submitted answers yet, the response is returned with status: "Not Finished" and "answer": null on every visible item. A session that never reached the step produces no entry at all — questionnaire_responses stays null when no instance exists.

Notes

  • File URLs expire. Entries in answer.files are pre-signed URLs (4-hour validity by default). Re-fetch the decision endpoint when you need fresh URLs.
  • Localization. Item title, placeholder, choice label, and section title/description are returned in English when the questionnaire supports it, otherwise in the questionnaire’s default_language. The value of a choice remains stable across languages so you can key business logic off it safely.
  • Item description is layout-only. It is populated only on HEADING/PARAGRAPH text blocks; interactive items always return description: null.

Questionnaires overview

How to build, version, and attach questionnaires to a workflow.

Data models — Questionnaire response

Canonical field-by-field schema for this object.

Retrieve session

Endpoint reference for the V3 decision payload.