> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Questionnaire

> Create a simple linear questionnaire. Send `form_elements` in display order; branching and repeatable groups require the Console. Defaults to `published` v1.

export const AgentPromptAccordion = ({prompt, title = "AI Agent Integration Prompt"}) => {
  const [copied, setCopied] = React.useState(false);
  const handleCopy = e => {
    e.stopPropagation();
    if (!prompt) return;
    navigator.clipboard.writeText(prompt.trim()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };
  const agents = ["Claude Code", "Codex", "Cursor", "Devin", "Windsurf", "GitHub Copilot"];
  return <div className="didit-agent-card">
      {}
      <div className="didit-agent-titlebar">
        <div className="didit-agent-dots" aria-hidden="true">
          <span className="didit-agent-dot didit-agent-dot-red"></span>
          <span className="didit-agent-dot didit-agent-dot-yellow"></span>
          <span className="didit-agent-dot didit-agent-dot-green"></span>
        </div>
        <span className="didit-agent-filename">{title}</span>
        <button type="button" className={`didit-agent-copy ${copied ? "didit-agent-copy-copied" : ""}`} onClick={handleCopy} title="Copy prompt to clipboard" aria-label={copied ? "Copied!" : "Copy prompt to clipboard"}>
          {copied ? <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Copied</span>
            </> : <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <rect x="5" y="5" width="9" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.5" />
                <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              <span>Copy</span>
            </>}
        </button>
      </div>

      {}
      <pre className="didit-agent-body"><code>{prompt.trim()}</code></pre>

      {}
      <div className="didit-agent-footer">
        <span className="didit-agent-footer-label">Paste into</span>
        <div className="didit-agent-chips">
          {agents.map(name => <span key={name} className="didit-agent-chip">{name}</span>)}
        </div>
      </div>
    </div>;
};

<AgentPromptAccordion
  title="Create Questionnaire API Prompt"
  prompt={`Create a simple Didit questionnaire through the Management API.

Endpoint:
POST https://verification.didit.me/v3/questionnaires/

Authentication:
Use the x-api-key header with my Didit API key.

Requirements:
- Use the simple v3 API shape with form_elements.
- Do not send graph, branches, next, required_if, or conditional logic.
- Include languages with en and default_language set to en.
- Use customer-friendly element_type values such as short_text, multiple_choice, email, file_upload, or date_picker.
- For choice questions, send options with value and label.
- Store the questionnaire_id from the response because I will use it later as questionnaire_uuid in workflows.

Example request body:
{
"title": "Customer Onboarding",
"languages": ["en"],
"default_language": "en",
"form_elements": [
{
  "id": "occupation",
  "element_type": "short_text",
  "label": { "en": "What is your occupation?" },
  "is_required": true
},
{
  "id": "source_of_funds",
  "element_type": "multiple_choice",
  "label": { "en": "Source of funds" },
  "is_required": true,
  "options": [
    { "value": "employment", "label": { "en": "Employment" } },
    { "value": "business", "label": { "en": "Business" } },
    { "value": "investments", "label": { "en": "Investments" } }
  ]
}
]
}

Build the API call, handle validation errors, and return the questionnaire_id from the response.`}
/>

Use this endpoint to create simple questionnaires through the API. Send a `form_elements` array in the order users should answer the questions. Didit builds the internal questionnaire graph for you.

The API supports simple linear questionnaires only. Do not send `graph`, `branches`, `next`, or conditional rules.

## Required fields

* `title` is the internal questionnaire name.
* `languages` must include `en`.
* `form_elements` must contain at least one question.
* Each form element needs an `element_type` and a translated `label`.

## Element types

Use lowercase values such as `short_text`, `multiple_choice`, `email`, `file_upload`, or `date_picker`. Uppercase enum values such as `SHORT_TEXT` are also accepted.

For `dropdown`, `single_choice`, and `multiple_choice`, add `options`. If you omit an option `value`, Didit generates one from the label.

```json theme={null}
{
  "title": "Customer Onboarding",
  "languages": ["en"],
  "default_language": "en",
  "form_elements": [
    {
      "id": "occupation",
      "element_type": "short_text",
      "label": { "en": "What is your occupation?" },
      "is_required": true
    },
    {
      "id": "source_of_funds",
      "element_type": "multiple_choice",
      "label": { "en": "Source of funds" },
      "is_required": true,
      "options": [
        { "value": "employment", "label": { "en": "Employment" } },
        { "value": "business", "label": { "en": "Business" } },
        { "value": "investments", "label": { "en": "Investments" } }
      ]
    }
  ]
}
```

## Field validation

Add an optional `validation` object to a `short_text`, `long_text`, or `number` element to enforce a format on the user's answer. This is useful for identifiers with strict formats such as tax IDs, national IDs, or card numbers. Validation runs while the user fills the field (the user cannot proceed until it passes) and is re-enforced by the API on submission.

| Field           | Applies to                | Description                                                                                                                               |
| --------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `pattern`       | `short_text`, `long_text` | Regular expression the value must fully match. Use the portable ECMA-262 subset; do not add `^`/`$` anchors (the whole value is matched). |
| `min_length`    | `short_text`, `long_text` | Minimum number of characters.                                                                                                             |
| `max_length`    | `short_text`, `long_text` | Maximum number of characters.                                                                                                             |
| `min`           | `number`                  | Minimum numeric value.                                                                                                                    |
| `max`           | `number`                  | Maximum numeric value.                                                                                                                    |
| `error_message` | all of the above          | Translated message shown when the value does not pass. Falls back to a generic message if omitted.                                        |

```json theme={null}
{
  "title": "Customer Onboarding",
  "languages": ["en"],
  "default_language": "en",
  "form_elements": [
    {
      "id": "tax_id",
      "element_type": "short_text",
      "label": { "en": "Tax ID" },
      "is_required": true,
      "validation": {
        "pattern": "[A-Z]{2}[0-9]{9}",
        "min_length": 11,
        "max_length": 11,
        "error_message": { "en": "Enter a valid Tax ID (2 letters followed by 9 digits)." }
      }
    }
  ]
}
```

The response includes `questionnaire_id`. Store it, because you will use it as `questionnaire_uuid` when you add the questionnaire to a workflow.


## OpenAPI

````yaml POST /v3/questionnaires/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/questionnaires/:
    post:
      tags:
        - Questionnaires
      summary: Create questionnaire
      description: >-
        Create a simple linear questionnaire. Send `form_elements` in display
        order; branching and repeatable groups require the Console. Defaults to
        `published` v1.
      operationId: create_questionnaire
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimpleQuestionnaireRequest'
            examples:
              Simple:
                summary: Basic questionnaire
                value:
                  title: Customer Onboarding
                  description: Additional information needed for verification
                  default_language: en
                  languages:
                    - en
                  is_active: true
                  form_elements:
                    - id: occupation
                      element_type: short_text
                      label:
                        en: What is your occupation?
                      is_required: true
                      placeholder:
                        en: Software engineer
                    - id: source_of_funds
                      element_type: multiple_choice
                      label:
                        en: Source of funds
                      is_required: true
                      options:
                        - value: employment
                          label:
                            en: Employment
                        - value: business
                          label:
                            en: Business
                        - value: investments
                          label:
                            en: Investments
                        - value: other
                          label:
                            en: Other
      responses:
        '201':
          description: >-
            Questionnaire created. The response includes the `questionnaire_id`
            — store it to reference this questionnaire from workflows or future
            update/delete calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuestionnaireDetail'
              examples:
                Created:
                  value:
                    questionnaire_id: 11111111-2222-3333-4444-555555555555
                    title: Customer Onboarding
                    description: Additional information needed for verification
                    languages:
                      - en
                    default_language: en
                    is_active: true
                    is_simple_questionnaire: true
                    graph:
                      start_node: occupation
                      nodes:
                        occupation:
                          element_type: SHORT_TEXT
                          is_required: true
                          title:
                            en: What is your occupation?
                          next: source_of_funds
                        source_of_funds:
                          element_type: MULTIPLE_CHOICE
                          is_required: true
                          title:
                            en: Source of funds
                          choices:
                            - value: employment
                              label:
                                en: Employment
                            - value: business
                              label:
                                en: Business
                          next: null
                    sections: []
                    questionnaire_group_id: 11111111-2222-3333-4444-555555555555
                    version: 1
                    status: published
                    published_at: '2026-04-23T10:00:00Z'
                    is_editable: false
        '400':
          description: >-
            Validation error. Common causes: an unknown `element_type`, a
            translatable field missing a translation for one of `languages`,
            `languages` missing `en`, `default_language` not in `languages`, an
            option without a `label`, a question that has
            `branches`/`required_if`/`repeatable_config` (not supported by this
            endpoint), or sending a raw `graph` instead of `form_elements`. The
            body is a DRF validation error keyed by field name.
          content:
            application/json:
              examples:
                Graph not accepted:
                  value:
                    graph: >-
                      The v3 questionnaire API only accepts simple
                      `form_elements`, not `graph`.
                Missing label:
                  value:
                    form_elements:
                      - label:
                          - This field is required.
        '403':
          description: >-
            API key missing, malformed, expired, or scoped to a different
            application.
          content:
            application/json:
              examples:
                Invalid token:
                  value:
                    detail: You do not have permission to perform this action.
        '415':
          description: >-
            Unsupported media type. Set `Content-Type: application/json` and
            send a JSON body.
        '429':
          description: Rate limit exceeded. Retry with exponential backoff.
        '500':
          description: >-
            Unexpected server error while creating the questionnaire. Safe to
            retry.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://verification.didit.me/v3/questionnaires/' \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "title": "Customer Onboarding",
                "default_language": "en",
                "languages": ["en"],
                "form_elements": [
                  {
                    "id": "occupation",
                    "element_type": "short_text",
                    "label": {"en": "What is your occupation?"},
                    "is_required": true
                  }
                ]
              }'
        - lang: Python
          label: Python (requests)
          source: |-
            import requests

            payload = {
                "title": "Customer Onboarding",
                "default_language": "en",
                "languages": ["en"],
                "form_elements": [
                    {
                        "id": "occupation",
                        "element_type": "short_text",
                        "label": {"en": "What is your occupation?"},
                        "is_required": True,
                    },
                ],
            }
            resp = requests.post(
                "https://verification.didit.me/v3/questionnaires/",
                headers={"x-api-key": "YOUR_API_KEY"},
                json=payload,
                timeout=10,
            )
            resp.raise_for_status()
            questionnaire = resp.json()
            print("Questionnaire id:", questionnaire["questionnaire_id"])
        - lang: JavaScript
          label: Node.js (fetch)
          source: >-
            const res = await
            fetch("https://verification.didit.me/v3/questionnaires/", {
              method: "POST",
              headers: {
                'x-api-key': 'YOUR_API_KEY',
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                title: "Customer Onboarding",
                default_language: "en",
                languages: ["en"],
                form_elements: [
                  {
                    id: "occupation",
                    element_type: "short_text",
                    label: { en: "What is your occupation?" },
                    is_required: true,
                  },
                ],
              }),
            });

            if (!res.ok) throw new Error(`Didit ${res.status}: ${await
            res.text()}`);

            const questionnaire = await res.json();

            console.log("Questionnaire id:", questionnaire.questionnaire_id);
components:
  schemas:
    SimpleQuestionnaireRequest:
      type: object
      description: >-
        Create a simple linear questionnaire. The API converts `form_elements`
        into the internal questionnaire graph.
      required:
        - title
        - languages
        - form_elements
      properties:
        title:
          type: string
          description: Internal name for the questionnaire.
        description:
          type: string
          nullable: true
        languages:
          type: array
          description: Languages included in every label. Must include `en`.
          items:
            type: string
          example:
            - en
        default_language:
          type: string
          description: Default language. Must be included in `languages`.
          example: en
        is_active:
          type: boolean
          default: true
        status:
          type: string
          enum:
            - draft
            - published
          description: >-
            Omit this field to create a published questionnaire ready for
            workflows.
        form_elements:
          type: array
          minItems: 1
          description: >-
            Questions in the exact order users should see them. Branching and
            conditional fields are not supported.
          items:
            $ref: '#/components/schemas/SimpleQuestionnaireElement'
    QuestionnaireDetail:
      type: object
      description: >-
        Full questionnaire detail returned from GET, POST (create) and PATCH
        (update) endpoints.
      properties:
        questionnaire_id:
          type: string
          format: uuid
          description: >-
            Unique identifier of the questionnaire. Use this id when referencing
            the questionnaire from a workflow or in subsequent update/delete
            requests.
        title:
          type: string
        description:
          type: string
          nullable: true
        languages:
          type: array
          items:
            type: string
        default_language:
          type: string
        is_active:
          type: boolean
        is_simple_questionnaire:
          type: boolean
        graph:
          type: object
          description: Graph structure with start_node and nodes map.
        sections:
          type: array
          description: >-
            Questionnaire content grouped into sections (derived from the
            graph).
          items:
            type: object
        questionnaire_group_id:
          type: string
          format: uuid
          description: >-
            Stable identifier that groups all versions of the same
            questionnaire.
        version:
          type: integer
        status:
          type: string
          enum:
            - draft
            - published
        published_at:
          type: string
          format: date-time
          nullable: true
        is_editable:
          type: boolean
          description: >-
            True when the questionnaire can still be edited in place (draft
            versions).
    SimpleQuestionnaireElement:
      type: object
      required:
        - element_type
        - label
      properties:
        id:
          type: string
          description: >-
            Optional stable question id. If omitted, the API generates `q1`,
            `q2`, etc. Use lowercase letters, numbers, and underscores for
            readability.
          example: source_of_funds
        element_type:
          type: string
          description: >-
            Question type. The API accepts these lowercase values and their
            uppercase equivalents.
          enum:
            - short_text
            - long_text
            - dropdown
            - single_choice
            - multiple_choice
            - number
            - image
            - file_upload
            - time
            - email
            - address
            - phone
            - country
            - date_picker
            - consent
            - section_header
            - separator
            - heading
            - paragraph
        label:
          type: object
          description: >-
            Question label by language code, for example `{ "en": "Source of
            funds" }`.
          additionalProperties:
            type: string
        description:
          type: object
          nullable: true
          additionalProperties:
            type: string
        placeholder:
          type: object
          nullable: true
          additionalProperties:
            type: string
        is_required:
          type: boolean
          default: false
        options:
          type: array
          description: >-
            Use for `dropdown`, `single_choice`, and `multiple_choice`. If
            `value` is omitted, the API generates one from the option label.
          items:
            type: object
            required:
              - label
            properties:
              value:
                type: string
              label:
                type: object
                additionalProperties:
                  type: string
        max_files:
          type: integer
          minimum: 1
          maximum: 5
          description: Use with `file_upload` or `image`.
        validation:
          type: object
          nullable: true
          description: >-
            Optional format validation for `short_text`, `long_text`, or
            `number`. Enforced while the user fills the field (they cannot
            proceed until it passes) and re-checked by the API on submission.
          properties:
            pattern:
              type: string
              description: >-
                Regular expression (ECMA-262 subset) the value must fully match.
                For `short_text` and `long_text`. Do not add ^/$ anchors; the
                whole value is matched.
            min_length:
              type: integer
              minimum: 0
              description: Minimum number of characters. For `short_text` and `long_text`.
            max_length:
              type: integer
              minimum: 0
              description: Maximum number of characters. For `short_text` and `long_text`.
            min:
              type: number
              description: Minimum numeric value. For `number`.
            max:
              type: number
              description: Maximum numeric value. For `number`.
            error_message:
              type: object
              description: >-
                Translated message shown when validation fails, keyed by
                language code.
              additionalProperties:
                type: string
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````