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
}
]
}'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"])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);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/questionnaires/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'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'
]
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/questionnaires/"
payload := strings.NewReader("{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/questionnaires/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/questionnaires/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"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
}Create Questionnaire
Create a simple linear questionnaire. Send form_elements in display order; branching and repeatable groups require the Console. Defaults to published v1.
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
}
]
}'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"])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);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/questionnaires/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'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'
]
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/questionnaires/"
payload := strings.NewReader("{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/questionnaires/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/questionnaires/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Customer Onboarding\",\n \"description\": \"Additional information needed for verification\",\n \"default_language\": \"en\",\n \"languages\": [\n \"en\"\n ],\n \"is_active\": true,\n \"form_elements\": [\n {\n \"id\": \"occupation\",\n \"element_type\": \"short_text\",\n \"label\": {\n \"en\": \"What is your occupation?\"\n },\n \"is_required\": true,\n \"placeholder\": {\n \"en\": \"Software engineer\"\n }\n },\n {\n \"id\": \"source_of_funds\",\n \"element_type\": \"multiple_choice\",\n \"label\": {\n \"en\": \"Source of funds\"\n },\n \"is_required\": true,\n \"options\": [\n {\n \"value\": \"employment\",\n \"label\": {\n \"en\": \"Employment\"\n }\n },\n {\n \"value\": \"business\",\n \"label\": {\n \"en\": \"Business\"\n }\n },\n {\n \"value\": \"investments\",\n \"label\": {\n \"en\": \"Investments\"\n }\n },\n {\n \"value\": \"other\",\n \"label\": {\n \"en\": \"Other\"\n }\n }\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"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
}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
titleis the internal questionnaire name.languagesmust includeen.form_elementsmust contain at least one question.- Each form element needs an
element_typeand a translatedlabel.
Element types
Use lowercase values such asshort_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.
{
"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 optionalvalidation 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. |
{
"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)." }
}
}
]
}
questionnaire_id. Store it, because you will use it as questionnaire_uuid when you add the questionnaire to a workflow.Authorizations
Body
Create a simple linear questionnaire. The API converts form_elements into the internal questionnaire graph.
Internal name for the questionnaire.
Languages included in every label. Must include en.
["en"]
Questions in the exact order users should see them. Branching and conditional fields are not supported.
1Show child attributes
Show child attributes
Default language. Must be included in languages.
"en"
Omit this field to create a published questionnaire ready for workflows.
draft, published Response
Questionnaire created. The response includes the questionnaire_id — store it to reference this questionnaire from workflows or future update/delete calls.
Full questionnaire detail returned from GET, POST (create) and PATCH (update) endpoints.
Unique identifier of the questionnaire. Use this id when referencing the questionnaire from a workflow or in subsequent update/delete requests.
Graph structure with start_node and nodes map.
Questionnaire content grouped into sections (derived from the graph).
Stable identifier that groups all versions of the same questionnaire.
draft, published True when the questionnaire can still be edited in place (draft versions).