> ## 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.

# API для создания сценария верификации: KYC-флоу

> Создайте сценарий верификации Didit через API: упорядоченные функции KYC, KYB, AML и биометрия в одном потоке. Оплата за вызов, без контрактов.



Промпт: создание сценария через API
        Скопировать промпт в буфер обмена



      
      

\<pre>

\`Create a simple Didit workflow through the Management API.

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

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

Requirements:
\- Use the simple v3 API shape with features.
\- Send features in the exact order users should complete them.
\- Do not send workflow_graph, branches, actions, webhooks, or conditional logic.
\- Didit will convert the features array into a linear node-based workflow and add the final status step automatically.
\- Use uppercase feature values such as OCR, LIVENESS, FACE_MATCH, AML, QUESTIONNAIRE, EMAIL_VERIFICATION, PHONE_VERIFICATION, or PROOF_OF_ADDRESS.
\- Configure each feature with the fields from /management-api/workflows/feature-configs.
\- For an OCR feature, omit config.documents_allowed or send an empty object to allow every supported document type. Send config.documents_allowed only to restrict the allowed documents.
\- Put dependency features first. For example, put OCR before FACE_MATCH, NFC, DATABASE_VALIDATION, or user AML checks that depend on document data.
\- For a QUESTIONNAIRE feature, first create the questionnaire with POST /v3/questionnaires/ and use the returned questionnaire_id as config.questionnaire_uuid.
\- Store the workflow uuid returned by the response. Use it as workflow_id when creating sessions and as settings_uuid when updating this workflow.

Example KYC request body:
\{
"workflow_label": "Standard KYC",
"features": [
\{
  "feature": "OCR",
  "config": {
    "documents_allowed": {
      "USA": {
        "DL": {
          "enabled": 1,
          "sides": 2
        }
      }
    },
    "duplicated_user_action": "REVIEW"
  }
},
\{
  "feature": "LIVENESS",
  "config": {
    "face_liveness_method": "PASSIVE"
  }
},
\{
  "feature": "FACE_MATCH"
}
]
}

Example questionnaire workflow body:
\{
"workflow_label": "Source of Funds",
"features": [
\{
  "feature": "QUESTIONNAIRE",
  "config": {
    "questionnaire_uuid": "11111111-2222-3333-4444-555555555555",
    "review_questionnaire_manually": true
  }
}
]
}

Build the API call, handle validation errors, and return the workflow uuid from the response.`

\</pre>



      
      

Вставьте в

Используйте этот эндпоинт, чтобы создавать сценарии через API без самостоятельного построения узлов графа. Передайте массив `features` в том порядке, в котором пользователи должны проходить проверки. Didit преобразует его во внутренний сценарий на основе узлов и автоматически добавит финальный шаг со статусом.Эндпоинт `POST /v3/workflows/` создаёт только **простые, линейные** сценарии, то есть плоский список `features`. Для **ветвления, условной маршрутизации, Document AI и узлов отказа/решения** используйте [формат графа](#ветвления-и-сценарии-на-основе-графа-граф) с узлами, описанный ниже. Он лежит в основе визуального конструктора в консоли и инструментов сценариев [Didit MCP](https://docs.didit.me/ru/integration/mcp/overview.md).Все поля `config`, которые принимает каждая функция, перечислены в разделе [Конфигурации функций сценария](https://docs.didit.me/ru/management-api/workflows/feature-configs.md).## Базовый сценарий KYC```json theme={null}
{
  "workflow_label": "Standard KYC",
  "features": [
    {
      "feature": "OCR",
      "config": {
        "documents_allowed": {
          "USA": {
            "DL": {
              "enabled": 1,
              "sides": 2
            }
          }
        },
        "duplicated_user_action": "REVIEW"
      }
    },
    {
      "feature": "LIVENESS",
      "config": {
        "face_liveness_method": "PASSIVE"
      }
    },
    {
      "feature": "FACE_MATCH"
    }
  ]
}
```## Сценарий с анкетойСначала создайте анкету с помощью `POST /v3/questionnaires/`. Затем используйте возвращённый `questionnaire_id` как `questionnaire_uuid`.```json theme={null}
{
  "workflow_label": "Source of Funds",
  "features": [
    {
      "feature": "QUESTIONNAIRE",
      "config": {
        "questionnaire_uuid": "11111111-2222-3333-4444-555555555555",
        "review_questionnaire_manually": true
      }
    }
  ]
}
```Порядок функций важен. Например, `OCR` должен стоять перед `FACE_MATCH`, `NFC`, `DATABASE_VALIDATION` или проверками AML пользователя, которые зависят от данных документа.## Справочник по конфигурации функцийКаждый элемент `features[]` имеет такую структуру:```json theme={null}
{
  "feature": "OCR",
  "label": "ID Verification",
  "config": {}
}
```Точный объект `config` зависит от функции. Полный список полей, значения по умолчанию, обязательные настройки, допустимые диапазоны и примеры см. в разделе [Конфигурации функций сценария](https://docs.didit.me/ru/management-api/workflows/feature-configs.md).Для `OCR` опустите `config.documents_allowed`, передайте `null` или `{}`, чтобы разрешить все поддерживаемые типы документов. Указывайте этот параметр, только если хотите ограничить сценарий определёнными странами или типами документов. Для `QUESTIONNAIRE` поле `config.questionnaire_uuid` обязательно.## Необязательные настройки сценарияПри создании сценария можно добавить любое из этих полей верхнего уровня, чтобы управлять поведением сессии. Все они необязательны. Если поле не указано, используется значение по умолчанию сценария.| Поле | Тип | Описание |
| - | - | - |
| `is_white_label_enabled` | boolean | Включает кастомизацию White label для сессий, созданных с этим сценарием. По умолчанию `false`. |
| `is_desktop_allowed` | boolean | Разрешает запуск потока верификации в браузерах на десктопе. По умолчанию `false`. |
| `max_retry_attempts` | integer (0–10) | Максимальное число повторных попыток после отклонённой верификации. `0` блокирует пользователя после первого отказа. По умолчанию `3`. |
| `retry_window_days` | integer (1–365) или `null` | Скользящее окно в днях, за которое считаются повторные попытки (`null` = лимит за всё время). По умолчанию `7`. |
| `session_expiration_time` | integer (3600–2419200) | Количество секунд до истечения незавершённой сессии. Минимум 1 час, максимум 4 недели. По умолчанию `604800` (7 дней). |
| `response_attributes` | object или `null` | Ограничивает поля, возвращаемые для каждой функции, например `{"id_verifications": ["full_name", "document_number"], "face_matches": null}`. `null` или отсутствующий ключ возвращает все поля. Пустой список возвращает только `status`, `warnings`, `node_id`, `is_nfc_skipped` и `skip_reason`, а остальные поля приходят со значением `null`. |```json theme={null}
{
  "workflow_label": "Standard KYC",
  "is_white_label_enabled": true,
  "is_desktop_allowed": true,
  "max_retry_attempts": 5,
  "retry_window_days": 14,
  "session_expiration_time": 86400,
  "features": [
    { "feature": "OCR" },
    { "feature": "LIVENESS" },
    { "feature": "FACE_MATCH" }
  ]
}
```## Ветвления и сценарии на основе графа (граф)Линейный список `features` не может выразить «если X, то Y». Для **условного ветвления** (отклонение по статусу, маршрутизация по извлечённому полю, условие шага по совпадению), шага запроса **Document AI** или терминальных узлов **отклонения/решения** сценарии Didit используют **граф узлов**, то есть ту же структуру, которую создаёт визуальный конструктор в консоли.> [!NOTE]
>
> Проще всего создать сценарий на основе графа с помощью **[Didit MCP](https://docs.didit.me/ru/integration/mcp/overview.md)**: попросите агента простыми словами («после верификации личности, если профессия ≈ "Software Engineer", добавь шаг подтверждения наличия средств»), и он построит, проверит и сохранит граф за вас. Структура ниже соответствует тому, что создают эти инструменты и консоль.### Структура графаГраф имеет вид `{ start_node, nodes }`. `nodes` — это словарь «идентификатор узла → узел». Рёбра неявные: каждый узел указывает вперёд через `next` (безусловно) и/или `branches[].goto` (условно).| Тип узла | Структура |
| - | - |
| `feature` | `{ "node_type": "feature", "feature": "OCR", "config": {…}, "next": "<id>", "branches": [] }` |
| `branch` | `{ "node_type": "branch", "branches": [ { "id", "logic": "and"\|"or", "rules": [<rule>], "goto": "<id>" } ], "next": "<fallback id>" }` |
| `status` (терминальный) | `{ "node_type": "status", "session_status": "Approved"\|"Declined"\|"In Review"\|"Determine" }` |
| `action` | `{ "node_type": "action", "actions": [ { "type": "add_tag"\|"add_review"\|… } ], "next": "<id>" }` |
| `webhook` | `{ "node_type": "webhook", "config": { "url", "method" }, "branches": [], "next": "<id>" }` |`start_node` должен быть узлом feature. Ветви проверяются по порядку, **срабатывает первое совпадение**. Пустой `rules: []` — это общее правило «иначе» (ставьте его последним). `session_status: "Determine"` принимает решение автоматически на основе совокупного результата функций.> [!WARNING]
>
> **Каждый узел branch должен иметь явную ветвь else**, то есть ветвь с `rules: []`, которая направляет сессии, не подпадающие ни под одно условие. Не полагайтесь на `next` узла branch как на запасной вариант: голый `next` отображается в конструкторе как неоднозначное ребро и его легко пропустить. Если вы отправляете узел branch с `next` и без ветви else, API **преобразует этот `next` в явную ветвь else** автоматически (так, `{ …, "branches": [<conditions>], "next": "liveness" }` сохраняется как `branches: [<conditions>, { "id": "else", "rules": [], "goto": "liveness" }]`). Создайте else сами, чтобы явно задать поведение: преобразование служит страховкой, а не заменой.### Правила ветвления и операторыКаждое правило сравнивает **поле** со **значением** с помощью **оператора**:```json theme={null}
{ "field": "kyc.extra_fields.profession", "operator": "fuzzy_match", "value": "Software Engineer", "score": 80 }
```- **Поля** называют результат функции (`kyc.status`, `aml.status`, `document_ai.status`, `face_match.score`, …) или извлечённое значение (`kyc.full_name`, `kyc.age`, `kyc.nationality`, `kyc.extra_fields.profession`, поле Document AI `document_ai.<key>`, `expected_details.*`). Ветвление может читать поле только в том случае, если соответствующая функция выполнялась на каждом пути, ведущем к этому ветвлению.
- **Операторы:** `equals`, `not_equals`, `greater_than(_or_equals)`, `less_than(_or_equals)`, `contains`, `not_contains`, `in`, `not_in`, `is_empty`, `is_not_empty`, `regex` и **`fuzzy_match`** (только для строковых полей; требует `score` от 0 до 100, то есть порог сходства, например: профессия ≥ 80% похожа на «Software Engineer»).### Ветвление по причине, по которой NFC не выполнялсяПосле узла `NFC` используйте `nfc.skip_reason` с `equals` или `in`, чтобы направлять сессии по причине, по которой чтение чипа не состоялось. Поле имеет семь стабильных значений:- `USER_SKIPPED`
- `DOCUMENT_WITHOUT_CHIP`
- `CHIP_CERTIFICATE_UNAVAILABLE`
- `DEVICE_WITHOUT_NFC`
- `INTEGRATION_WITHOUT_NFC_ACCESS`
- `MRZ_KEY_UNAVAILABLE`
- `JPKI_UNAVAILABLE`Значение каждого из них описано в разделе [Причины пропуска NFC](https://docs.didit.me/ru/core-technology/nfc-verification/warnings-nfc-verification.md#причины-пропуска). Когда NFC выполнен успешно, `nfc.skip_reason` равен `null`, поэтому ни правило `equals`, ни правило `in` для причины пропуска не сработают.Поле также вычисляется для узлов NFC, пропущенных гейтом. Сюда входят случаи, когда отчёта или предупреждения NFC нет, и случаи, когда `allow_nfc_skip` равен `false`, но документ или устройство не позволяют NFC запуститься. Поэтому такие сессии можно направлять, не полагаясь на запись в `nfc_verifications[]`.> [!NOTE]
>
> Сессии, сохранённые до того, как поддержка NFC стала иметь три состояния, могут иметь `has_device_nfc_support: false`. Поэтому более старая веб-сессия может определяться как `DEVICE_WITHOUT_NFC`, а не `INTEGRATION_WITHOUT_NFC_ACCESS`.В этом графе `equals` используется для пропуска пользователем, `in` для пропусков по гейту или возможностям, а явная ветвь else — для успешного NFC. Ветвление идёт после узла `NFC`, и каждый маршрут ведёт вперёд к терминальному узлу:```json theme={null}
{
  "start_node": "ocr",
  "nodes": {
    "ocr": {
      "node_type": "feature",
      "feature": "OCR",
      "next": "nfc"
    },
    "nfc": {
      "node_type": "feature",
      "feature": "NFC",
      "config": { "allow_nfc_skip": false },
      "next": "route_nfc"
    },
    "route_nfc": {
      "node_type": "branch",
      "branches": [
        {
          "id": "user_skipped",
          "logic": "and",
          "rules": [
            { "field": "nfc.skip_reason", "operator": "equals", "value": "USER_SKIPPED" }
          ],
          "goto": "manual_review"
        },
        {
          "id": "nfc_unavailable",
          "logic": "and",
          "rules": [
            {
              "field": "nfc.skip_reason",
              "operator": "in",
              "value": [
                "DOCUMENT_WITHOUT_CHIP",
                "CHIP_CERTIFICATE_UNAVAILABLE",
                "DEVICE_WITHOUT_NFC",
                "INTEGRATION_WITHOUT_NFC_ACCESS",
                "MRZ_KEY_UNAVAILABLE",
                "JPKI_UNAVAILABLE"
              ]
            }
          ],
          "goto": "manual_review"
        },
        {
          "id": "else",
          "logic": "and",
          "rules": [],
          "goto": "approved"
        }
      ]
    },
    "manual_review": { "node_type": "status", "session_status": "In Review" },
    "approved": { "node_type": "status", "session_status": "Approved" }
  }
}
```Чтобы выразить «NFC не выполнялся ни по одной из известных причин», используйте `in` со **всеми семью** значениями. Оставьте явную ветвь else для успешного NFC (`nfc.skip_reason: null`) и для любого будущего значения, которое ваш граф пока не распознаёт.### Document AI (например, подтверждение наличия средств)Узел `DOCUMENT_AI` запрашивает один или несколько документов и извлекает именованные поля:```json theme={null}
{
  "node_type": "feature",
  "feature": "DOCUMENT_AI",
  "label": "Proof of Funds",
  "config": {
    "document_ai_documents": [
      {
        "document_key": "proof_of_funds",
        "title": "Proof of Funds",
        "description": "Upload a recent bank statement.",
        "fields": [
          {
            "key": "account_holder",
            "name": "Account holder",
            "instruction": "The full name of the account holder as printed on the statement.",
            "type": "text",
            "required": true,
            "is_full_name": true
          },
          {
            "key": "closing_balance",
            "name": "Closing balance",
            "instruction": "The closing balance amount.",
            "type": "number",
            "required": true
          }
        ]
      }
    ],
    "document_ai_missing_required_fields_action": "REVIEW",
    "document_ai_name_mismatch_action": "REVIEW"
  },
  "next": "final_decision"
}
```Каждое настроенное поле становится значением, по которому можно выполнять ветвление: `document_ai.<key>`, а результатом шага является `document_ai.status`.Установите `"is_full_name": true` для поля, в котором содержится полное имя держателя документа. Его извлечённое значение сравнивается с полным именем проверенной личности (имя из OCR или верификации личности либо ожидаемые данные сессии). `document_ai_name_mismatch_action` определяет, что произойдёт при несовпадении ниже `document_ai_name_match_score_threshold`. Флаг **необязательный**: для документа можно не указывать ни одного поля, но **не более одного поля в документе** может иметь этот флаг. Все поля конфигурации Document AI см. в разделе [Конфигурация функций сценария → Document AI](https://docs.didit.me/ru/management-api/workflows/feature-configs.md#document-ai).### Эндпоинты и жизненный цикл черновикаРедактирование графа выполняется для каждого приложения и использует эндпоинты консоли и управления (Bearer-токен пользователя + `read:workflows`/`write:workflows`). Граф можно редактировать только в **черновой** версии, поэтому жизненный цикл такой: **создать черновик → задать граф → опубликовать**.| Метод | Путь | Назначение |
| - | - | - |
| `GET` | `…/verification-settings/{settings_uuid}/workflow-graph/` | Текущий граф + `status`/`is_editable` |
| `POST` | `…/application/{app}/workflow-graph/validate/` (body `{ "graph": … }`) | Проверка без сохранения (пробный запуск) |
| `GET` | `…/application/{app}/workflow-graph/field-definitions/` | Поля, по которым можно ветвить, и допустимые операторы |
| `POST` | `…/verification-settings/{settings_uuid}/create-draft/` | Редактируемый черновик из опубликованной версии |
| `PUT` | `…/verification-settings/{settings_uuid}/workflow-graph/` (body `{ "graph": … }`) | Сохранить граф |
| `PATCH` | `…/verification-settings/{settings_uuid}/` (body `{ "status": "published" }`) | Опубликовать черновик |#### Предупреждения валидацииEndpoint валидации возвращает `{ "is_valid": true, "graph": …, "warnings": [] }`. Предупреждение носит **рекомендательный** характер: граф корректен, его можно сохранить и опубликовать, даже если предупреждения есть. Каждая запись содержит узел ветвления и ветку, к которой она относится, чтобы конструктор мог указать на конкретное условие:```json theme={null}
{
  "type": "branch_outcome_contradiction",
  "node_id": "after_ocr",
  "branch_id": "b1",
  "severity": "warning",
  "message": "Branch 1 only matches sessions where ID Verification Status is Approved or In Review, but every path from it ends in the session outcome \"Declined\". Check the condition or the outcome.",
  "params": { "branchNumber": 1, "field": "ID Verification Status", "allowed": "Approved or In Review", "outcome": "Declined" }
}
```| `type` | Что это означает |
| - | - |
| `branch_outcome_contradiction` | Условие ветки и результат, к которому приводит каждый путь из неё, противоречат друг другу. Например, `kyc.status NOT EQUALS Declined`, направленное в результат `Declined`. Результат может находиться через несколько шагов дальше по пути. |
| `branch_condition_unreachable` | Ветка никогда не сработает, потому что каждый путь, ведущий к этому ветвлению, уже ограничивает поле статуса значениями, которые условие исключает. |
| `else_branch_unreachable` | Ветка else никогда не выполнится: остальные ветки уже покрывают все значения, которые поле может здесь принимать. |Невалидный граф возвращает `400` с `errors` **и** списком `warnings` по возможности. Только `errors` блокируют сохранение.### Пример: направить инженеров-программистов на подтверждение наличия средств> После верификации личности: если она была **отклонена**, отклонить сессию; если профессия владельца ≈ "Software Engineer" (сходство ≥80%), запросить документ, подтверждающий наличие средств; затем принять окончательное решение.```json theme={null}
{
  "start_node": "ocr_1",
  "nodes": {
    "ocr_1": { "node_type": "feature", "feature": "OCR", "label": "ID Verification", "next": "after_ocr" },
    "after_ocr": {
      "node_type": "branch",
      "label": "Route after ID verification",
      "branches": [
        { "id": "declined", "logic": "or", "rules": [ { "field": "kyc.status", "operator": "equals", "value": "Declined" } ], "goto": "decline" },
        { "id": "software_engineer", "logic": "and", "rules": [ { "field": "kyc.extra_fields.profession", "operator": "fuzzy_match", "value": "Software Engineer", "score": 80 } ], "goto": "proof_of_funds" },
        { "id": "else", "logic": "and", "rules": [], "goto": "final_decision" }
      ]
    },
    "proof_of_funds": {
      "node_type": "feature",
      "feature": "DOCUMENT_AI",
      "label": "Proof of Funds",
      "config": {
        "document_ai_documents": [
          { "document_key": "proof_of_funds", "title": "Proof of Funds", "description": "Upload a recent bank statement.",
            "fields": [
              { "key": "account_holder", "name": "Account holder", "type": "text", "required": true },
              { "key": "closing_balance", "name": "Closing balance", "type": "number", "required": true }
            ] }
        ],
        "document_ai_missing_required_fields_action": "REVIEW"
      },
      "next": "final_decision"
    },
    "final_decision": { "node_type": "status", "session_status": "Determine", "label": "Final decision" },
    "decline": { "node_type": "status", "session_status": "Declined", "label": "Declined" }
  }
}
```Финальный узел использует `session_status: "Determine"`, который **автоматически принимает решение** (одобрить / отклонить / отправить на проверку) на основе тех функций, которые реально выполнялись в сессии. Поэтому и путь с подтверждением наличия средств, и путь else корректно приводят к решению, без того чтобы какая-либо ветка читала `document_ai.status` (этого поля нет на пути, где Document AI пропускается). Помните: ветвь может читать только то поле, функция которого выполнялась на *каждом* пути, ведущем к ней.Отправьте его в виде `{ "graph": <above> }` на endpoint `…/workflow-graph/` (сначала выполните валидацию). Чтобы создать **новый** сценарий с нуля, используйте `didit_workflow_set_graph` из MCP; чтобы **изменить существующий** сценарий, используйте `didit_workflow_edit_graph` (небольшие операции, которые сохраняют существующие узлы и списки разрешённых значений). См. [Didit MCP](https://docs.didit.me/ru/integration/mcp/tools.md).


## OpenAPI

````yaml ru/openapi-25.json POST /v3/workflows/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: >-
    API верификации личности. Аутентификация выполняется с помощью заголовка
    x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/workflows/:
    post:
      tags:
        - Workflows
      summary: Создать сценарий
      description: >-
        Создайте простой сценарий. Передавайте `features` в порядке выполнения
        (применяются правила порядка); по умолчанию создаётся опубликованная
        (`published`) версия v1. Тело запроса принимает ТОЛЬКО поля,
        перечисленные в `SimpleWorkflowRequest`: любой другой ключ (включая
        `workflow_type`) отклоняется с кодом 400. Не идемпотентно: каждый вызов
        создаёт новый сценарий. Не более 50 сценариев на приложение.
      operationId: create_workflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimpleWorkflowRequest'
            examples:
              Simple KYC:
                summary: >-
                  Линейный сценарий верификации личности, проверки живости и
                  сравнения лиц
                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: Запустить AML после верификации личности
                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: Запустить анкету, созданную с помощью 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: >-
            Сценарий создан. Тело ответа представляет собой ПОЛНУЮ конфигурацию
            сценария — ту же исходную сериализацию `VerificationSettings`,
            возвращаемую `GET /v3/workflows/{settings_uuid}/` (~190 полей:
            переключатель каждой функции, порог, действие и сгенерированный
            `workflow_graph`), а не компактный элемент списка. Сохраните `uuid`
            (также доступный как `workflow_id`), чтобы ссылаться на него в
            последующих вызовах создания сессий. Примечание: `features`
            представляет собой строку, объединённую с помощью `" + "`, а цены
            являются числами JSON.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowDetail'
              examples:
                Created (abbreviated):
                  summary: Ключевые поля полного объекта конфигурации
                  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: >-
            Ошибка валидации. Частые причины: ключ верхнего уровня вне
            допустимого белого списка (например, `workflow_type`), неизвестное
            значение `feature`, функция, расположенная до ее зависимости
            (например, `FACE_MATCH` перед `OCR`), пассивная функция (`AML`,
            `IP_ANALYSIS`, `DATABASE_VALIDATION`, `KYB_KEY_PEOPLE`),
            используемая в качестве первого шага, функция `QUESTIONNAIRE`, чей
            `config.questionnaire_uuid` не существует для этого приложения,
            функция `SIGNATURE`, которая будет запущена без документа для
            подписания, функция `SIGNATURE` с `signature_level: "aes"`, когда
            Advanced (AES) недоступен (`aes_not_available`, см.
            `signature_availability` в сценарии), или порог вне допустимого
            диапазона. Тело представляет собой объект ошибки валидации DRF:
            ключами являются имена полей, а значениями являются массивы понятных
            человеку сообщений.
          content:
            application/json:
              examples:
                Advanced (AES) not available:
                  value:
                    features:
                      signature_level:
                        - >-
                          Node 'signature': Advanced (AES) is not available yet
                          (aes_not_available).
                Signature step with no document:
                  value:
                    features:
                      non_field_errors:
                        - >-
                          Node 'signature': Add a document to sign, or let each
                          session bring its own.
                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: >-
            API-ключ отсутствует, сформирован неверно, истёк или привязан к
            другому приложению. Обновите через [Auth
            API](/ru/auth-api/get-credentials) и повторите попытку.
          content:
            application/json:
              examples:
                Invalid token:
                  value:
                    detail: You do not have permission to perform this action.
        '415':
          description: >-
            Неподдерживаемый тип содержимого. Укажите `Content-Type:
            application/json` и передайте тело в формате JSON.
        '429':
          description: >-
            Превышен лимит запросов. Повторите попытку с экспоненциальной
            задержкой.
        '500':
          description: >-
            Непредвиденная ошибка сервера при создании сценария. Повторная
            попытка безопасна.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://verification.didit.me/v3/workflows/' \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "workflow_label": "Standard KYC",
                "features": [
                  {"feature": "OCR"},
                  {"feature": "LIVENESS", "config": {"face_liveness_method": "passive"}},
                  {"feature": "FACE_MATCH", "config": {"face_match_score_decline_threshold": 40, "face_match_score_review_threshold": 60}}
                ]
              }'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.workflows.create(
                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},
                }],
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit from "@didit-protocol/sdk-node";

            // Reads DIDIT_API_KEY.
            const didit = new Didit();

            const result = await didit.workflows.create({
              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 },
              }],
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Workflows.Create(ctx, didit.SimpleWorkflowRequest{\n\tWorkflowLabel: didit.String(\"Standard KYC\"),\n\tFeatures: []didit.SimpleWorkflowFeature{{\n\t\tFeature: \"OCR\",\n\t\tConfig:  didit.Some(map[string]any{\"duplicated_user_action\": \"review\"}),\n\t}, {\n\t\tFeature: \"LIVENESS\",\n\t\tConfig:  didit.Some(map[string]any{\"face_liveness_method\": \"passive\"}),\n\t}, {\n\t\tFeature: \"FACE_MATCH\",\n\t\tConfig:  didit.Some(map[string]any{\"face_match_score_decline_threshold\": 40, \"face_match_score_review_threshold\": 60}),\n\t}},\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.util.List;

            import java.util.Map;

            import me.didit.Didit;

            import me.didit.types.SimpleWorkflowFeature;

            import me.didit.types.SimpleWorkflowRequest;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.workflows().create(SimpleWorkflowRequest.builder()
                    .workflowLabel("Standard KYC")
                    .features(List.of(
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("OCR"))
                                    .config(Map.of("duplicated_user_action", "review"))
                                    .build(),
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("LIVENESS"))
                                    .config(Map.of("face_liveness_method", "passive"))
                                    .build(),
                            SimpleWorkflowFeature.builder()
                                    .feature(SimpleWorkflowFeature.Feature.of("FACE_MATCH"))
                                    .config(Map.of("face_match_score_decline_threshold", 40, "face_match_score_review_threshold", 60))
                                    .build()))
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;

            // Reads DIDIT_API_KEY.
            $didit = new DiditClient();

            $result = $didit->workflows->create([
                '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],
                ]],
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.workflows.create(
              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 },
              }]
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Collections.Generic;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await client.Workflows.CreateAsync(new
            SimpleWorkflowRequest

            {
                WorkflowLabel = "Standard KYC",
                Features = new SimpleWorkflowFeature[]
                {
                    new()
                    {
                        Feature = "OCR",
                        Config = new Dictionary<string, object> { ["duplicated_user_action"] = "review" },
                    },
                    new()
                    {
                        Feature = "LIVENESS",
                        Config = new Dictionary<string, object> { ["face_liveness_method"] = "passive" },
                    },
                    new()
                    {
                        Feature = "FACE_MATCH",
                        Config = new Dictionary<string, object> { ["face_match_score_decline_threshold"] = 40, ["face_match_score_review_threshold"] = 60 },
                    },
                },
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    SimpleWorkflowRequest:
      type: object
      description: >-
        Создайте простой линейный сценарий. API преобразует этот список функций
        во внутренний граф сценария на основе узлов. СТРОГИЙ белый список полей:
        любой ключ, не указанный здесь (включая `workflow_type`), отклоняется с
        кодом 400.
      required:
        - features
      properties:
        workflow_label:
          type: string
          maxLength: 50
          default: ID Verification
          description: >-
            Отображаемое имя для сценария (максимум 50 символов). По умолчанию
            `"ID Verification"`, если параметр опущен — всегда задавайте его,
            чтобы сценарии оставались различимыми.
          example: Standard KYC
        is_default:
          type: boolean
          description: Установить этот сценарий по умолчанию для новых сессий.
        status:
          type: string
          enum:
            - draft
            - published
          description: >-
            Опустите это поле, чтобы создать опубликованный сценарий, готовый к
            запуску сессий. Используйте `draft`, только если хотите сохранить
            без публикации.
        features:
          type: array
          minItems: 1
          description: >-
            Функции верификации в порядке выполнения. API связывает каждый
            элемент со следующим и автоматически добавляет один финальный узел
            статуса.
          items:
            $ref: '#/components/schemas/SimpleWorkflowFeature'
        is_white_label_enabled:
          type: boolean
          description: >-
            Включить кастомизацию White label для сессий, созданных с этим
            сценарием.
          default: false
        is_desktop_allowed:
          type: boolean
          description: Разрешить запуск сценария верификации в браузерах на десктопе.
          default: false
        max_retry_attempts:
          type: integer
          minimum: 0
          maximum: 10
          default: 3
          description: >-
            Максимальное количество повторных попыток после отклонения
            верификации. `0` блокирует пользователя после первого отклонения.
        retry_window_days:
          type: integer
          minimum: 1
          maximum: 365
          nullable: true
          default: 7
          description: >-
            Скользящее окно в днях для подсчёта повторных попыток. `null`
            устанавливает лимит за всё время.
        face_liveness_max_attempts:
          type: integer
          minimum: 1
          maximum: 3
          default: 3
          description: >-
            Максимальное количество попыток проверки живости за сессию. По
            умолчанию 3: одна начальная попытка плюс две повторные попытки. Это
            значение также копируется в сгенерированные узлы проверки живости и
            оценки возраста в сценарии, если только оно не переопределено в
            конфигурации на уровне функции.
        face_match_max_attempts:
          type: integer
          minimum: 1
          maximum: 3
          default: 3
          description: >-
            Максимальное количество попыток сравнения лиц за сессию. По
            умолчанию 3: одна начальная попытка плюс две повторные попытки. Это
            значение также копируется в сгенерированные узлы сравнения лиц в
            сценарии, если только оно не переопределено в конфигурации на уровне
            функции.
        session_expiration_time:
          type: integer
          minimum: 3600
          maximum: 2419200
          default: 604800
          description: >-
            Количество секунд до истечения срока незавершённой сессии. Минимум 1
            час (3600), максимум 4 недели (2419200).
    WorkflowDetail:
      type: object
      description: >-
        Поля ниже являются типизированными; объект также содержит все остальные
        столбцы конфигурации сценария (переключатели функций, пороги, действия
        при предупреждениях, разрешённые документы, обратные вызовы) в качестве
        дополнительных свойств. Поля, неприменимые к `workflow_type`, имеют
        значение `null`.
      properties:
        uuid:
          type: string
          format: uuid
          description: >-
            Идентификатор конкретной версии (`settings_uuid`). Каждая версия
            сценария имеет собственный идентификатор.
        workflow_id:
          type: string
          format: uuid
          description: >-
            Постоянный идентификатор, общий для всех версий сценария. Созданные
            с его помощью сессии используют последнюю опубликованную версию.
        workflow_label:
          type: string
          description: Отображаемое имя сценария.
        workflow_type:
          type: string
          nullable: true
          enum:
            - kyc
            - kyb
            - adaptive_age_verification
            - biometric_authentication
            - address_verification
            - questionnaire_verification
            - email_verification
            - phone_verification
            - null
          description: >-
            Шаблон сценария. `null` для графовых сценариев, созданных без
            шаблона.
        is_default:
          type: boolean
          description: Является ли этот сценарий сценарием по умолчанию для приложения.
        is_archived:
          type: boolean
          description: Архивные сценарии не могут запускать новые сессии.
        version:
          type: integer
          description: Номер версии внутри сценария.
        status:
          type: string
          enum:
            - draft
            - published
          description: >-
            Черновые версии можно редактировать; опубликованные версии
            неизменяемы и используются для новых сессий.
        published_at:
          type: string
          format: date-time
          nullable: true
          description: Когда была опубликована эта версия. `null` для черновиков.
        is_simple_workflow:
          type: boolean
          description: '`true`, если сценарий не имеет пользовательского `workflow_graph`.'
        is_editable:
          type: boolean
          description: '`true` только для версий со статусом `draft`.'
        workflow_url:
          type: string
          format: uri
          description: Публичный URL для запуска сессии с этим сценарием.
        workflow_graph:
          type: object
          nullable: true
          additionalProperties: true
          description: >-
            Структура графа сценария (узлы и рёбра). `null` для простых
            сценариев.
        features:
          type: string
          description: >-
            Включенные функции, объединенные через `" + "`, например `"OCR +
            LIVENESS"`.
        total_price:
          type: number
          nullable: true
          description: Цена за сессию; для графовых сценариев это самый дорогой путь.
        min_price:
          type: number
          nullable: true
          description: Цена самого дешёвого пути в сценарии.
        max_price:
          type: number
          nullable: true
          description: Цена самого дорогого пути в сценарии.
        special_add_on_prices:
          type: object
          nullable: true
          additionalProperties: true
          description: >-
            Специальные цены на дополнения для организации или `null`, если они
            не заданы.
        max_retry_attempts:
          type: integer
          description: >-
            Количество повторных попыток, разрешенных после отклоненной
            верификации.
        retry_window_days:
          type: integer
          nullable: true
          description: Количество дней, в течение которых разрешены повторные попытки.
        session_expiration_time:
          type: integer
          description: Количество секунд до истечения срока незавершённой сессии.
        questionnaire:
          type: object
          nullable: true
          additionalProperties: true
          description: Анкета, прикрепленная к сценарию, или `null`.
        kyb_role_settings:
          type: array
          items:
            type: object
            additionalProperties: true
          description: Настройки верификации по ролям для ключевых лиц KYB.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        signature_availability:
          type: object
          description: >-
            Какие уровни Электронной подписи доступны для подписания прямо
            сейчас. Проверьте это перед установкой `signature_level`.
            Возвращается в сценариях `kyc`, `kyb` и графовых сценариях.
          properties:
            simple:
              type: boolean
              description: Simple доступен всегда.
            aes:
              type: boolean
              description: >-
                Доступна ли сейчас подпись с расширенным уровнем (AES). Пока
                значение `false`, сохранение нового шага с `signature_level:
                "aes"` отклоняется с ошибкой `aes_not_available`.
            qes:
              type: boolean
              description: >-
                Доступна ли сейчас подпись с квалифицированным уровнем (QES).
                Имеет значение `false`, пока не подключен квалифицированный
                провайдер.
        is_bank_verification_enabled:
          type: boolean
          description: >-
            Выполняется ли в простом сценарии KYC или KYB верификация банка. Она
            выполняется после шагов контакта (и верификации местоположения) и
            перед проверкой по базам данных, AML и анализом IP. Верификация
            банка пока не является общедоступной: её включение отклоняется
            везде, где она не активирована.
        bank_verification_config:
          type: object
          additionalProperties: true
          description: >-
            Настройки верификации банковских счетов простого сценария с теми же
            ключами, которые принимает узел `BANK_VERIFICATION` (например,
            `bank_countries` и `bank_method_order`). Неизвестные ключи
            отбрасываются. Каждый ключ необязателен, а отсутствующий ключ
            сохраняет значение по умолчанию, поэтому `{}` означает использование
            всех значений по умолчанию. См. раздел [Настройки верификации
            счетов](/ru/management-api/workflows/feature-configs#верификация-банка).
          example: {}
        is_geolocation_enabled:
          type: boolean
          description: >-
            Выполняется ли в простом сценарии KYC верификация местоположения.
            Она выполняется после шагов контакта и перед верификацией банка и
            проверкой по базам данных. В сценариях верификации бизнеса (KYB)
            этот шаг недоступен.
        geolocation_config:
          type: object
          additionalProperties: true
          description: >-
            Настройки верификации местоположения для простого сценария с теми же
            ключами, которые принимает узел `GEOLOCATION` (например,
            `is_geolocation_geofencing_enabled` и `geolocation_max_attempts`).
            Неизвестные ключи отбрасываются. Каждый ключ необязателен;
            отсутствующий ключ сохраняет значение по умолчанию, поэтому `{}`
            означает использование всех значений по умолчанию.
          example: {}
      additionalProperties: true
    SimpleWorkflowFeature:
      type: object
      required:
        - feature
      properties:
        feature:
          type: string
          description: >-
            Функция для запуска. Используйте значения в верхнем регистре,
            приведенные здесь.
          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
            - SIGNATURE
        config:
          type: object
          description: >-
            Настройки конкретной функции. Для `QUESTIONNAIRE` укажите
            `questionnaire_uuid` со значением `questionnaire_id`, возвращённым
            endpoint создания анкеты. Для `SIGNATURE`: сценарию, переводимому в
            продакшн, требуется документ для подписания: установите
            `signature_documents_source` в `session` или `both`, чтобы каждая
            сессия могла передавать свой собственный, либо передайте `status:
            "draft"` и добавьте документы перед публикацией. Значение
            `signature_level: "aes"` отклоняется с ошибкой `aes_not_available`,
            пока `signature_availability.aes` имеет значение `false` в сценарии.
            Для `OCR` параметр `methods` определяет, какие методы Верификации
            личности разрешены для каждой страны (захват документа, проверка без
            документов по государственным или другим авторитетным источникам и
            цифровые кошельки удостоверений личности); если его опустить, для
            всех стран будет использоваться только захват документов. Для
            `SIGNATURE` см. [Настройки электронной
            подписи](/ru/management-api/workflows/feature-configs#электронная-подпись):
            `signature_level` сейчас принимает значения `simple` (по умолчанию,
            верификация личности, электронная почта или телефон не требуются) и
            `aes`, а документы сценария и их поля настраиваются в консоли,
            поэтому через API отправляйте документы и поля для каждой сессии с
            параметром `signature_documents_source: "session"`.
          additionalProperties: true
        label:
          type: string
          description: Необязательная внутренняя метка для этого узла сценария.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API-ключ вашего приложения из раздела «Разработчикам» -> «API-ключи» в
        Business Console. Основной ключ имеет полный доступ. Именованный ключ
        может иметь ограниченную область действия: без доступа, чтение или
        запись для каждого ресурса, ограничение определенными сценариями или
        одобренными сессиями, списком IP-адресов и сроком действия. 401
        означает, что ключ неверен, отозван или его срок действия истек; 403
        означает, что ключ не был передан, у ключа нет доступа к этому ресурсу
        или действию, либо запрос поступил с адреса вне его списка IP-адресов;
        404 на маршруте сессии означает, что сессия не входит в сценарии или
        статусы ключа. Ключ без доступа к медиа получает URL изображений, видео
        и PDF как null, а ключ без прав на запись сессий получает ссылки на
        сессии и токены как null. См. https://docs.didit.me/console/api-keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.