Questionnaire Templates API

Questionnaire Templates are reusable DDQ (Due Diligence Questionnaire) blueprints containing structured questions. Each template is the source of truth for question order, types, and conditional logic. Use this API to retrieve template structure when creating responses.

Read-Only API

Questionnaire Templates are created and managed through the web interface. This API lets you read template metadata, fetch question structures, and build dynamic forms.

Common Use Cases

  • Retrieve available templates before creating a questionnaire response
  • Fetch question structure to build dynamic UI forms
  • Understand required fields and question types for autofill
  • Evaluate conditional visibility rules before submitting answers

Questionnaire Template Object

The template object represents a reusable DDQ blueprint with structured questions.

List View Fields

FieldTypev1v2Description
idinteger-Integer identifier (v1 only)
uuiduuid-UUID identifier (v2 only)
namestringTemplate name
descriptionstringDescription text
questionnaire_typestringddq or rfi
question_countintegerTotal number of text questions
created_atdatetimeCreation timestamp (ISO 8601)

Detail View Additional Fields

FieldTypeDescription
sectionsobjectOptional JSON structure defining predefined sections
questionsarrayArray of text-based question objects
file_questionsarrayArray of file upload requirement objects
response_countintegerNumber of active responses using this template (excludes PREFILL status)

List Questionnaire Templates

Retrieve a paginated list of all questionnaire templates in your tenant.

GET /api/v1/questionnaires/
GET /api/v2/questionnaire-templates/

Query Parameters

ParameterTypeDescription
typestringFilter: ddq or rfi
pageintegerPage number (default: 1)
page_sizeintegerResults per page (default: 50, max: 100)

Query Parameters

ParameterTypeDescription
typestringFilter: ddq or rfi
afterstringCursor for next page (from next_cursor)
beforestringCursor for previous page (from prev_cursor)
page_sizeintegerResults per page (default: 50, max: 100)

List Questionnaire Templates

curl https://api.kycgenie.com/api/v1/questionnaires/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/questionnaire-templates/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

response = requests.get(
    "https://api.kycgenie.com/api/v1/questionnaires/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = response.json()
for t in data["results"]:
    print(f"{t['name']} ({t['id']}) - {t['question_count']} questions")
from kycgenie import KYCGenie
import os

client = KYCGenie(api_key=os.getenv("KYCGENIE_API_KEY"))

result = client.questionnaire_templates.list()

for t in result.results:
    print(f"{t.name} ({t.uuid}) - {t.question_count} questions")

# Paginate
if result.has_more:
    next_page = client.questionnaire_templates.list()  # cursor pagination handled automatically
const response = await fetch(
  "https://api.kycgenie.com/api/v1/questionnaires/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
data.results.forEach(t => {
  console.log(`${t.name} (${t.id}) - ${t.question_count} questions`);
});
const response = await fetch(
  "https://api.kycgenie.com/api/v2/questionnaire-templates/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
data.results.forEach(t => {
  console.log(`${t.name} (${t.uuid}) - ${t.question_count} questions`);
});
if (data.has_more) console.log("Next cursor:", data.next_cursor);

Response Example

{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": 1,
      "name": "Standard DDQ",
      "description": "Standard due diligence questionnaire",
      "questionnaire_type": "ddq",
      "question_count": 42,
      "created_at": "2026-01-15T10:30:00Z"
    },
    {
      "id": 2,
      "name": "Security Assessment",
      "description": "Information security assessment",
      "questionnaire_type": "ddq",
      "question_count": 28,
      "created_at": "2026-01-18T14:20:00Z"
    }
  ]
}
{
  "has_more": false,
  "next_cursor": null,
  "prev_cursor": null,
  "results": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440010",
      "name": "Standard DDQ",
      "description": "Standard due diligence questionnaire",
      "questionnaire_type": "ddq",
      "question_count": 42,
      "created_at": "2026-01-15T10:30:00Z"
    },
    {
      "uuid": "660e8400-e29b-41d4-a716-446655440011",
      "name": "Security Assessment",
      "description": "Information security assessment",
      "questionnaire_type": "ddq",
      "question_count": 28,
      "created_at": "2026-01-18T14:20:00Z"
    }
  ]
}

Get Questionnaire Template

Retrieve a specific template by ID, including all questions and file requirements.

GET /api/v1/questionnaires/{id}/
GET /api/v2/questionnaire-templates/{uuid}/

Path Parameters

ParameterTypeDescription
idintegerTemplate integer ID

Path Parameters

ParameterTypeDescription
uuiduuidTemplate UUID (use uuid from list response)

Returns the full template object including questions, file_questions, and section structure. Returns 200 OK.

Get Template Details

curl https://api.kycgenie.com/api/v1/questionnaires/1/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/questionnaire-templates/550e8400-e29b-41d4-a716-446655440010/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

response = requests.get(
    "https://api.kycgenie.com/api/v1/questionnaires/1/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
tmpl = response.json()
print(f"Name: {tmpl['name']}")
print(f"Questions: {len(tmpl['questions'])}")
print(f"File requirements: {len(tmpl['file_questions'])}")
from kycgenie import KYCGenie
import os

client = KYCGenie(api_key=os.getenv("KYCGENIE_API_KEY"))

tmpl = client.questionnaire_templates.get_template(
    questionnaire_uuid="550e8400-e29b-41d4-a716-446655440010",
)

print(f"Name: {tmpl.name}")
print(f"Questions: {len(tmpl.questions)}")
print(f"File requirements: {len(tmpl.file_questions)}")
const response = await fetch(
  "https://api.kycgenie.com/api/v1/questionnaires/1/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const tmpl = await response.json();
console.log(`Name: ${tmpl.name}`);
console.log(`Questions: ${tmpl.questions.length}`);
const response = await fetch(
  "https://api.kycgenie.com/api/v2/questionnaire-templates/550e8400-e29b-41d4-a716-446655440010/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const tmpl = await response.json();
console.log(`Name: ${tmpl.name}`);
console.log(`UUID: ${tmpl.uuid}`);

Response Example (200 OK)

{
  "id": 1,
  "name": "Standard DDQ",
  "description": "Standard due diligence questionnaire",
  "questionnaire_type": "ddq",
  "sections": null,
  "question_count": 3,
  "response_count": 12,
  "created_at": "2026-01-15T10:30:00Z",
  "questions": [
    {
      "id": 123,
      "number": 1,
      "section": "Part 1",
      "section_number": 1,
      "sub_section": "Company Information",
      "sub_section_number": 1,
      "text": "What is your company's legal name?",
      "question_type": "text",
      "required": true,
      "exclude_from_autofill": false,
      "options": null,
      "visibility_conditions": null
    }
  ],
  "file_questions": [
    {
      "id": 45,
      "document_type": "certificate_of_incorporation",
      "description": "Certificate of Incorporation",
      "required": true,
      "multiple": false,
      "order": 1,
      "min_files": 1,
      "max_files": 1,
      "accepted_extensions": ["pdf", "jpg", "png"]
    }
  ]
}
{
  "uuid": "550e8400-e29b-41d4-a716-446655440010",
  "name": "Standard DDQ",
  "description": "Standard due diligence questionnaire",
  "questionnaire_type": "ddq",
  "sections": null,
  "question_count": 3,
  "response_count": 12,
  "created_at": "2026-01-15T10:30:00Z",
  "questions": [
    {
      "id": 123,
      "number": 1,
      "section": "Part 1",
      "section_number": 1,
      "sub_section": "Company Information",
      "sub_section_number": 1,
      "text": "What is your company's legal name?",
      "question_type": "text",
      "required": true,
      "exclude_from_autofill": false,
      "options": null,
      "visibility_conditions": null
    }
  ],
  "file_questions": [
    {
      "id": 45,
      "document_type": "certificate_of_incorporation",
      "description": "Certificate of Incorporation",
      "required": true,
      "multiple": false,
      "order": 1,
      "min_files": 1,
      "max_files": 1,
      "accepted_extensions": ["pdf", "jpg", "png"]
    }
  ]
}

List Template Questions

Retrieve all questions for a template, including both text-based questions and file upload requirements. Questions are ordered by section_number, sub_section_number, then number.

GET /api/v1/questionnaires/{id}/questions/
GET /api/v2/questionnaire-templates/{uuid}/questions/

Returns {questions[], file_questions[]} with 200 OK. No pagination - returns all questions for the template.

List Template Questions

curl https://api.kycgenie.com/api/v1/questionnaires/1/questions/ \
  -H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/questionnaire-templates/550e8400-e29b-41d4-a716-446655440010/questions/ \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

response = requests.get(
    "https://api.kycgenie.com/api/v1/questionnaires/1/questions/",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = response.json()
for q in data["questions"]:
    print(f"Q{q['number']}: {q['text']} [{q['question_type']}]")
    if q["options"]:
        print(f"  Options: {q['options']}")
    if q["visibility_conditions"]:
        print(f"  Conditional: {q['visibility_conditions']}")
from kycgenie import KYCGenie
import os

client = KYCGenie(api_key=os.getenv("KYCGENIE_API_KEY"))

data = client.questionnaire_templates.list_questions(
    questionnaire_uuid="550e8400-e29b-41d4-a716-446655440010",
)

for q in data.questions:
    print(f"Q{q.number}: {q.text} [{q.question_type}]")

for fq in data.file_questions:
    print(f"File: {fq.description} (required={fq.required})")
const res = await fetch(
  "https://api.kycgenie.com/api/v1/questionnaires/1/questions/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();
data.questions.forEach(q => {
  console.log(`Q${q.number}: ${q.text} [${q.question_type}]`);
  if (q.options) console.log("  Options:", q.options);
});
const res = await fetch(
  "https://api.kycgenie.com/api/v2/questionnaire-templates/550e8400-e29b-41d4-a716-446655440010/questions/",
  { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await res.json();
data.questions.forEach(q => {
  console.log(`Q${q.number}: ${q.text} [${q.question_type}]`);
  if (q.options) console.log("  Options:", q.options);
});

Response Example (200 OK)

{
  "questions": [
    {
      "id": 123,
      "number": 1,
      "section": "Part 1",
      "section_number": 1,
      "sub_section": "Company Information",
      "sub_section_number": 1,
      "text": "What is your company's legal name?",
      "question_type": "text",
      "required": true,
      "exclude_from_autofill": false,
      "options": null,
      "visibility_conditions": null
    },
    {
      "id": 124,
      "number": 2,
      "section": "Part 1",
      "section_number": 1,
      "sub_section": "Company Information",
      "sub_section_number": 1,
      "text": "What is your primary business activity?",
      "question_type": "select",
      "required": true,
      "exclude_from_autofill": false,
      "options": ["Financial Services", "Technology", "Healthcare", "Other"],
      "visibility_conditions": null
    },
    {
      "id": 125,
      "number": 3,
      "section": "Part 1",
      "section_number": 1,
      "sub_section": "Regulatory",
      "sub_section_number": 2,
      "text": "Please describe your regulatory authorisations.",
      "question_type": "text",
      "required": true,
      "exclude_from_autofill": false,
      "options": null,
      "visibility_conditions": {
        "operator": "AND",
        "rules": [
          {"question_id": 124, "condition": "eq", "value": "Financial Services"}
        ]
      }
    }
  ],
  "file_questions": [
    {
      "id": 45,
      "document_type": "certificate_of_incorporation",
      "description": "Certificate of Incorporation",
      "required": true,
      "multiple": false,
      "order": 1,
      "min_files": 1,
      "max_files": 1,
      "accepted_extensions": ["pdf", "jpg", "png"]
    }
  ]
}

Question Object

Text-based questions within a questionnaire template. Both v1 and v2 return the same question shape (integer id).

Attributes

FieldTypeDescription
idintegerUnique question identifier
numberintegerDisplay ordering number
sectionstringSection name (e.g. "Part 1")
section_numberintegerNumeric section order
sub_sectionstring | nullSubsection name
sub_section_numberintegerNumeric subsection order
textstringThe question text (max 1000 characters)
question_typestringQuestion type (see table below)
requiredbooleanWhether an answer is required for submission
exclude_from_autofillbooleanIf true, AI autofill skips this question
optionsarray | nullValid option strings for select and multi_select types; null for all others
visibility_conditionsobject | nullConditional visibility rules. null = always shown. See Conditional Questions.

File Question Attributes

FieldTypeDescription
idintegerUnique file question identifier
document_typestringDocument type name (e.g. certificate_of_incorporation)
descriptionstringHuman-readable description
requiredbooleanWhether this file is required for submission
multiplebooleanWhether multiple files are allowed (max_files > 1 or unlimited)
orderintegerDisplay order
min_filesinteger | nullMinimum required file count
max_filesinteger | nullMaximum allowed file count; null = unlimited
accepted_extensionsarrayAllowed file extensions (e.g. ["pdf","jpg","png"])

Question Types

The question_type field determines what value to supply in answer_text when submitting answers via the Questionnaire Responses API.

TypeDescriptionanswer_text format
textFree textAny string
numberNumeric valueNumeric string, e.g. "42"
emailEmail addressValid email string
telPhone numberPhone number string
urlURL / WebsiteURL string, e.g. "https://example.com"
percentagePercentage valueNumeric string, e.g. "75" (no % symbol)
currencyCurrency amountNumeric string, e.g. "15000"
booleanYes / No"yes" or "no"
yes_no_naYes / No / Not Applicable"yes", "no", or "na"
dateDate onlyUse the date_answer field (YYYY-MM-DD), not answer_text
text_and_dateText with an associated dateSupply both answer_text (text) and date_answer (YYYY-MM-DD)
selectSingle-choice dropdownOne of the strings from the question's options array
multi_selectMultiple-choice checkboxesJSON array string of selected options, e.g. '["Option A","Option B"]'
countryCountry pickerISO 3166-1 alpha-2 code, e.g. "GB"
structuredMulti-field structured data (e.g. UBO details)Use the structured_data field (list of instance dicts), not answer_text
File Upload Requirements

File uploads are handled separately via the file_questions array. These use the FileQuestion model with document type specifications and are submitted via the Documents API.