> ## 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 Document AI API: извлечение заданных полей из любого PDF или изображения, сравнение имён и проверка подделок. $0.20 за документ.

Отправьте один документ и список полей, которые нужно из него извлечь. Didit запускает модель извлечения данных по умолчанию для файла, возвращает все поля с типами (`text`, `number` или `date` в формате `YYYY-MM-DD`), обнаруживает и декодирует поддерживаемые QR-коды и штрихкоды, проверяет файл на наличие манипуляций и, при необходимости, сравнивает имя в документе с ожидаемым физическим лицом или компанией. Используйте его для подтверждения наличия средств, расчётных листков, банковских выписок, налоговых документов, счетов-фактур или любого документа, который не соответствует фиксированному шаблону.

Это серверная версия шага [Document AI](https://docs.didit.me/ru/core-technology/document-ai/overview.md) из размещённого сценария. Запрос имеет тип `multipart/form-data`: файл передаётся в поле `document`, а описания полей передаются в поле `fields` в виде одной строки с JSON-массивом.

## Определение полей для извлечения

Параметр `fields` представляет собой JSON-массив из 1–30 элементов, передаваемый одной строкой. Каждый элемент содержит `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`, а `extracted_data` содержит ключи, соответствующие вашим значениям `key`. Если модель не смогла найти значение, оно равно `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` | Необработанный payload декодера в виде строки base64, если он доступен; в противном случае пустая строка |

Массив охватывает все обработанные страницы PDF и пуст, если поддерживаемый код не найден. Didit никогда не угадывает содержимое кода: повреждённые QR-коды могут возвращаться с расположением и `parsed_payload: null`, а сбои при обнаружении кодов не приводят к ошибке запроса Document AI.

## Сопоставление имён

Укажите не более одного поля с `is_full_name: true` и передайте данные о том, кому, по вашим ожиданиям, принадлежит документ:

| Вы проверяете | Передайте | Имя сравнивается с |
| - | - | - |
| Физическое лицо | `expected_first_name` + `expected_last_name` | полным именем физического лица |
| Компанию | `expected_company_name` (+ необязательный `expected_company_country`, двухбуквенный код 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/ru/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 МБ. Зашифрованные PDF возвращают `400`; загрузите расшифрованный PDF или фотографию.
* **`save_api_request`** (по умолчанию `true`): запрос, извлечённые поля и обнаруженные коды отображаются в Business Console в разделе **Manual Checks**, где ваша команда может их просмотреть. Установите `false`, чтобы не сохранять данные.
* **`vendor_data`** и **`metadata`** возвращаются в ответе без изменений, чтобы вы могли связать результат со своими записями.
* **Цена:** \$0.20 за документ; списывается, когда документ обработан и возвращён статус. Скидка по вашему тарифу применяется. См. [Цены](https://docs.didit.me/ru/getting-started/pricing.md#цены-отдельных-api-сервер-серверные-интеграции).

> [!NOTE]
>
> Нужно, чтобы пользователь загрузил документ сам, собрать до 3 документов в одном потоке, автоматически перевести экран загрузки или сопоставить извлечённые поля с данными удостоверения личности или анкеты? Используйте вместо этого размещённый [шаг сценария Document AI](https://docs.didit.me/ru/core-technology/document-ai/overview.md).


## OpenAPI

````yaml ru/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`, `date` в формате `YYYY-MM-DD`), опциональную оценку
        совпадения имени с ожидаемым физлицом или компанией, сигналы о
        модификации PDF/EXIF, `status` со значением `Approved`/`Declined`/`In
        Review`, а также список `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`;
        читаемый, но проблемный документ возвращает `200` с `Declined`/`In
        Review`, поэтому всегда проверяйте `document_ai.status` и
        `document_ai.warnings`, а не только HTTP-код.


        **Биллинг.** Каждый ответ `200` расходует один кредит Document AI API
        (**$0.20 per document** по тарифной сетке), списание производится из
        кредитов тарифа или баланса пополнения. Если баланса организации
        недостаточно для покрытия вызова, 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: >-
                    Одна закодированная в JSON строка массива с **1–30**
                    определениями полей (максимум 16 КБ). Каждый элемент: `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, доступную через `GET
                    /v3/session/{sessionId}/decision/` по возвращенному
                    `request_id`, с сохранением загруженного документа,
                    извлеченных значений, определений полей и снимка
                    сопоставления имен. Если `false`, ничего не сохраняется, а
                    `request_id` является временным UUID только для
                    сопоставления ответа; вызов по-прежнему тарифицируется.
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    Необязательная непрозрачная строка (ваш внутренний
                    идентификатор пользователя, email, UUID…), сохраняемая в
                    сессии и возвращаемая в ответе. Используйте её для
                    сопоставления вызовов API с вашими собственными записями и
                    для последующей фильтрации сессий.
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Необязательный объект JSON, сохраняемый вместе с сессией
                    (когда `save_api_request=true`) и возвращаемый обратно в
                    ответе. В 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` (доступен для использования с `GET
                      /v3/session/{sessionId}/decision/`); в противном случае
                      это временный корреляционный UUID.
                  document_ai:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                          - In Review
                        description: >-
                          `Approved`, если ни одно предупреждение не приводит к
                          отклонению или рассмотрению; `Declined`, если хотя бы
                          один риск сопоставляется с `DECLINE`; в противном
                          случае `In Review`, если хотя бы один сопоставляется с
                          `REVIEW`. Список `warnings` поясняет причину.
                      extracted_data:
                        type: object
                        additionalProperties: true
                        description: >-
                          Одна запись на каждый запрошенный ключ поля. Значения
                          типизированы в соответствии с `type` поля: строки для
                          `text`, числа для `number`, строки в формате
                          `YYYY-MM-DD` для `date` — или `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: >-
                          QR-коды и штрихкоды, обнаруженные на всех обработанных
                          страницах. Пусто, если ничего не найдено. Для
                          обнаруженного, но не поддающегося декодированию
                          QR-кода возвращается `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: >-
                          Нечёткое сходство (0–100) между `name_on_document` и
                          ожидаемым именем человека или наименованием компании.
                          Возвращается каждый раз, когда присутствуют как
                          значение имени, так и ожидаемое имя — при совпадениях
                          **и** несовпадениях; в противном случае `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: >-
            Превышен лимит запросов. Endpoint'ы POST/PATCH/DELETE делят общий
            лимит в 300 запросов на запись в минуту на один API-ключ (для
            создания транзакций и отправки событий действует отдельный лимит в
            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-ключ вашего приложения из раздела «Разработчикам» -> «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.