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

# Document AI API：自定义证件数据提取

> Didit 的 POST /v3/document-ai/ 接口可服务端调用，从任意 PDF 或图片中提取您定义的字段，支持姓名匹配与篡改检测。每份文档 $0.20。

发送一份证件以及需要从中读取的字段列表。Didit 会使用其默认提取模型处理文件，返回每个带类型的字段（`text`、`number` 或 `date`；日期格式为 `YYYY-MM-DD`），检测并解码受支持的 QR 码和条形码，检查文件是否被篡改，并可选择将证件上的姓名与您预期的个人或企业进行比对。适用于资金证明、工资单、银行对账单、税务文件、发票，或任何不符合固定模板的证件。

这是托管式 [Document AI](https://docs.didit.me/zh/core-technology/document-ai/overview.md) 步骤的服务器到服务器版本。请求格式为 `multipart/form-data`：文件放在 `document` 中，字段定义以单个 JSON 编码数组字符串的形式放在 `fields` 中。

## 定义要提取的字段

`fields` 是一个包含 1 到 30 项的 JSON 数组，以单个字符串形式发送。每一项包含 `key`（小写字母、数字和下划线，在同一请求中必须唯一）、便于阅读的 `name`、告诉模型要查找什么的 `instruction`、`type`（`text`、`number` 或 `date`），以及两个标志：`required` 和 `is_full_name`。

```json theme={null}
[
  {
    "key": "account_holder",
    "name": "Account holder",
    "instruction": "Full name of the person or company the account belongs to",
    "type": "text",
    "required": true,
    "is_full_name": true
  },
  {
    "key": "balance",
    "name": "Closing balance",
    "instruction": "Closing balance shown on the statement, as a number without the currency symbol",
    "type": "number",
    "required": true
  },
  {
    "key": "currency",
    "name": "Currency",
    "instruction": "Three-letter currency code of the balance",
    "type": "text"
  },
  {
    "key": "statement_date",
    "name": "Statement date",
    "instruction": "Date the statement was issued",
    "type": "date",
    "required": true
  }
]
```

在 multipart 请求中，整个数组是一个表单值：

```bash theme={null}
curl -X POST https://verification.didit.me/v3/document-ai/ \
  -H "x-api-key: $DIDIT_API_KEY" \
  -F "document=@./bank-statement.pdf" \
  -F 'fields=[{"key":"account_holder","name":"Account holder","instruction":"Full name of the account holder","type":"text","required":true,"is_full_name":true},{"key":"balance","name":"Closing balance","instruction":"Closing balance as a number","type":"number","required":true}]' \
  -F "expected_first_name=Jane" \
  -F "expected_last_name=Doe"
```

响应会回显规范化后的 `fields`，并返回以您的 `key` 值为键的 `extracted_data`，模型未找到的内容返回 `null`。每一项中的 `name`、`instruction` 和 `type` 都是可选的（`type` 默认为 `text`）；`key` 为必填。若将 `fields` 作为方括号形式的表单键（`fields[0][key]=...`）发送，或发送的不是 JSON 数组，将在任何提取运行之前返回 `400`，因此不会产生计费。

## QR 码与条形码

每个成功的响应都包含 `document_ai.detected_codes`。每一项包含以下内容：

| 字段 | 说明 |
| - | - |
| `type` | 检测到的码制，例如 `QR_CODE`、`CODE_128`、`EAN_13`、`DATA_MATRIX` 或 `PDF_417` |
| `page_number` | 从 1 开始的页码 |
| `position` | 以渲染页面像素表示的检测多边形，无法可靠定位时为 `null` |
| `x`、`y`、`width`、`height` | 以渲染页面像素表示的边界框，无法可靠定位时为 `null` |
| `page_width`、`page_height` | 坐标所使用的渲染页面尺寸 |
| `parsed_payload` | 解码后的字符串或结构化值，码仅能定位时为 `null` |
| `raw_payload` | 以 base64 字符串表示的原始解码器 payload（如有）；否则为空字符串 |

对于 PDF，该数组涵盖每个已处理页面；未找到受支持的码时为空数组。Didit 从不猜测 payload 内容：损坏的 QR 码可能会返回其位置以及 `parsed_payload: null`，而码检测失败不会导致 Document AI 请求失败。

## 姓名匹配

最多在一个字段上标记 `is_full_name: true`，并传入您预期该证件所属的对象：

| 您要验证的对象 | 传入 | 姓名比对对象 |
| - | - | - |
| 个人 | `expected_first_name` + `expected_last_name` | 该个人的全名 |
| 企业 | `expected_company_name`（+ 可选的 `expected_company_country`，为 2 位 ISO 代码） | 企业名称 |

两组参数只传一组，不要同时传入。当提取到姓名且存在预期姓名时，响应会包含 `name_match_score`（0 到 100）和 `name_on_document`。低于 `document_ai_name_match_score_threshold`（默认 `80`）的分数会触发 `DOCUMENT_AI_NAME_MISMATCH` 警告，并执行 `document_ai_name_mismatch_action`。若没有字段标记 `is_full_name`，Didit 会回退到第一个键名类似姓名（`name`、`holder`、`full_name`、`account_holder`）的文本字段。如果您希望控制比对哪个值，请显式标记该字段。当证件上找不到任何姓名值，或未传入预期姓名时，将跳过姓名检查，`name_match_score` 为 `null`。

## 风险与操作

下表中的每个风险都对应一个可按请求设置的操作参数：`DECLINE`、`REVIEW` 或 `NO_ACTION`。触发的最严格操作决定 `document_ai.status`（`Declined` > `In Review` > `Approved`），所有被触发的风险都会列在 `document_ai.warnings` 中。默认值与托管工作流步骤一致。关于每种风险的检测方式，请参阅 [Document AI 规则与警告](https://docs.didit.me/zh/core-technology/document-ai/warnings-document-ai.md)。

| 风险 | 参数 | 默认值 |
| - | - | - |
| `DOCUMENT_AI_UNREADABLE_DOCUMENT` | `document_ai_unreadable_document_action` | `REVIEW` |
| `DOCUMENT_AI_MISSING_REQUIRED_FIELDS` | `document_ai_missing_required_fields_action` | `REVIEW` |
| `DOCUMENT_AI_SUSPECTED_MANIPULATION` | `document_ai_document_tampering_action` | `DECLINE` |
| `DOCUMENT_AI_NAME_MISMATCH` | `document_ai_name_mismatch_action` | `NO_ACTION` |
| `DOCUMENT_AI_UNSUPPORTED_FILE` | `document_ai_unsupported_file_action` | `REVIEW` |

## 文件、保存与计费

* **可接受的文件：** PDF（支持多页）、JPG、JPEG、PNG、TIFF、WebP，或包含证件的 ZIP 文件，大小上限为 30 MB。加密的 PDF 将返回 `400`；请上传已解密的 PDF 或照片。
* **`save_api_request`**（默认 `true`）：请求、提取的字段和检测到的码会显示在 Business Console 的 **人工审核** 下，供您的团队复核。设置为 `false` 可跳过保存。
* **`vendor_data`** 和 **`metadata`** 会在响应中原样返回，便于您将结果与自己的记录关联。
* **价格：** 每份证件 \$0.20，在证件被处理并返回状态时计费。您的套餐折扣同样适用。请参阅 [定价](https://docs.didit.me/zh/getting-started/pricing.md#服务器间独立-api-定价)。

> [!NOTE]
>
> 需要由用户自行上传证件、在一个流程中收集最多 3 份证件、自动翻译上传界面，或将提取的字段与身份证件或问卷数据进行交叉比对？请改用托管的 [Document AI 工作流步骤](https://docs.didit.me/zh/core-technology/document-ai/overview.md)。


## OpenAPI

````yaml zh/openapi-25.json POST /v3/document-ai/
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/document-ai/:
    post:
      tags:
        - Standalone APIs
      summary: Document AI（自定义字段提取 + 防篡改检查）
      description: >-
        只需一次调用，即可从任何证明文件（工资单、资金证明、财富来源信函、税单、合同、发票）中提取**您**定义的字段。发送文件以及 `fields`
        定义（键、名称、提取指令、类型），即可返回类型化值（`text`、`number`、以 `YYYY-MM-DD` 格式呈现的
        `date`）、与预期个人或公司比对的可选的姓名匹配分数、PDF/EXIF 篡改信号、`Approved`/`Declined`/`In
        Review` `status`，以及说明所发现全部问题的 `warnings` 列表。这是托管 Document AI 工作流步骤（参见
        `/core-technology/document-ai/overview`）的服务端对服务端对应功能；它使用 Didit
        的默认提取模型，且不提供供应商选择。


        **延迟。** 提取基于 LLM：典型调用耗时 **5–15 秒**，多页 PDF 最长可达 **约 30 秒**。请配置**至少 45
        秒**的客户端超时，且在调用完成前不要重试。


        **请求格式。** 仅限 `multipart/form-data`。`fields` 为**一个经过 JSON 编码的数组字符串**（1–30
        项，最多 16 KB）；括号风格的表单数组将被拒绝并返回 `400`。每项均为 `{key, name, instruction, type,
        required, is_full_name}`，其中 `key` 是返回的 JSON
        键（`^[a-z0-9_]{1,64}$`，唯一），`instruction` 指示模型读取什么内容，`type` 为 `text`（默认）|
        `number` | `date`，当无法读取值时 `required` 会引发
        `DOCUMENT_AI_MISSING_REQUIRED_FIELDS`，且最多只能有一个字段设置 `is_full_name: true`
        以标记与预期姓名进行比对的值。


        **姓名匹配。** 传入 `expected_first_name` + `expected_last_name`（个人）**或**
        `expected_company_name`（+ 可选的 `expected_company_country`），两者不可同时传入。标记了
        `is_full_name` 的字段的值（或者在未标记任何字段时，键名看起来像姓名的第一个文本字段）将进行模糊比对；当双方均存在时，始终返回
        `name_match_score`（0–100）和 `name_on_document`，低于
        `document_ai_name_match_score_threshold`（默认 80）的分数会添加
        `DOCUMENT_AI_NAME_MISMATCH`，受 `document_ai_name_mismatch_action` 控制。


        **决策逻辑。** 每种风险对应一个可配置的操作：`DECLINE` → `status: "Declined"`，`REVIEW` →
        `status: "In Review"`，`NO_ACTION` → 仅供参考。默认值与工作流步骤一致：无法读取的证件
        `REVIEW`、缺失必填字段 `REVIEW`、疑似篡改 `DECLINE`、姓名不匹配 `NO_ACTION`、不支持的文件
        `REVIEW`。完全无法处理的证件返回 `400`；可读但存在问题的证件返回带有 `Declined`/`In Review` 的
        `200`，请务必检查 `document_ai.status` 和 `document_ai.warnings`，而不仅仅是 HTTP
        状态码。


        **计费。** 每个 `200` 响应消耗一个 Document AI API 额度，标价为**每份证件
        $0.20**，从您的套餐额度或充值余额中扣除。当组织的余额无法支付调用时，endpoint 在进行任何处理之前返回 `403`。沙盒 API
        密钥返回确定性的模拟响应且不计费。


        **持久化。** 在 `save_api_request=true`（默认）时，调用将作为 API
        类型的会话存储：证件、提取的值、字段定义和姓名匹配快照均予以保留，会话显示在 Business Console 中，并且
        `request_id` 可用于 `GET /v3/session/{sessionId}/decision/`。
      operationId: post_v3document-ai
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - document
                - fields
              properties:
                document:
                  type: string
                  format: binary
                  description: >-
                    要读取的证件。允许的扩展名：`tiff`、`jpg`、`jpeg`、`png`、`pdf`、`webp`、`zip`。最大上传大小：**30
                    MB**（超出限制的文件将被拒绝并返回 `400`）。支持多页 PDF（延迟可能会更高）；加密的 PDF 将被拒绝并返回
                    `400`。图像在处理前会自动压缩。
                fields:
                  type: string
                  description: >-
                    包含 **1–30** 个字段定义的单个 JSON 编码数组字符串（最大 16
                    KB）。每个项目：`key`（必填，`^[a-z0-9_]{1,64}$`，唯一：在 `extracted_data`
                    中返回的键）、`name`（≤100 个字符，在消息中显示）、`instruction`（≤500
                    个字符，模型应读取的内容）、`type`（默认 `text` | `number` |
                    `date`）、`required`（布尔值，默认 `false`）、`is_full_name`（布尔值，默认
                    `false`，每个请求最多一个）。括号风格的表单数组、无效 JSON、重复键或多个 `is_full_name`
                    将在任何处理或计费之前返回 `400`。
                  example: >-
                    [{"key": "employer_name", "name": "Employer name",
                    "instruction": "The employer or company issuing the
                    payslip.", "type": "text", "required": true, "is_full_name":
                    false}, {"key": "employee_name", "name": "Employee name",
                    "instruction": "The full name of the employee as printed on
                    the payslip.", "type": "text", "required": true,
                    "is_full_name": true}, {"key": "net_pay", "name": "Net pay",
                    "instruction": "The net amount paid to the employee for the
                    period.", "type": "number", "required": true,
                    "is_full_name": false}, {"key": "pay_date", "name": "Pay
                    date", "instruction": "The payment date shown on the
                    payslip.", "type": "date", "required": false,
                    "is_full_name": false}]
                expected_first_name:
                  type: string
                  description: >-
                    用于与证件的姓名字段进行核验的名（支持音译的模糊匹配）。与 `expected_last_name` 一起使用；不能与
                    `expected_company_name` 组合。
                  example: Sophia
                expected_last_name:
                  type: string
                  description: >-
                    用于与证件的姓名字段比对的姓氏，与 `expected_first_name` 结合以计算
                    `name_match_score`。
                  example: Martinez
                expected_company_name:
                  type: string
                  description: >-
                    要与证件上的名称字段进行核验的企业名称（适用于企业证件）。不能与 `expected_first_name` /
                    `expected_last_name`
                    同时使用（特意未提供示例值，生成的请求示例使用个人字段；核验企业证件时请将其替换为本字段）。
                expected_company_country:
                  type: string
                  description: >-
                    可选的 ISO 3166-1 alpha-2 国家/地区代码（两个 ASCII 字母，例如 `FR`），用于针对
                    `expected_company_name` 调整公司名称规范化。仅与 `expected_company_name`
                    一同使用。
                document_ai_name_match_score_threshold:
                  type: integer
                  minimum: 0
                  maximum: 100
                  default: 80
                  description: >-
                    认定姓名匹配的最低 `name_match_score`（0–100）。低于此分值将添加
                    `DOCUMENT_AI_NAME_MISMATCH`，受
                    `document_ai_name_mismatch_action` 控制。
                  example: 80
                document_ai_unreadable_document_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: 当无法从证件中读取任何字段时的处理操作（`DOCUMENT_AI_UNREADABLE_DOCUMENT`）。
                document_ai_missing_required_fields_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    当至少有一个 `required`
                    字段无法读取时的处理操作（`DOCUMENT_AI_MISSING_REQUIRED_FIELDS`；`additional_data.missing_fields`
                    列出了这些字段）。
                document_ai_document_tampering_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: DECLINE
                  description: >-
                    当 PDF/EXIF 取证怀疑存在篡改（数字签名后被修改、已知的 PDF
                    编辑器、覆盖文本篡改、可疑的重新导出、图像异常）时的处理操作（`DOCUMENT_AI_SUSPECTED_MANIPULATION`）。
                document_ai_name_mismatch_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: NO_ACTION
                  description: >-
                    当 `name_match_score`
                    低于阈值时的处理操作（`DOCUMENT_AI_NAME_MISMATCH`）。
                document_ai_unsupported_file_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: 当上传内容为空或不是可处理的文件（`DOCUMENT_AI_UNSUPPORTED_FILE`）时采取的操作。
                save_api_request:
                  type: boolean
                  default: true
                  description: >-
                    为 `true`（默认）时，将此次调用持久化为 API 类型的会话，在 Business Console
                    中可见，可使用返回的 `request_id` 通过 `GET
                    /v3/session/{sessionId}/decision/`
                    检索，并存储上传的证件、提取的值、字段定义以及姓名比对快照。为 `false`
                    时，不存储任何内容，`request_id` 仅为用于关联响应的临时 UUID；该调用仍会计费。
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    可选的不透明字符串（您的内部用户 ID、邮箱、UUID 等），存储在持久化会话中并在响应中回显。可用于将 API
                    调用与您自己的记录相关联，并在稍后筛选会话。
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    与会话一同存储（当 `save_api_request=true` 时）并在响应中原样返回的可选 JSON 对象。在
                    multipart 请求中，请将其作为 JSON 编码的字符串字段发送（例如
                    `metadata={"flow":"onboarding"}`），它将被解析为对象。
                  example:
                    flow: onboarding
      responses:
        '200':
          description: >-
            证件已处理。`document_ai.status` 为 `Approved`、`Declined` 或 `In
            Review`；检测到的每个问题都在 `document_ai.warnings` 中逐项列出。有问题的证件仍会返回 `200` —
            请检查响应体，而不仅仅是 HTTP 状态码。当 `save_api_request=true` 时，`request_id`
            为持久化的会话 ID。
          content:
            application/json:
              examples:
                Approved:
                  summary: 工资单读取无误，姓名已匹配
                  value:
                    request_id: 9d6a3b1e-2f0c-4a8e-9b7d-1c2e3f4a5b6c
                    document_ai:
                      status: Approved
                      extracted_data:
                        employer_name: Acme Payments Ltd
                        employee_name: Sophia Martinez
                        net_pay: 3120.5
                        pay_date: '2026-07-31'
                      detected_codes:
                        - type: CODE_128
                          page_number: 1
                          position:
                            - - 96
                              - 456
                            - - 96
                              - 616
                            - - 1012
                              - 611
                            - - 1015
                              - 456
                          x: 96
                          'y': 456
                          width: 919
                          height: 160
                          page_width: 1200
                          page_height: 1700
                          raw_payload: SU5WLTIwMjYtMDA0Mg==
                          parsed_payload: INV-2026-0042
                      fields:
                        - key: employer_name
                          name: Employer name
                          instruction: The employer or company issuing the payslip.
                          type: text
                          required: true
                          is_full_name: false
                        - key: employee_name
                          name: Employee name
                          instruction: >-
                            The full name of the employee as printed on the
                            payslip.
                          type: text
                          required: true
                          is_full_name: true
                        - key: net_pay
                          name: Net pay
                          instruction: The net amount paid to the employee for the period.
                          type: number
                          required: true
                          is_full_name: false
                        - key: pay_date
                          name: Pay date
                          instruction: The payment date shown on the payslip.
                          type: date
                          required: false
                          is_full_name: false
                      name_match_score: 100
                      name_on_document: Sophia Martinez
                      warnings: []
                    vendor_data: user-123
                    metadata:
                      flow: onboarding
                    created_at: '2026-08-19T16:40:12.318Z'
                In Review — missing required field:
                  summary: 无法读取 `net_pay`；默认操作为 REVIEW
                  value:
                    request_id: 3f2a9c7b-5d4e-4b1a-8c6f-0e9d8c7b6a5f
                    document_ai:
                      status: In Review
                      extracted_data:
                        employer_name: Acme Payments Ltd
                        employee_name: Sophia Martinez
                        net_pay: null
                        pay_date: '2026-07-31'
                      detected_codes: []
                      fields:
                        - key: employer_name
                          name: Employer name
                          instruction: The employer or company issuing the payslip.
                          type: text
                          required: true
                          is_full_name: false
                        - key: employee_name
                          name: Employee name
                          instruction: >-
                            The full name of the employee as printed on the
                            payslip.
                          type: text
                          required: true
                          is_full_name: true
                        - key: net_pay
                          name: Net pay
                          instruction: The net amount paid to the employee for the period.
                          type: number
                          required: true
                          is_full_name: false
                        - key: pay_date
                          name: Pay date
                          instruction: The payment date shown on the payslip.
                          type: date
                          required: false
                          is_full_name: false
                      name_match_score: 100
                      name_on_document: Sophia Martinez
                      warnings:
                        - risk: DOCUMENT_AI_MISSING_REQUIRED_FIELDS
                          feature: DOCUMENT_AI
                          additional_data:
                            missing_fields:
                              - Net pay
                          log_type: warning
                          short_description: Required fields could not be extracted
                          long_description: >-
                            One or more fields configured as required could not
                            be extracted from the uploaded document.
                    vendor_data: null
                    metadata: null
                    created_at: '2026-08-19T16:41:05.002Z'
                Declined — suspected manipulation:
                  summary: PDF 取证标记了已知的编辑器；默认操作 DECLINE
                  value:
                    request_id: 7c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f
                    document_ai:
                      status: Declined
                      extracted_data:
                        employer_name: Acme Payments Ltd
                        employee_name: Sophia Martinez
                        net_pay: 3120.5
                        pay_date: '2026-07-31'
                      detected_codes: []
                      fields:
                        - key: employer_name
                          name: Employer name
                          instruction: The employer or company issuing the payslip.
                          type: text
                          required: true
                          is_full_name: false
                        - key: employee_name
                          name: Employee name
                          instruction: >-
                            The full name of the employee as printed on the
                            payslip.
                          type: text
                          required: true
                          is_full_name: true
                        - key: net_pay
                          name: Net pay
                          instruction: The net amount paid to the employee for the period.
                          type: number
                          required: true
                          is_full_name: false
                        - key: pay_date
                          name: Pay date
                          instruction: The payment date shown on the payslip.
                          type: date
                          required: false
                          is_full_name: false
                      name_match_score: null
                      name_on_document: Sophia Martinez
                      warnings:
                        - risk: DOCUMENT_AI_SUSPECTED_MANIPULATION
                          feature: DOCUMENT_AI
                          additional_data:
                            detection_method: known_editor
                            processed_by_known_editor: ilovepdf
                          log_type: error
                          short_description: Suspected document manipulation
                          long_description: >-
                            The system detected signs of potential manipulation
                            or editing in the uploaded document.
                    vendor_data: null
                    metadata: null
                    created_at: '2026-08-19T16:42:40.771Z'
              schema:
                type: object
                properties:
                  request_id:
                    type: string
                    format: uuid
                    description: >-
                      当 `save_api_request=true` 时持久化的会话 ID（可用于 `GET
                      /v3/session/{sessionId}/decision/`）；否则为一个临时的关联 UUID。
                  document_ai:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                          - In Review
                        description: >-
                          没有警告判定为拒绝或审核时为 `Approved`；至少有一个风险映射到 `DECLINE` 时为
                          `Declined`；否则当至少有一个映射到 `REVIEW` 时为 `In
                          Review`。`warnings` 列表说明了具体原因。
                      extracted_data:
                        type: object
                        additionalProperties: true
                        description: >-
                          每个请求的字段键对应一个条目。值根据字段 `type` 确定类型（`text` 为字符串，`number`
                          为数字，`date` 为 `YYYY-MM-DD` 格式的字符串），当无法读取值时为 `null`。
                        example:
                          employer_name: Acme Payments Ltd
                          employee_name: Sophia Martinez
                          net_pay: 3120.5
                          pay_date: '2026-07-31'
                      detected_codes:
                        type: array
                        description: >-
                          在所有已处理页面中检测到的二维码和条形码。未找到时为空。已定位但无法解码的二维码其
                          `parsed_payload: null`。
                        items:
                          $ref: '#/components/schemas/DocumentAIDetectedCode'
                      fields:
                        type: array
                        description: >-
                          本次提取所使用的标准化字段定义，原样返回（当 `save_api_request=true`
                          时也会随会话一同存储）。
                        items:
                          type: object
                          properties:
                            key:
                              type: string
                            name:
                              type: string
                            instruction:
                              type: string
                            type:
                              type: string
                              enum:
                                - text
                                - number
                                - date
                            required:
                              type: boolean
                            is_full_name:
                              type: boolean
                      name_match_score:
                        type: number
                        nullable: true
                        minimum: 0
                        maximum: 100
                        description: >-
                          `name_on_document`
                          与预期的个人/企业名称之间的模糊相似度（0–100）。只要名称值与预期名称均存在即会返回，无论匹配**还是**不匹配；否则为
                          `null`。
                        example: 96
                      name_on_document:
                        type: string
                        nullable: true
                        description: >-
                          从证件中提取并与预期姓名进行比对的姓名值（`is_full_name`
                          字段，或首个类似姓名的文本字段）。无可用的姓名值时为 `null`。
                        example: Sophia Martinez
                      warnings:
                        type: array
                        description: >-
                          完全通过审核时为空。每个条目说明一项检测到的风险；包含 `log_type: "error"` 的条目会将
                          `status` 设置为 `Declined`，包含 `log_type: "warning"`
                          的条目会将其设置为 `In Review`。
                        items:
                          type: object
                          properties:
                            risk:
                              type: string
                              enum:
                                - DOCUMENT_AI_UNREADABLE_DOCUMENT
                                - DOCUMENT_AI_MISSING_REQUIRED_FIELDS
                                - DOCUMENT_AI_SUSPECTED_MANIPULATION
                                - DOCUMENT_AI_NAME_MISMATCH
                                - DOCUMENT_AI_UNSUPPORTED_FILE
                              description: >-
                                机器可读的风险代码。每一项均由匹配的 `document_ai_*_action`
                                请求选项控制。
                              example: DOCUMENT_AI_MISSING_REQUIRED_FIELDS
                            feature:
                              type: string
                              enum:
                                - DOCUMENT_AI
                              description: 引发该警告的功能。在此 endpoint 上始终为 `DOCUMENT_AI`。
                            additional_data:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: >-
                                风险的额外上下文：缺少必填字段时为 `{"missing_fields": ["Net
                                pay"]}`，姓名不匹配时为 `{"name_on_document", "score",
                                "threshold"}`，涉嫌篡改时为鉴伪检测结果（`detection_method`、制作软件/编辑者详情）。无可补充内容时为
                                `null`。
                              example:
                                missing_fields:
                                  - Net pay
                            log_type:
                              type: string
                              enum:
                                - error
                                - warning
                                - information
                              description: >-
                                根据配置的操作派生的严重程度：`error`（DECLINE）、`warning`（REVIEW）、`information`（NO_ACTION）。
                            short_description:
                              type: string
                              description: 易于阅读的单行风险概述。
                              example: Required fields could not be extracted
                            long_description:
                              type: string
                              description: 便于人类阅读的说明，在相关位置插入 `additional_data`。
                  vendor_data:
                    type: string
                    nullable: true
                    description: 您发送的 `vendor_data` 回显，或 `null`。
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: 您发送的 `metadata` 对象回显，或 `null`。
                  created_at:
                    type: string
                    format: date-time
                    description: 请求处理的时间（UTC，ISO 8601）。
        '400':
          description: >-
            验证或处理错误。字段级问题返回 DRF 的标准外层结构（每个出错字段对应一个消息数组）。加密或无法读取的证件以及提取失败返回
            `{"error": ...}`。
          content:
            application/json:
              examples:
                Missing document:
                  summary: 表单数据中未包含 `document`
                  value:
                    document:
                      - No file was submitted.
                Invalid fields payload:
                  summary: '`fields` 不是一个 JSON 编码的数组字符串'
                  value:
                    fields:
                      - fields must be a valid JSON array string.
                Duplicate field keys:
                  summary: 两个项目共享相同的 `key`
                  value:
                    fields:
                      - Every fields item must have a unique key.
                Conflicting expectations:
                  summary: 个人与企业预期信息一同发送
                  value:
                    non_field_errors:
                      - >-
                        Provide either person expected-name fields or
                        expected_company_name, not both.
                Invalid metadata:
                  summary: '`metadata` 不是 JSON 对象（或包含 NUL 字符）'
                  value:
                    metadata:
                      - Metadata must be a JSON object.
                Oversized vendor_data:
                  summary: '`vendor_data` 超过 2,000 字节上限'
                  value:
                    vendor_data:
                      - vendor_data is too long (maximum 2000 bytes).
                Encrypted PDF:
                  summary: 受密码保护的 PDF
                  value:
                    error: >-
                      The PDF is encrypted. Please upload a decrypted PDF or a
                      photo instead.
                Extraction failed:
                  summary: 提取流水线无法处理该证件
                  value:
                    error:
                      - Error extracting Document AI information
              schema:
                type: object
                additionalProperties: true
        '403':
          description: >-
            权限被拒绝。当缺少 `x-api-key` 请求头或调用组织的余额无法覆盖此次调用时返回；错误、已撤销或已过期的密钥返回
            `401`。缺少密钥时返回 `403` 及 `{"detail": ...}`；错误、已撤销或已过期的密钥返回
            `401`。额度不足，以及费率表中未包含 Document AI API 条目的合同计费组织，均会在进行任何证件处理之前返回 `403`
            及 `{"error": ...}`。
          content:
            application/json:
              examples:
                Missing or invalid API key:
                  summary: 缺少 `x-api-key` 请求头，或者密钥无效/已被吊销
                  value:
                    detail: You do not have permission to perform this action.
                Not enough credits:
                  summary: 组织余额不足以支付本次调用
                  value:
                    error: >-
                      You don't have enough credits to perform this request.
                      Please top up at https://business.didit.me
                Contract rate missing:
                  summary: 按合同计费的组织，其费率表中没有 Document AI API 条目
                  value:
                    error: >-
                      Document AI API is not included in your contract rate
                      card. Contact support@didit.me to enable it.
              schema:
                type: object
                properties:
                  detail:
                    type: string
                  error:
                    type: string
        '429':
          description: >-
            超出速率限制。POST/PATCH/DELETE endpoint 每个 API 密钥每分钟共享 300
            次写入请求的额度（交易创建和事件摄入具有单独的 600 次额度）。响应包含
            `X-RateLimit-Limit`、`X-RateLimit-Remaining`、`X-RateLimit-Reset` 和
            `Retry-After` 响应头。
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: 当前分钟内的写入请求超过 300 次
                  value:
                    detail: >-
                      Write request rate limit exceeded. You can make up to 300
                      requests per minute.
              schema:
                type: object
                properties:
                  detail:
                    type: string
        '503':
          $ref: '#/components/responses/DocumentProcessingBusy'
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.document_ai.analyze(
                document=open("document.pdf", "rb"),
                fields="[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]",
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit, { fileFromPath } from "@didit-protocol/sdk-node";

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

            const result = await didit.documentAi.analyze({
              document: await fileFromPath("document.pdf"),
              fields: "[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]",
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.DocumentAi.Analyze(ctx, didit.DocumentAiAnalyzeParams{\n\tDocument: didit.FileFromPath(\"document.pdf\"),\n\tFields:   \"[{\\\"key\\\": \\\"employer_name\\\", \\\"name\\\": \\\"Employer name\\\", \\\"instruction\\\": \\\"The employer or company issuing the payslip.\\\", \\\"type\\\": \\\"text\\\", \\\"required\\\": true, \\\"is_full_name\\\": false}, {\\\"key\\\": \\\"employee_name\\\", \\\"name\\\": \\\"Employee name\\\", \\\"instruction\\\": \\\"The full name of the employee as printed on the payslip.\\\", \\\"type\\\": \\\"text\\\", \\\"required\\\": true, \\\"is_full_name\\\": true}, {\\\"key\\\": \\\"net_pay\\\", \\\"name\\\": \\\"Net pay\\\", \\\"instruction\\\": \\\"The net amount paid to the employee for the period.\\\", \\\"type\\\": \\\"number\\\", \\\"required\\\": true, \\\"is_full_name\\\": false}, {\\\"key\\\": \\\"pay_date\\\", \\\"name\\\": \\\"Pay date\\\", \\\"instruction\\\": \\\"The payment date shown on the payslip.\\\", \\\"type\\\": \\\"date\\\", \\\"required\\\": false, \\\"is_full_name\\\": false}]\",\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.nio.file.Path;

            import me.didit.Didit;

            import me.didit.types.DocumentAiAnalyzeParams;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.documentAi().analyze(DocumentAiAnalyzeParams.builder()
                    .document(Path.of("document.pdf"))
                    .fields("[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]")
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;
            use Didit\File;

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

            $result = $didit->documentAi->analyze([
                'document' => File::fromPath('document.pdf'),
                'fields' => '[{"key": "employer_name", "name": "Employer name", "instruction": "The employer or company issuing the payslip.", "type": "text", "required": true, "is_full_name": false}, {"key": "employee_name", "name": "Employee name", "instruction": "The full name of the employee as printed on the payslip.", "type": "text", "required": true, "is_full_name": true}, {"key": "net_pay", "name": "Net pay", "instruction": "The net amount paid to the employee for the period.", "type": "number", "required": true, "is_full_name": false}, {"key": "pay_date", "name": "Pay date", "instruction": "The payment date shown on the payslip.", "type": "date", "required": false, "is_full_name": false}]',
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

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

            result = didit.document_ai.analyze(
              document: Pathname("document.pdf"),
              fields: "[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]"
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await client.DocumentAi.AnalyzeAsync(new
            DocumentAiAnalyzeParams

            {
                Document = FileUpload.FromPath("document.pdf"),
                Fields = "[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]",
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    DocumentAIDetectedCode:
      type: object
      required:
        - type
        - page_number
        - position
        - x
        - 'y'
        - width
        - height
        - page_width
        - page_height
        - raw_payload
        - parsed_payload
      properties:
        type:
          type: string
          description: 检测到的符号系统，例如 `QR_CODE`、`CODE_128`、`EAN_13`、`DATA_MATRIX` 或 `PDF_417`。
        page_number:
          type: integer
          minimum: 1
          description: 从 1 开始的页码。
        position:
          type: array
          nullable: true
          description: 在渲染页面的像素坐标中检测到的多边形。当没有可靠的位置可用时为 `null`。
          items:
            type: array
            minItems: 2
            maxItems: 2
            items:
              type: integer
        x:
          type: integer
          nullable: true
          description: 边界框的左边缘（以渲染页面的像素为单位）。
        'y':
          type: integer
          nullable: true
          description: 边界框的顶部边缘（以渲染页面像素为单位）。
        width:
          type: integer
          nullable: true
          description: 渲染页面像素中的边界框宽度。
        height:
          type: integer
          nullable: true
          description: 渲染页面像素中的边界框高度。
        page_width:
          type: integer
          description: 渲染页面的宽度（以像素为单位）。
        page_height:
          type: integer
          description: 渲染页面的高度（以像素为单位）。
        raw_payload:
          type: string
          description: 原始解码器 payload（base64 字符串形式，如可用）；否则为空字符串。
        parsed_payload:
          nullable: true
          description: 解码后的字符串或结构化值。当定位到代码但无法解码时为 `null`。
  responses:
    DocumentProcessingBusy:
      description: >-
        当前正在处理的证件过多，因此本次上传未被处理：未存储任何内容，且未消耗尝试次数。请在 `Retry-After`
        指定的秒数后再次发送相同文件。请根据 `code` 进行分支判断，而非根据消息文本。
      headers:
        Retry-After:
          description: 再次发送相同请求前需等待的秒数。
          schema:
            type: integer
            example: 10
      content:
        application/json:
          schema:
            type: object
            required:
              - detail
              - code
            properties:
              detail:
                type: string
              code:
                type: string
                enum:
                  - document_processing_busy
          example:
            detail: We are busy processing documents. Please try again in a moment.
            code: document_processing_busy
  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.