> ## 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: extração de dados de documentos

> POST /v3/document-ai/ da Didit extrai campos que você define de PDFs ou imagens, com checagem de nome e adulteração. $0.20 por documento.

Envie um documento e a lista de campos que você quer ler nele. A Didit executa seu modelo de extração padrão sobre o arquivo, retorna cada campo com tipo (`text`, `number` ou `date` como `YYYY-MM-DD`), detecta e decodifica os QR codes e códigos de barras compatíveis, verifica se o arquivo foi manipulado e, opcionalmente, compara o nome no documento com o nome da pessoa ou empresa esperada. Use-o para comprovante de fundos, holerites, extratos bancários, documentos fiscais, faturas ou qualquer documento que não se encaixe em um modelo fixo.

Esta é a versão de servidor para servidor da etapa hospedada de [Document AI](https://docs.didit.me/pt-br/core-technology/document-ai/overview.md). A requisição é `multipart/form-data`: o arquivo vai em `document`, e as definições dos campos vão em `fields` como uma única string com um array codificado em JSON.

## Defina os campos a extrair

`fields` é um array JSON de 1 a 30 itens, enviado como uma única string. Cada item tem uma `key` (letras minúsculas, dígitos e sublinhados, única dentro da requisição), um `name` legível por humanos, uma `instruction` que diz ao modelo o que procurar, um `type` (`text`, `number` ou `date`) e duas flags: `required` e `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
  }
]
```

Em uma requisição multipart, o array inteiro é um único valor de formulário:

```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"
```

A resposta devolve os `fields` normalizados e retorna `extracted_data` com chaves correspondentes aos seus valores de `key`, com `null` para tudo o que o modelo não conseguiu encontrar. `name`, `instruction` e `type` são opcionais em cada item (`type` tem `text` como padrão); `key` é obrigatório. Enviar `fields` como chaves de formulário com colchetes (`fields[0][key]=...`) ou em qualquer formato que não seja um array JSON retorna `400` antes de qualquer extração, portanto nada é cobrado.

## QR codes e códigos de barras

Toda resposta bem-sucedida inclui `document_ai.detected_codes`. Cada item contém:

| Campo | Descrição |
| - | - |
| `type` | Simbologia detectada, como `QR_CODE`, `CODE_128`, `EAN_13`, `DATA_MATRIX` ou `PDF_417` |
| `page_number` | Número da página, começando em 1 |
| `position` | Polígono detectado em pixels da página renderizada, ou `null` quando não há uma localização confiável |
| `x`, `y`, `width`, `height` | Caixa delimitadora em pixels da página renderizada, ou `null` quando não há uma localização confiável |
| `page_width`, `page_height` | Dimensões da página renderizada usadas pelas coordenadas |
| `parsed_payload` | String decodificada ou valor estruturado, ou `null` quando o código só pode ser localizado |
| `raw_payload` | Payload bruto do decodificador como string base64, quando disponível; caso contrário, uma string vazia |

O array cobre todas as páginas processadas de um PDF e fica vazio quando nenhum código suportado é encontrado. A Didit nunca adivinha um payload: QR codes danificados podem ser retornados com sua localização e `parsed_payload: null`, e falhas na detecção de códigos não fazem a requisição de Document AI falhar.

## Correspondência de nome

Marque no máximo um campo com `is_full_name: true` e envie o nome de quem você espera que seja o titular do documento:

| Você está verificando | Envie | O nome é comparado com |
| - | - | - |
| Uma pessoa | `expected_first_name` + `expected_last_name` | o nome completo da pessoa |
| Uma empresa | `expected_company_name` (+ `expected_company_country` opcional, um código ISO de 2 letras) | o nome da empresa |

Envie um grupo ou o outro, não os dois. Quando um nome é extraído e há um nome esperado, a resposta inclui `name_match_score` (de 0 a 100) e `name_on_document`. Uma pontuação abaixo de `document_ai_name_match_score_threshold` (padrão `80`) gera o aviso `DOCUMENT_AI_NAME_MISMATCH` e aplica `document_ai_name_mismatch_action`. Se nenhum campo estiver marcado com `is_full_name`, a Didit usa o primeiro campo de texto cuja chave pareça um nome (`name`, `holder`, `full_name`, `account_holder`); marque o campo explicitamente quando quiser controlar qual valor é comparado. Quando nenhum nome é encontrado no documento, ou nenhum nome esperado é enviado, a verificação de nome é ignorada e `name_match_score` é `null`.

## Riscos e ações

Cada risco abaixo corresponde a um parâmetro de ação que você pode definir por requisição: `DECLINE`, `REVIEW` ou `NO_ACTION`. A ação mais rigorosa acionada define `document_ai.status` (`Declined` > `In Review` > `Approved`), e todos os riscos acionados são listados em `document_ai.warnings`. Os padrões são os mesmos da etapa do fluxo hospedado; consulte [Regras e avisos do Document AI](https://docs.didit.me/pt-br/core-technology/document-ai/warnings-document-ai.md) para saber como cada risco é detectado.

| Risco | Parâmetro | Padrão |
| - | - | - |
| `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` |

## Arquivos, salvamento e faturamento

* **Arquivos aceitos:** PDF (com suporte a várias páginas), JPG, JPEG, PNG, TIFF, WebP ou um ZIP contendo o documento, até 30 MB. PDFs criptografados retornam `400`; envie um PDF descriptografado ou uma foto.
* **`save_api_request`** (padrão `true`): a requisição, os campos extraídos e os códigos detectados aparecem no Business Console em **Manual Checks**, onde sua equipe pode revisá-los. Defina como `false` para não salvar.
* **`vendor_data`** e **`metadata`** são retornados sem alterações na resposta para que você possa vincular o resultado aos seus próprios registros.
* **Preço:** \$0.20 por documento, cobrado quando o documento é processado e um status é retornado. O desconto do seu plano se aplica. Consulte [Preços](https://docs.didit.me/pt-br/getting-started/pricing.md#preços-das-apis-avulsas-servidor-a-servidor).

> [!NOTE]
>
> Precisa que o próprio usuário envie o documento? Precisa coletar até 3 documentos em um único fluxo, traduzir automaticamente a tela de envio ou cruzar os campos extraídos com dados do documento de identidade ou de questionários? Use, em vez disso, a [etapa hospedada do fluxo de trabalho do Document AI](https://docs.didit.me/pt-br/core-technology/document-ai/overview.md).


## OpenAPI

````yaml pt-br/openapi-25.json POST /v3/document-ai/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: API de verificação de identidade. Autentique-se com o cabeçalho x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/document-ai/:
    post:
      tags:
        - Standalone APIs
      summary: >-
        Document AI (extração de campos personalizados + verificações de
        adulteração)
      description: >-
        Extraia os campos que **você** define de qualquer documento de apoio
        (holerites, comprovantes de fundos, cartas de origem do patrimônio,
        declarações fiscais, contratos, faturas) em uma única chamada. Envie o
        arquivo junto com uma definição de `fields` (chave, nome, instrução de
        extração, tipo) e receba valores tipados (`text`, `number`, `date` como
        `YYYY-MM-DD`), uma pontuação opcional de correspondência de nome com a
        pessoa ou empresa esperada, sinais de adulteração de PDF/EXIF, um
        `status` `Approved`/`Declined`/`In Review` e uma lista `warnings` que
        explica cada problema encontrado. Este é o equivalente servidor a
        servidor da etapa Document AI do fluxo de verificação (workflow)
        hospedado (veja `/core-technology/document-ai/overview`). Ele usa o
        modelo de extração padrão da Didit e não expõe a seleção de provedor.


        **Latência.** A extração é baseada em LLM: chamadas típicas levam **5–15
        segundos**, e PDFs com várias páginas levam até **~30 segundos**.
        Configure um timeout de cliente de **pelo menos 45 segundos** e não
        tente novamente antes de a chamada terminar.


        **Formato da requisição.** Apenas `multipart/form-data`. `fields` é
        **uma única string com um array codificado em JSON** (1–30 itens, no
        máximo 16 KB). Arrays de formulário no estilo de colchetes são
        rejeitados com `400`. Cada item é `{key, name, instruction, type,
        required, is_full_name}`: `key` é a chave JSON que você recebe de volta
        (`^[a-z0-9_]{1,64}$`, única), `instruction` diz ao modelo o que ler,
        `type` é `text` (padrão) | `number` | `date`, `required` gera
        `DOCUMENT_AI_MISSING_REQUIRED_FIELDS` quando o valor não pode ser lido,
        e no máximo um campo pode definir `is_full_name: true` para marcar o
        valor comparado com o nome esperado.


        **Correspondência de nome.** Envie `expected_first_name` +
        `expected_last_name` (pessoa) **ou** `expected_company_name` (+
        `expected_company_country` opcional), mas não ambos. O valor do campo
        `is_full_name` (ou, quando nenhum estiver marcado, o primeiro campo de
        texto cuja chave pareça um nome) é comparado de forma aproximada.
        `name_match_score` (0–100) e `name_on_document` são sempre retornados
        quando os dois lados existem, e uma pontuação abaixo de
        `document_ai_name_match_score_threshold` (padrão 80) adiciona
        `DOCUMENT_AI_NAME_MISMATCH`, regido por
        `document_ai_name_mismatch_action`.


        **Lógica de decisão.** Cada risco corresponde a uma ação configurável:
        `DECLINE` → `status: "Declined"`, `REVIEW` → `status: "In Review"`,
        `NO_ACTION` → apenas informativo. Os padrões espelham a etapa do fluxo:
        documento ilegível `REVIEW`, campos obrigatórios ausentes `REVIEW`,
        suspeita de manipulação `DECLINE`, divergência de nome `NO_ACTION`,
        arquivo não suportado `REVIEW`. Um documento que não pode ser processado
        de forma alguma retorna `400`. Um documento legível, mas problemático,
        retorna `200` com `Declined`/`In Review`. Sempre inspecione
        `document_ai.status` e `document_ai.warnings`, não apenas o código HTTP.


        **Faturamento.** Cada resposta `200` consome um crédito de API do
        Document AI, **$0.20 por documento** pelo preço de tabela, pago com o
        crédito do seu plano ou com o saldo de recarga. Quando o saldo da
        organização não cobre a chamada, o endpoint retorna `403` antes de
        qualquer processamento. Chaves de API de sandbox retornam uma resposta
        simulada determinística e não são cobradas.


        **Persistência.** Com `save_api_request=true` (padrão), a chamada é
        armazenada como uma sessão do tipo API: o documento, os valores
        extraídos, as definições de campos e o snapshot da correspondência de
        nome são mantidos, a sessão aparece no Business Console e `request_id`
        funciona com `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: >-
                    O documento a ser lido. Extensões permitidas: `tiff`, `jpg`,
                    `jpeg`, `png`, `pdf`, `webp`, `zip`. Tamanho máximo de
                    upload: **30 MB** (arquivos maiores são rejeitados com
                    `400`). PDFs com várias páginas são compatíveis (espere
                    maior latência); PDFs criptografados são rejeitados com
                    `400`. As imagens são compactadas automaticamente antes do
                    processamento.
                fields:
                  type: string
                  description: >-
                    Uma string com um array codificado em JSON contendo **1–30**
                    definições de campos (máximo de 16 KB). Cada item: `key`
                    (obrigatório, `^[a-z0-9_]{1,64}$`, único; a chave retornada
                    em `extracted_data`), `name` (≤100 caracteres, exibido nas
                    mensagens), `instruction` (≤500 caracteres, o que o modelo
                    deve ler), `type` (`text` padrão | `number` | `date`),
                    `required` (booleano, padrão `false`), `is_full_name`
                    (booleano, padrão `false`, no máximo um por requisição).
                    Arrays de formulário no estilo de colchetes, JSON inválido,
                    chaves duplicadas ou mais de um `is_full_name` retornam
                    `400` antes de qualquer processamento ou faturamento.
                  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: >-
                    Primeiro nome a ser verificado em relação ao campo de nome
                    do documento (correspondência aproximada, considerando
                    transliteração). Use junto com `expected_last_name`; não
                    pode ser combinado com `expected_company_name`.
                  example: Sophia
                expected_last_name:
                  type: string
                  description: >-
                    Sobrenome a ser verificado em relação ao campo de nome do
                    documento, combinado com `expected_first_name` para
                    `name_match_score`.
                  example: Martinez
                expected_company_name:
                  type: string
                  description: >-
                    Nome da empresa a ser verificado em relação ao campo de nome
                    do documento (para documentos de empresas). Não pode ser
                    combinado com `expected_first_name` / `expected_last_name`
                    (sem valor de exemplo de propósito: o exemplo de requisição
                    gerado usa os campos de pessoa; substitua-os por este ao
                    verificar um documento de empresa).
                expected_company_country:
                  type: string
                  description: >-
                    Código de país ISO 3166-1 alfa-2 opcional (duas letras
                    ASCII, por exemplo `FR`) que ajusta a normalização do nome
                    da empresa para `expected_company_name`. Usado apenas com
                    `expected_company_name`.
                document_ai_name_match_score_threshold:
                  type: integer
                  minimum: 0
                  maximum: 100
                  default: 80
                  description: >-
                    `name_match_score` mínimo (0–100) para considerar que o nome
                    corresponde. Uma pontuação menor adiciona
                    `DOCUMENT_AI_NAME_MISMATCH`, regido por
                    `document_ai_name_mismatch_action`.
                  example: 80
                document_ai_unreadable_document_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    O que fazer quando nenhum campo pôde ser lido do documento
                    (`DOCUMENT_AI_UNREADABLE_DOCUMENT`).
                document_ai_missing_required_fields_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    O que fazer quando pelo menos um campo `required` não pôde
                    ser lido (`DOCUMENT_AI_MISSING_REQUIRED_FIELDS`;
                    `additional_data.missing_fields` os lista).
                document_ai_document_tampering_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: DECLINE
                  description: >-
                    O que fazer quando a análise forense de PDF/EXIF suspeita de
                    manipulação — modificação após a assinatura digital, editor
                    de PDF conhecido, manipulação por sobreposição de texto,
                    reexportação suspeita, anomalias de imagem
                    (`DOCUMENT_AI_SUSPECTED_MANIPULATION`).
                document_ai_name_mismatch_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: NO_ACTION
                  description: >-
                    O que fazer quando `name_match_score` está abaixo do limiar
                    (`DOCUMENT_AI_NAME_MISMATCH`).
                document_ai_unsupported_file_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    O que fazer quando o envio está vazio ou não é um arquivo
                    processável (`DOCUMENT_AI_UNSUPPORTED_FILE`).
                save_api_request:
                  type: boolean
                  default: true
                  description: >-
                    Quando `true` (padrão), persiste a chamada como uma sessão
                    do tipo API: visível no Business Console, recuperável via
                    `GET /v3/session/{sessionId}/decision/` usando o
                    `request_id` retornado, com o documento enviado, os valores
                    extraídos, as definições de campos e o snapshot da
                    correspondência de nome armazenados. Quando `false`, nada é
                    armazenado e `request_id` é um UUID transitório usado apenas
                    para correlacionar a resposta; a chamada continua sendo
                    cobrada.
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    String opaca opcional (seu ID interno de usuário, e-mail,
                    UUID…) armazenada na sessão persistida e devolvida na
                    resposta. Use-a para correlacionar chamadas de API com seus
                    próprios registros e para filtrar sessões posteriormente.
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Objeto JSON opcional armazenado com a sessão (quando
                    `save_api_request=true`) e devolvido na resposta. Em
                    requisições multipart, envie-o como um campo de string
                    codificada em JSON (por exemplo,
                    `metadata={"flow":"onboarding"}`), que é convertido em um
                    objeto.
                  example:
                    flow: onboarding
      responses:
        '200':
          description: >-
            Documento processado. `document_ai.status` é `Approved`, `Declined`
            ou `In Review`; cada problema detectado é detalhado em
            `document_ai.warnings`. Um documento com problemas ainda retorna
            `200`: inspecione o corpo, não apenas o código HTTP. Quando
            `save_api_request=true`, `request_id` é o id da sessão persistida.
          content:
            application/json:
              examples:
                Approved:
                  summary: Holerite lido sem problemas, nome correspondente
                  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: Não foi possível ler `net_pay`; ação padrão 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: >-
                    A análise forense de PDF identificou um editor conhecido;
                    ação padrão 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: >-
                      ID da sessão persistida quando `save_api_request=true`
                      (utilizável com `GET /v3/session/{sessionId}/decision/`);
                      caso contrário, um UUID de correlação transitório.
                  document_ai:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                          - In Review
                        description: >-
                          `Approved` quando nenhum aviso resulta em recusa ou
                          revisão; `Declined` quando pelo menos um risco é
                          mapeado para `DECLINE`; caso contrário, `In Review`
                          quando pelo menos um é mapeado para `REVIEW`. A lista
                          `warnings` explica o motivo.
                      extracted_data:
                        type: object
                        additionalProperties: true
                        description: >-
                          Uma entrada por chave de campo solicitada. Os valores
                          são tipados conforme o `type` do campo (strings para
                          `text`, números para `number`, strings `YYYY-MM-DD`
                          para `date`) ou `null` quando o valor não pôde ser
                          lido.
                        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 codes e códigos de barras detectados em todas as
                          páginas processadas. Vazio quando nenhum é encontrado.
                          Um QR code localizado, mas que não pôde ser
                          decodificado, tem `parsed_payload: null`.
                        items:
                          $ref: '#/components/schemas/DocumentAIDetectedCode'
                      fields:
                        type: array
                        description: >-
                          As definições de campos normalizadas usadas nesta
                          extração, devolvidas na resposta (também armazenadas
                          com a sessão quando `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: >-
                          Similaridade aproximada (0–100) entre
                          `name_on_document` e o nome esperado da
                          pessoa/empresa. Retornada sempre que existem tanto um
                          valor de nome quanto um nome esperado, em
                          correspondências **e** em divergências; caso
                          contrário, `null`.
                        example: 96
                      name_on_document:
                        type: string
                        nullable: true
                        description: >-
                          O valor de nome extraído do documento (o campo
                          `is_full_name` ou o primeiro campo de texto semelhante
                          a um nome) que foi comparado com o nome esperado.
                          `null` quando nenhum valor de nome estava disponível.
                        example: Sophia Martinez
                      warnings:
                        type: array
                        description: >-
                          Vazio em uma aprovação sem ressalvas. Cada entrada
                          explica um risco detectado; entradas com `log_type:
                          "error"` definem `status` como `Declined`, e entradas
                          com `log_type: "warning"` o definem como `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: >-
                                Código de risco legível por máquina. Cada um é
                                controlado pela opção de requisição
                                `document_ai_*_action` correspondente.
                              example: DOCUMENT_AI_MISSING_REQUIRED_FIELDS
                            feature:
                              type: string
                              enum:
                                - DOCUMENT_AI
                              description: >-
                                Recurso que emitiu o aviso. Sempre `DOCUMENT_AI`
                                neste endpoint.
                            additional_data:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: >-
                                Contexto adicional sobre o risco:
                                `{"missing_fields": ["Net pay"]}` para campos
                                obrigatórios ausentes, `{"name_on_document",
                                "score", "threshold"}` para divergência de nome
                                e o achado forense (`detection_method`, detalhes
                                do produtor/editor) para suspeita de
                                manipulação. `null` quando não há nada a
                                acrescentar.
                              example:
                                missing_fields:
                                  - Net pay
                            log_type:
                              type: string
                              enum:
                                - error
                                - warning
                                - information
                              description: >-
                                Severidade derivada da ação configurada: `error`
                                (DECLINE), `warning` (REVIEW), `information`
                                (NO_ACTION).
                            short_description:
                              type: string
                              description: Descrição legível de uma linha do risco.
                              example: Required fields could not be extracted
                            long_description:
                              type: string
                              description: >-
                                Explicação legível, interpolada com
                                `additional_data` quando relevante.
                  vendor_data:
                    type: string
                    nullable: true
                    description: Eco do `vendor_data` que você enviou, ou `null`.
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: Eco do objeto `metadata` que você enviou, ou `null`.
                  created_at:
                    type: string
                    format: date-time
                    description: Quando a requisição foi processada (UTC, ISO 8601).
        '400':
          description: >-
            Erro de validação ou de processamento. Problemas em nível de campo
            retornam o envelope padrão do DRF (um array de mensagens para cada
            campo com problema). Documentos criptografados ou ilegíveis e falhas
            de extração retornam `{"error": ...}`.
          content:
            application/json:
              examples:
                Missing document:
                  summary: '`document` não incluído nos dados do formulário'
                  value:
                    document:
                      - No file was submitted.
                Invalid fields payload:
                  summary: '`fields` não é uma única string de array codificada em JSON'
                  value:
                    fields:
                      - fields must be a valid JSON array string.
                Duplicate field keys:
                  summary: Dois itens compartilham a mesma `key`
                  value:
                    fields:
                      - Every fields item must have a unique key.
                Conflicting expectations:
                  summary: Expectativas de pessoa e de empresa enviadas juntas
                  value:
                    non_field_errors:
                      - >-
                        Provide either person expected-name fields or
                        expected_company_name, not both.
                Invalid metadata:
                  summary: '`metadata` não é um objeto JSON (ou contém um caractere NUL)'
                  value:
                    metadata:
                      - Metadata must be a JSON object.
                Oversized vendor_data:
                  summary: '`vendor_data` acima do limite de 2.000 bytes'
                  value:
                    vendor_data:
                      - vendor_data is too long (maximum 2000 bytes).
                Encrypted PDF:
                  summary: PDF protegido por senha
                  value:
                    error: >-
                      The PDF is encrypted. Please upload a decrypted PDF or a
                      photo instead.
                Extraction failed:
                  summary: O pipeline de extração não conseguiu processar o documento
                  value:
                    error:
                      - Error extracting Document AI information
              schema:
                type: object
                additionalProperties: true
        '403':
          description: >-
            Permissão negada. Retornado quando o cabeçalho `x-api-key` está
            ausente e também quando o saldo da organização que faz a chamada não
            cobre a chamada; uma chave incorreta, revogada ou expirada retorna
            `401`. Uma chave ausente retorna `403` com `{"detail": ...}`; uma
            chave incorreta, revogada ou expirada retorna `401`. Créditos
            insuficientes (e organizações faturadas por contrato cuja tabela de
            tarifas não tem uma entrada para a Document AI API) retornam `403`
            com `{"error": ...}` antes de qualquer processamento do documento.
          content:
            application/json:
              examples:
                Missing or invalid API key:
                  summary: Nenhum cabeçalho `x-api-key`, ou a chave é inválida/revogada
                  value:
                    detail: You do not have permission to perform this action.
                Not enough credits:
                  summary: O saldo da organização não cobre a chamada
                  value:
                    error: >-
                      You don't have enough credits to perform this request.
                      Please top up at https://business.didit.me
                Contract rate missing:
                  summary: >-
                    Organização com faturamento por contrato cuja tabela de
                    tarifas não tem entrada para a API de Document AI
                  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: >-
            Limite de requisições excedido. Todos os endpoints POST/PATCH/DELETE
            compartilham uma cota de 300 requisições de escrita por minuto por
            chave de API. A resposta inclui os cabeçalhos `X-RateLimit-Limit`,
            `X-RateLimit-Remaining`, `X-RateLimit-Reset` e `Retry-After`.
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: Mais de 300 requisições de escrita no minuto atual
                  value:
                    detail: >-
                      Write request rate limit exceeded. You can make up to 300
                      requests per minute.
              schema:
                type: object
                properties:
                  detail:
                    type: string
      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: >-
            Simbologia detectada, por exemplo `QR_CODE`, `CODE_128`, `EAN_13`,
            `DATA_MATRIX` ou `PDF_417`.
        page_number:
          type: integer
          minimum: 1
          description: Número da página, começando em 1.
        position:
          type: array
          nullable: true
          description: >-
            Polígono detectado em coordenadas de pixels da página renderizada. É
            `null` quando não há uma localização confiável disponível.
          items:
            type: array
            minItems: 2
            maxItems: 2
            items:
              type: integer
        x:
          type: integer
          nullable: true
          description: >-
            Borda esquerda da caixa delimitadora, em pixels da página
            renderizada.
        'y':
          type: integer
          nullable: true
          description: >-
            Borda superior da caixa delimitadora, em pixels da página
            renderizada.
        width:
          type: integer
          nullable: true
          description: Largura da caixa delimitadora em pixels da página renderizada.
        height:
          type: integer
          nullable: true
          description: Altura da caixa delimitadora em pixels da página renderizada.
        page_width:
          type: integer
          description: Largura da página renderizada, em pixels.
        page_height:
          type: integer
          description: Altura da página renderizada, em pixels.
        raw_payload:
          type: string
          description: >-
            Payload bruto do decodificador como string base64, quando
            disponível; caso contrário, uma string vazia.
        parsed_payload:
          nullable: true
          description: >-
            String decodificada ou valor estruturado. `null` quando o código foi
            localizado, mas não pôde ser decodificado.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Chave de API da sua aplicação, em Developers -> API keys no Business
        Console. A chave principal tem acesso total. Uma chave nomeada pode ter
        escopo restrito: nenhum acesso, leitura ou escrita por recurso, limitada
        a alguns fluxos ou a sessões aprovadas, a uma lista de endereços IP e a
        uma data de validade. 401 significa que a chave está errada, revogada ou
        expirada; 403 significa que nenhuma chave foi enviada, que a chave não
        tem acesso a este recurso ou ação, ou que a requisição veio de um
        endereço fora da sua lista de IPs; 404 em uma rota de sessão significa
        que a sessão está fora dos fluxos ou status da chave. Uma chave sem
        acesso a mídia recebe URLs de imagem, vídeo e PDF como null, e uma chave
        sem permissão de escrita em sessões recebe links e tokens de sessão como
        null. Consulte https://docs.didit.me/console/api-keys.

````

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