openapi: 3.0.0 info: version: 3.0.0 title: Didit Verification Billing Workflows API description: Identity verification API. Authenticate with x-api-key header. servers: - url: https://verification.didit.me tags: - name: Workflows paths: /v3/workflows/: get: summary: List workflows description: List your workflows, newest first, in a limit/offset pagination envelope (`{count, next, previous, results}`, default page size 50). Each row is one version; `workflow_id` is the stable group ID and new sessions use the latest `published` version. operationId: list_workflows tags: - Workflows parameters: - name: limit in: query required: false schema: type: integer default: 50 description: Page size (number of workflows per page). - name: offset in: query required: false schema: type: integer default: 0 description: Number of rows to skip before the first returned workflow. responses: '200': description: One page of workflows ordered by `created_at` descending, wrapped in the pagination envelope. Each item in `results` is a `WorkflowListItem`. content: application/json: schema: type: object properties: count: type: integer description: Total number of workflow versions for the application. next: type: string format: uri nullable: true description: URL of the next page, or `null` on the last page. previous: type: string format: uri nullable: true description: URL of the previous page, or `null` on the first page. results: type: array items: $ref: '#/components/schemas/WorkflowListItem' examples: Two workflows: summary: A default KYC workflow and a draft KYC + AML workflow value: count: 2 next: null previous: null results: - uuid: a1b2c3d4-5678-90ab-cdef-111111111111 workflow_id: a1b2c3d4-5678-90ab-cdef-111111111111 workflow_label: Standard KYC workflow_type: kyc is_default: true is_archived: false is_white_label_enabled: false total_price: 0.15 min_price: 0.15 max_price: 0.15 features: OCR + LIVENESS + FACE_MATCH is_simple_workflow: true is_editable: false workflow_url: https://verify.didit.me/u/_yljPOx8RWG3UAz5ZRQGVQ max_retry_attempts: 3 retry_window_days: 7 session_expiration_time: 604800 version: 2 status: published has_draft: false created_by: name: Alex Mateo email: alex@example.com type: user updated_at: '2026-04-12T10:30:00Z' - uuid: b2c3d4e5-6789-01bc-defa-222222222222 workflow_id: b2c3d4e5-6789-01bc-defa-222222222222 workflow_label: Full Verification + AML workflow_type: kyc is_default: false is_archived: false is_white_label_enabled: false total_price: 0.25 min_price: 0.25 max_price: 0.25 features: OCR + LIVENESS + FACE_MATCH + AML is_simple_workflow: true is_editable: true workflow_url: https://verify.didit.me/u/Aq3kPOx8RWG3UAz5ZRQGVQ max_retry_attempts: 3 retry_window_days: 7 session_expiration_time: 604800 version: 1 status: draft has_draft: true created_by: null updated_at: '2026-04-15T18:05:21Z' '403': description: 'The API key is missing, malformed, expired, or belongs to a different application. Body: `{"detail": "You do not have permission to perform this action."}`. Refresh the token via the [Auth API](/auth-api/get-credentials) and retry.' content: application/json: schema: type: object properties: detail: type: string examples: Invalid token: value: detail: You do not have permission to perform this action. '429': description: Rate limit exceeded. Retry with exponential backoff and honour any `Retry-After` header. '500': description: Unexpected server error while building the list. The request can be safely retried. security: - ApiKeyAuth: [] x-codeSamples: - lang: curl label: cURL source: "curl -X GET 'https://verification.didit.me/v3/workflows/' \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Accept: application/json'" - lang: Python label: Python (requests) source: "import requests\n\nresp = requests.get(\n \"https://verification.didit.me/v3/workflows/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n timeout=10,\n)\nresp.raise_for_status()\npage = resp.json()\nfor workflow in page[\"results\"]:\n print(workflow[\"uuid\"], workflow[\"workflow_label\"], workflow[\"status\"])" - lang: JavaScript label: Node.js (fetch) source: "const res = await fetch(\"https://verification.didit.me/v3/workflows/\", {\n headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst page = await res.json();\npage.results.forEach((w) => console.log(w.uuid, w.workflow_label, w.status));" post: summary: Create workflow description: Create a simple workflow. Send `features` in execution order (ordering rules apply); defaults to `published` v1. The body accepts ONLY the fields listed in `SimpleWorkflowRequest` — any other key (including `workflow_type`) is rejected with a 400. Not idempotent — each call creates a new workflow. Maximum 50 workflows per application. operationId: create_workflow tags: - Workflows requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SimpleWorkflowRequest' examples: Simple KYC: summary: Linear ID, liveness, and face match workflow value: workflow_label: Standard KYC features: - feature: OCR config: duplicated_user_action: review - feature: LIVENESS config: face_liveness_method: passive - feature: FACE_MATCH config: face_match_score_decline_threshold: 40 face_match_score_review_threshold: 60 KYC + AML: summary: Run AML after ID verification value: workflow_label: KYC with AML features: - feature: OCR - feature: AML config: aml_score_review_threshold: 70 aml_score_approve_threshold: 30 Questionnaire workflow: summary: Run a questionnaire created with POST /v3/questionnaires/ value: workflow_label: Source of Funds features: - feature: QUESTIONNAIRE config: questionnaire_uuid: 11111111-2222-3333-4444-555555555555 review_questionnaire_manually: true responses: '201': description: 'Workflow created. The response body is the FULL workflow configuration — the same raw `VerificationSettings` serialization returned by `GET /v3/workflows/{settings_uuid}/` (~190 fields: every feature toggle, threshold, action and the generated `workflow_graph`), not the compact list item. Store the `uuid` (also exposed as `workflow_id`) so you can reference it from later session-creation calls. Note: `features` is a `" + "`-joined string and prices are JSON numbers.' content: application/json: schema: type: object description: Full workflow configuration (abbreviated here — see `GET /v3/workflows/{settings_uuid}/`). additionalProperties: true examples: Created (abbreviated): summary: Key fields of the full configuration object value: uuid: c3d4e5f6-7890-12cd-ef34-333333333333 workflow_id: c3d4e5f6-7890-12cd-ef34-333333333333 workflow_label: Standard KYC workflow_type: null is_default: false is_archived: false total_price: 0.15 min_price: 0.15 max_price: 0.15 features: OCR + LIVENESS + FACE_MATCH is_simple_workflow: false is_editable: false workflow_url: https://verify.didit.me/u/w9TkPOx8RWG3UAz5ZRQGVQ workflow_graph: start_node: ocr nodes: '... one node per feature plus a final status node ...' max_retry_attempts: 3 retry_window_days: 7 session_expiration_time: 604800 version: 1 status: published published_at: '2026-05-17T10:30:00Z' created_at: '2026-05-17T10:30:00Z' updated_at: '2026-05-17T10:30:00Z' '400': description: 'Validation error. Common causes: a top-level key outside the accepted whitelist (e.g. `workflow_type`), an unknown `feature` value, a feature placed before its dependency (e.g., `FACE_MATCH` before `OCR`), a passive feature (`AML`, `IP_ANALYSIS`, `DATABASE_VALIDATION`, `KYB_KEY_PEOPLE`) used as the first step, a `QUESTIONNAIRE` feature whose `config.questionnaire_uuid` does not exist for this application, or an out-of-range threshold. Body is a DRF validation error object — keys are field names, values are arrays of human-readable messages.' content: application/json: examples: Missing feature: value: features: - At least one feature is required. Unknown top-level field: value: workflow_type: - The v3 workflow API only accepts `workflow_label`, `is_default`, `status`, `features`, `is_white_label_enabled`, `is_desktop_allowed`, `max_retry_attempts`, `retry_window_days`, `session_expiration_time`, `face_liveness_max_attempts`, `face_match_max_attempts`. Unknown feature: value: features: - 'Invalid feature ''FOO''. Allowed values: AGE_ESTIMATION, AML, DATABASE_VALIDATION, EMAIL_VERIFICATION, FACE_MATCH, IP_ANALYSIS, KYB_DOCUMENTS, KYB_KEY_PEOPLE, KYB_REGISTRY, LIVENESS, NFC, OCR, PHONE_VERIFICATION, PROOF_OF_ADDRESS, QUESTIONNAIRE.' Ordering: value: features: - 'Feature ''FACE_MATCH'' must appear after one of: OCR.' Questionnaire not found: value: features: Questionnaire '11111111-2222-3333-4444-555555555555' was not found for this application. Create the questionnaire first, then use its questionnaire_id. '403': description: The API key is missing, malformed, expired, or scoped to a different application. Refresh via the [Auth API](/auth-api/get-credentials) and retry. 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 workflow. Safe to retry. security: - ApiKeyAuth: [] x-codeSamples: - lang: curl label: cURL source: "curl -X POST 'https://verification.didit.me/v3/workflows/' \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"workflow_label\": \"Standard KYC\",\n \"features\": [\n {\"feature\": \"OCR\"},\n {\"feature\": \"LIVENESS\", \"config\": {\"face_liveness_method\": \"passive\"}},\n {\"feature\": \"FACE_MATCH\", \"config\": {\"face_match_score_decline_threshold\": 40, \"face_match_score_review_threshold\": 60}}\n ]\n }'" - lang: Python label: Python (requests) source: "import requests\n\npayload = {\n \"workflow_label\": \"Standard KYC\",\n \"features\": [\n {\"feature\": \"OCR\"},\n {\"feature\": \"LIVENESS\", \"config\": {\"face_liveness_method\": \"passive\"}},\n {\"feature\": \"FACE_MATCH\"},\n ],\n}\nresp = requests.post(\n \"https://verification.didit.me/v3/workflows/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n json=payload,\n timeout=10,\n)\nresp.raise_for_status()\nworkflow = resp.json()\nprint(\"Workflow id:\", workflow[\"uuid\"])" - lang: JavaScript label: Node.js (fetch) source: "const res = await fetch(\"https://verification.didit.me/v3/workflows/\", {\n method: \"POST\",\n headers: {\n 'x-api-key': 'YOUR_API_KEY',\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n workflow_label: \"Standard KYC\",\n features: [\n { feature: \"OCR\" },\n { feature: \"LIVENESS\", config: { face_liveness_method: \"passive\" } },\n { feature: \"FACE_MATCH\" },\n ],\n }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);\nconst workflow = await res.json();\nconsole.log(\"Workflow id:\", workflow.uuid);" /v3/workflows/{settings_uuid}/: get: summary: Get workflow description: 'Fetch full configuration for one workflow version by `settings_uuid`: feature toggles, thresholds, allowed documents, graph, retry policy, callbacks, and pricing.' operationId: get_workflow tags: - Workflows parameters: - name: settings_uuid in: path required: true schema: type: string format: uuid description: Per-version UUID of the workflow (the `uuid` value returned by the list endpoint). Each version of a workflow has its own `settings_uuid`. responses: '200': description: 'Full workflow configuration. The shape is the raw `VerificationSettings` serialization (~190 fields: every feature toggle, threshold, warning action, allowed-documents config, the `workflow_graph`, retry policy, callbacks and pricing). The example below is abbreviated. Notes: `features` is a `" + "`-joined string (e.g. `"OCR + LIVENESS"`), prices are JSON numbers, and `is_editable` is `true` only for `draft` versions.' content: application/json: examples: KYC workflow with face match (abbreviated): value: uuid: a1b2c3d4-5678-90ab-cdef-111111111111 workflow_id: a1b2c3d4-5678-90ab-cdef-111111111111 workflow_label: Standard KYC workflow_type: kyc is_default: true is_archived: false is_liveness_enabled: true face_liveness_method: passive face_liveness_score_decline_threshold: 50 face_liveness_score_review_threshold: 70 is_face_match_enabled: true face_match_score_decline_threshold: 40 face_match_score_review_threshold: 60 is_aml_enabled: false is_phone_verification_enabled: false is_email_verification_enabled: false is_database_validation_enabled: false is_ip_analysis_enabled: false is_nfc_enabled: false duplicated_user_action: no_action documents_allowed: ESP: P: sides: 1 enabled: 1 subtypes: - EPASSPORT - PASSPORT_GENERIC preferred_characters: latin expiration_check_mode: strict max_retry_attempts: 3 retry_window_days: 7 session_expiration_time: 604800 version: 2 status: published published_at: '2026-04-12T10:30:00Z' is_simple_workflow: false is_editable: false workflow_url: https://verify.didit.me/u/_yljPOx8RWG3UAz5ZRQGVQ total_price: 0.15 min_price: 0.15 max_price: 0.15 features: OCR + LIVENESS + FACE_MATCH created_at: '2025-01-15T10:30:00Z' updated_at: '2026-04-12T10:30:00Z' '403': description: API key is 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. '404': description: No workflow with this `settings_uuid` exists for the authenticated application. Either the UUID is wrong or it belongs to another application — Didit deliberately does not distinguish the two cases to avoid leaking the existence of cross-application records. content: application/json: examples: Not found: value: detail: Not found. '429': description: Rate limit exceeded. Retry with exponential backoff. '500': description: Unexpected server error. Safe to retry. security: - ApiKeyAuth: [] x-codeSamples: - lang: curl label: cURL source: "curl -X GET 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n -H 'x-api-key: YOUR_API_KEY'" - lang: Python label: Python (requests) source: "import requests\n\nresp = requests.get(\n f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n timeout=10,\n)\nresp.raise_for_status()\nworkflow = resp.json()\nprint(workflow[\"workflow_label\"], workflow[\"status\"])" - lang: JavaScript label: Node.js (fetch) source: "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst workflow = await res.json();\nconsole.log(workflow.workflow_label, workflow.status);" patch: summary: Update workflow description: 'Update a workflow. Versioning depends on the `status` field you send and the current state of the version: (1) no `status` on a **published** version → the published version is updated in place (same `uuid`, same `version`); (2) no `status` on a **draft** → the draft is updated and immediately published; (3) `status: "published"` on a **published** version → a NEW published version is created under the same `workflow_id` (new `uuid`, `version` + 1) and returned, and any existing draft in the group is deleted; (4) `status: "draft"` keeps a draft as a draft (autosave) but is rejected with 400 on a published version (`"Cannot revert a published version to draft."`). The body accepts the same strict field whitelist as create — unknown keys are rejected with 400.' operationId: update_workflow tags: - Workflows parameters: - name: settings_uuid in: path required: true schema: type: string format: uuid description: Per-version UUID of the workflow to update. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SimpleWorkflowUpdateRequest' examples: Replace features: summary: Send the full desired feature order value: features: - feature: OCR - feature: AML Rename: summary: Rename a workflow value: workflow_label: Premium KYC Set as default: summary: Make this workflow the application's default value: is_default: true Update config: summary: Change feature configuration value: features: - feature: OCR - feature: LIVENESS config: face_liveness_method: passive Publish a draft: summary: Promote a draft to published value: status: published responses: '200': description: 'Workflow updated. The body is the FULL configuration of the resulting version (same raw `VerificationSettings` shape as `GET /v3/workflows/{settings_uuid}/`). When the update created a new version (`status: "published"` sent on a published row) the returned `uuid` and `version` differ from the ones you patched — use the returned `uuid` for subsequent calls.' content: application/json: schema: type: object description: Full workflow configuration (see `GET /v3/workflows/{settings_uuid}/`). additionalProperties: true '400': description: 'Validation error — a top-level key outside the accepted whitelist, an unknown feature, invalid ordering, out-of-range threshold, referencing a non-existent questionnaire, or `status: "draft"` sent for a published version (`"Cannot revert a published version to draft."`). The response body is a DRF validation error keyed by field name.' '403': description: API key missing or invalid. content: application/json: examples: Invalid token: value: detail: You do not have permission to perform this action. '404': description: No workflow with this `settings_uuid` exists for the authenticated application. '415': description: 'Unsupported media type. Set `Content-Type: application/json`.' '429': description: Rate limit exceeded. Retry with exponential backoff. '500': description: Unexpected server error. Safe to retry. security: - ApiKeyAuth: [] x-codeSamples: - lang: curl label: cURL source: "curl -X PATCH 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\"workflow_label\": \"Premium KYC\"}'" - lang: Python label: Python (requests) source: "import requests\n\nresp = requests.patch(\n f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n json={\"workflow_label\": \"Premium KYC\"},\n timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json()[\"workflow_label\"])" - lang: JavaScript label: Node.js (fetch) source: "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n method: \"PATCH\",\n headers: {\n 'x-api-key': 'YOUR_API_KEY',\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ workflow_label: \"Premium KYC\" }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst workflow = await res.json();\nconsole.log(workflow.workflow_label);" delete: summary: Delete workflow description: Permanently delete one workflow version (hard delete, no undo). Existing sessions keep their verification results but their workflow reference is cleared; other versions in the same `workflow_id` group are not deleted. operationId: delete_workflow tags: - Workflows parameters: - name: settings_uuid in: path required: true schema: type: string format: uuid description: Per-version UUID of the workflow to delete. responses: '204': description: Workflow deleted. The response body is empty. '403': description: API key missing or invalid. content: application/json: examples: Invalid token: value: detail: You do not have permission to perform this action. '404': description: No workflow with this `settings_uuid` exists for the authenticated application. content: application/json: examples: Not found: value: detail: Not found. '429': description: Rate limit exceeded. Retry with exponential backoff. '500': description: Unexpected server error. Safe to retry. security: - ApiKeyAuth: [] x-codeSamples: - lang: curl label: cURL source: "curl -X DELETE 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n -H 'x-api-key: YOUR_API_KEY'" - lang: Python label: Python (requests) source: "import requests\n\nresp = requests.delete(\n f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n timeout=10,\n)\nresp.raise_for_status() # raises on 4xx/5xx; 204 is success" - lang: JavaScript label: Node.js (fetch) source: "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n method: \"DELETE\",\n headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (res.status !== 204) throw new Error(`Didit ${res.status}`);" components: schemas: WorkflowListItem: type: object description: One workflow version in the list view. properties: uuid: type: string format: uuid description: Per-version UUID. Use as `{settings_uuid}` for get/update/delete, and as `workflow_id` when creating sessions. workflow_id: type: string format: uuid description: Stable group ID shared by every version of the same workflow. Equals `uuid` for version 1. workflow_label: type: string description: Display name for the workflow. workflow_type: type: string nullable: true description: 'Base type for simple workflows: `kyc`, `kyb`, `adaptive_age_verification`, `biometric_authentication`, etc. `null` for graph-based workflows without a KYB feature.' is_default: type: boolean description: Whether this is the default workflow for new sessions. is_archived: type: boolean is_white_label_enabled: type: boolean description: Whether white-label customization applies to sessions created with this workflow. total_price: type: number description: Fixed price per verification in USD (JSON number, excludes variable-priced features such as DATABASE_VALIDATION and PHONE_VERIFICATION). min_price: type: number description: Cheapest fixed price across workflow-graph paths, in USD. max_price: type: number description: Most expensive fixed price across workflow-graph paths, in USD. features: type: string description: Enabled features as a single `" + "`-joined string, e.g. `"OCR + LIVENESS + FACE_MATCH"`. Split on `" + "` to get a list. is_simple_workflow: type: boolean description: True when the workflow has no custom workflow graph. is_editable: type: boolean description: True when this version is a `draft` (drafts are editable in place; published versions are immutable in the Console). workflow_url: type: string format: uri description: Public shareable verification URL for this workflow (`https://verify.didit.me/u/`). max_retry_attempts: type: integer description: Maximum retry attempts allowed after a declined verification (0-10). retry_window_days: type: integer nullable: true description: Rolling window in days used to count retries (1-365). `null` = all-time limit. session_expiration_time: type: integer description: Seconds before an unfinished session expires (3600-2419200). version: type: integer description: Version number within the `workflow_id` group, starting at 1. status: type: string enum: - draft - published description: Version status. New sessions use the latest `published` version of a group. has_draft: type: boolean description: True when any version in this `workflow_id` group is currently a draft. created_by: type: object nullable: true description: 'Who created this version: `{name, email, type}` where `type` is `user` (Console user, `email` set) or `api_key` (`name` is the client id, `email` is null). `null` when no creator was recorded.' properties: name: type: string email: type: string nullable: true type: type: string enum: - user - api_key updated_at: type: string format: date-time SimpleWorkflowRequest: type: object description: 'Create a simple linear workflow. The API converts this feature list into a node-based workflow graph internally. STRICT field whitelist: any key not listed here (including `workflow_type`) is rejected with a 400.' required: - features properties: workflow_label: type: string maxLength: 50 default: ID Verification description: Display name for the workflow (max 50 characters). Defaults to `"ID Verification"` when omitted — always set it so workflows stay distinguishable. example: Standard KYC is_default: type: boolean description: Set this workflow as the default for new sessions. status: type: string enum: - draft - published description: Omit this field to create a published workflow ready for sessions. Use `draft` only when you want to save without publishing. features: type: array minItems: 1 description: Verification features in execution order. The API links each item to the next one and adds one final status node automatically. items: $ref: '#/components/schemas/SimpleWorkflowFeature' is_white_label_enabled: type: boolean description: Enable white-label customization for sessions created with this workflow. default: false is_desktop_allowed: type: boolean description: Allow the verification flow to run on desktop browsers. default: false max_retry_attempts: type: integer minimum: 0 maximum: 10 default: 3 description: Maximum retry attempts allowed after a declined verification. `0` blocks the user after the first decline. retry_window_days: type: integer minimum: 1 maximum: 365 nullable: true default: 7 description: Rolling window in days used to count retries. `null` enforces an all-time limit. face_liveness_max_attempts: type: integer minimum: 1 maximum: 3 default: 3 description: 'Maximum liveness submissions per session. Default 3: one initial attempt plus two retries. This value is also copied into generated liveness and age-estimation workflow nodes unless the feature-level config overrides it.' face_match_max_attempts: type: integer minimum: 1 maximum: 3 default: 3 description: 'Maximum face-match submissions per session. Default 3: one initial attempt plus two retries. This value is also copied into generated face-match workflow nodes unless the feature-level config overrides it.' session_expiration_time: type: integer minimum: 3600 maximum: 2419200 default: 604800 description: Seconds before an unfinished session expires. Minimum 1 hour (3600), maximum 4 weeks (2419200). SimpleWorkflowUpdateRequest: type: object description: 'Update workflow metadata or replace the full linear feature list. STRICT field whitelist: any key not listed here is rejected with a 400.' properties: workflow_label: type: string maxLength: 50 description: Display name for the workflow (max 50 characters). is_default: type: boolean description: Set this workflow as the default for new sessions. status: type: string enum: - draft - published description: Controls versioning. Omit to update the current version in place (drafts auto-publish). `published` on an already-published version creates and returns a NEW version. `draft` is only valid while the version is still a draft. features: type: array minItems: 1 description: If provided, this replaces the full feature order and configuration. items: $ref: '#/components/schemas/SimpleWorkflowFeature' is_white_label_enabled: type: boolean description: Enable white-label customization for sessions created with this workflow. is_desktop_allowed: type: boolean description: Allow the verification flow to run on desktop browsers. max_retry_attempts: type: integer minimum: 0 maximum: 10 description: Maximum retry attempts allowed after a declined verification. `0` blocks the user after the first decline. retry_window_days: type: integer minimum: 1 maximum: 365 nullable: true description: Rolling window in days used to count retries. `null` enforces an all-time limit. face_liveness_max_attempts: type: integer minimum: 1 maximum: 3 description: Maximum liveness submissions per session. This value is also copied into generated liveness and age-estimation workflow nodes unless the feature-level config overrides it. face_match_max_attempts: type: integer minimum: 1 maximum: 3 description: Maximum face-match submissions per session. This value is also copied into generated face-match workflow nodes unless the feature-level config overrides it. session_expiration_time: type: integer minimum: 3600 maximum: 2419200 description: Seconds before an unfinished session expires. Minimum 1 hour (3600), maximum 4 weeks (2419200). SimpleWorkflowFeature: type: object required: - feature properties: feature: type: string description: Feature to run. Use the uppercase values shown here. enum: - OCR - NFC - LIVENESS - FACE_MATCH - PROOF_OF_ADDRESS - QUESTIONNAIRE - DOCUMENT_AI - PHONE_VERIFICATION - EMAIL_VERIFICATION - DATABASE_VALIDATION - AML - IP_ANALYSIS - AGE_ESTIMATION - KYB_REGISTRY - KYB_DOCUMENTS - KYB_KEY_PEOPLE config: type: object description: Feature-specific settings. For `QUESTIONNAIRE`, include `questionnaire_uuid` with the `questionnaire_id` returned by the questionnaire create endpoint. additionalProperties: true label: type: string description: Optional internal label for this workflow node. securitySchemes: ApiKeyAuth: type: apiKey in: header name: x-api-key TransactionTokenAuth: type: apiKey in: header name: X-Transaction-Token description: Short-lived scoped token minted by your backend via POST /v3/transactions/sdk-token/. Used by the Didit SDKs on the device-facing /v1/transactions/ endpoints. SessionTokenAuth: type: apiKey in: header name: Session-Token description: Short-lived token returned in the `session_token` field of POST /v3/session/. Used by the hosted verification flow (and custom sandbox UIs) to call session-scoped endpoints on behalf of the verifying user, without your server-side API key.