> ## 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 流程

> 通过 API 以编程方式创建 Didit 验证工作流，按顺序编排 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>



      
      

粘贴到

使用此 endpoint 可以通过 API 创建工作流，无需自行构建工作流图节点。请按用户应完成检查的顺序发送 `features` 数组。Didit 会将其转换为基于节点的工作流，并自动添加最终状态步骤。此 `POST /v3/workflows/` endpoint 仅创建**简单的线性**工作流，即扁平的 `features` 列表。如需**分支、条件路由、Document AI 以及拒绝/决策节点**，请使用下文介绍的节点[图格式](#分支与基于节点的工作流（图）)（它为控制台中的可视化构建器和 [Didit MCP](https://docs.didit.me/zh/integration/mcp/overview.md) 工作流工具提供支持）。请参阅[工作流功能配置](https://docs.didit.me/zh/management-api/workflows/feature-configs.md)，了解每个功能接受的所有 `config` 字段。## 基础 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/zh/management-api/workflows/feature-configs.md)中查看完整字段列表、默认值、必填设置、取值范围和示例。对于 `OCR`，省略 `config.documents_allowed`、发送 `null` 或发送 `{}`，即可允许所有受支持的证件类型。仅当您希望将工作流限制为特定国家/地区或证件类型时，才需要包含此字段。对于 `QUESTIONNAIRE`，`config.questionnaire_uuid` 为必填项。## 可选工作流设置创建工作流时，您可以包含以下任一顶级字段来控制会话行为。这些字段均为可选，省略时将使用工作流默认值。| 字段 | 类型 | 说明 |
| - | - | - |
| `is_white_label_enabled` | 布尔值 | 为使用此工作流创建的会话启用白标定制。默认值为 `false`。 |
| `is_desktop_allowed` | 布尔值 | 允许验证流程在桌面浏览器中运行。默认值为 `false`。 |
| `max_retry_attempts` | 整数（0–10） | 验证被拒绝后允许的最大重试次数。`0` 表示用户首次被拒绝后即被阻止。默认值为 `3`。 |
| `retry_window_days` | 整数（1–365）或 `null` | 用于统计重试次数的滚动时间窗口（以天为单位）（`null` 表示按所有时间统计重试次数（即全时段限制））。默认值为 `7`。 |
| `session_expiration_time` | 整数（3600–2419200） | 未完成的会话过期前的秒数。最短 1 小时，最长 4 周。默认值为 `604800`（7 天）。 |
| `response_attributes` | 对象或 `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/zh/integration/mcp/overview.md)**：用自然语言向智能体提出需求（“完成身份验证后，如果职业大致为“Software Engineer”，则添加资金证明步骤”），它会为您构建、验证并保存该图。下面的结构就是这些工具（以及控制台）生成的结果。### 图的结构图的形式为 `{ start_node, nodes }`。`nodes` 是从节点 ID 到节点的映射。边是隐式的：每个节点通过 `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` 必须是功能节点。分支按顺序求值，**先匹配者胜出**；空的 `rules: []` 是兜底的“否则”分支（需放在最后）。`session_status: "Determine"` 会根据各功能的综合结果自动做出决定。> [!WARNING]
>
> **每个分支节点都必须有明确的否则分支**，即一个 `rules: []` 的分支，用于承接与所有条件都不匹配的会话。不要依赖分支节点的 `next` 作为兜底：单独的 `next` 在构建器中会呈现为含糊不清的边，而且很容易被遗漏。如果您发送的分支节点带有 `next` 却没有否则分支，API 会为您**将该 `next` 转换为明确的否则分支**（例如 `{ …, "branches": [<conditions>], "next": "liveness" }` 会被保存为 `branches: [<conditions>, { "id": "else", "rules": [], "goto": "liveness" }]`）。请自行构建否则分支以保持明确；该转换只是安全兜底，不能替代显式定义。### 分支规则与运算符每条规则使用**运算符**将**字段**与**值**进行比较：```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.*`）。分支只能读取在所有通往该分支的路径上都已运行过的 feature 的字段。
- **运算符：**`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`**（仅适用于字符串字段；需要一个 0–100 的 `score`，即相似度阈值，例如职业与 "Software Engineer" 的相似度 ≥ 80%）。### 根据 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/zh/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` 可能存在。因此，较早的 Web 会话可能会解析为 `DEVICE_WITHOUT_NFC`，而不是 `INTEGRATION_WITHOUT_NFC_ACCESS`。该图对用户跳过使用 `equals`，对门控或能力跳过使用 `in`，并为成功的 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`。对于成功的 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_match_score_threshold` 时，由 `document_ai_name_mismatch_action` 决定后续处理。该标志为**可选**项，一份证件可以不标记任何字段，但**每份证件最多只能有一个字段**设置该标志。Document AI 的全部配置字段请参阅 [工作流功能配置 → Document AI](https://docs.didit.me/zh/management-api/workflows/feature-configs.md#document-ai)。### endpoint 与草稿生命周期图的编辑按应用进行，使用控制台/管理 endpoint（用户 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" }`) | 发布草稿 |#### 校验警告校验端点返回 `{ "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> }` 的形式发送到 `…/workflow-graph/` 端点（请先调用校验端点）。要从零开始创建**新**工作流，请使用 MCP 的 `didit_workflow_set_graph`；要**修改现有**工作流，请使用 `didit_workflow_edit_graph`（少量操作，保留现有节点和允许列表）。参阅 [Didit MCP](https://docs.didit.me/zh/integration/mcp/tools.md)。


## OpenAPI

````yaml zh/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: >-
            工作流已创建。响应体为完整的工作流配置，与 `GET /v3/workflows/{settings_uuid}/` 返回的原生
            `VerificationSettings` 序列化内容相同（约 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`
            值、功能放置在其依赖项之前（例如在 `OCR` 之前放置
            `FACE_MATCH`）、将被动功能（`AML`、`IP_ANALYSIS`、`DATABASE_VALIDATION`、`KYB_KEY_PEOPLE`）用作第一步、`QUESTIONNAIRE`
            功能的 `config.questionnaire_uuid` 在此应用中不存在、`SIGNATURE`
            功能在没有待签署证件的情况下上线、`SIGNATURE` 功能设置为 `signature_level: "aes"`
            但高级签名（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](/zh/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: 为使用此工作流创建的会话启用白标定制。
          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: 当工作流没有自定义 `workflow_graph` 时为 `true`。
        is_editable:
          type: boolean
          description: 仅对 `draft` 版本为 `true`。
        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`）。未知键将被丢弃。每个键均为可选，缺少的键保持其默认值，因此 `{}`
            表示全部使用默认值。参见[银行验证设置](/zh/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` 中传入问卷创建 endpoint
            返回的 `questionnaire_id`。对于 `SIGNATURE`，上线的工​​作流需要待签署的证件：将
            `signature_documents_source` 设置为 `session` 或 `both` 以便每次会话自带证件，或者发送
            `status: "draft"` 并在发布前添加证件。当工作流上的 `signature_availability.aes` 为
            `false` 时，`signature_level: "aes"` 会被拒绝并返回 `aes_not_available`。对于
            `OCR`，`methods`
            用于选择每个国家/地区可以使用的身份证件验证方法（证件采集、针对政府或其他权威来源的非证件查询，以及数字身份钱包）；如果省略，则所有国家/地区仅支持证件采集。对于
            `SIGNATURE`，请参阅[电子签名设置](/zh/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 密钥，可在 Business Console 的“开发者 -> API
        密钥”中获取。主密钥拥有完整访问权限。指定名称的密钥可设置作用域：针对每个资源设为无权限、只读或读写，限定于特定工作流或已通过的会话、限定于
        IP 地址列表，以及设置到期日期。401 表示密钥错误、已撤销或已过期；403 表示未发送密钥、密钥无权访问该资源或操作，或请求来自其 IP
        列表之外的地址；在会话路由上返回 404 表示该会话不在该密钥允许的工作流或状态范围内。没有媒体访问权限的密钥获取到的图片、视频和 PDF
        URL 将为 null；没有会话写入权限的密钥获取到的会话链接和 token 将为 null。请参阅
        https://docs.didit.me/console/api-keys。

````

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