> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# API d'extracció de dades de documents amb Document AI

> Extreu els camps que definiu de qualsevol PDF o imatge amb Didit, de servidor a servidor, amb comprovacions de noms i manipulació. $0.20 per document.

Envia un document i la llista de camps que vols llegir-hi. Didit executa sobre el fitxer el model d'extracció predeterminat, retorna tots els camps amb el tipus indicat (`text`, `number` o `date` com a `YYYY-MM-DD`), detecta i descodifica els codis QR i de barres compatibles, comprova si el fitxer ha estat manipulat i, opcionalment, compara el nom que consta al document amb la persona o l'empresa que esperes. Fes-lo servir per a comprovants de fons, nòmines, extractes bancaris, documents fiscals, factures o qualsevol document que no encaixi en una plantilla fixa.

Aquesta és la versió de servidor a servidor del pas de [Document AI](https://docs.didit.me/ca/core-technology/document-ai/overview.md) allotjat. La sol·licitud és `multipart/form-data`: el fitxer va a `document` i les definicions dels camps a `fields`, com una única cadena que conté una matriu JSON codificada.

## Definir els camps a extreure

`fields` és un array JSON d'1 a 30 elements, enviat com una única cadena. Cada element té una `key` (lletres minúscules, dígits i guions baixos, única dins de la sol·licitud), un `name` llegible per a humans, una `instruction` que indica al model què ha de buscar, un `type` (`text`, `number` o `date`) i dos indicadors: `required` i `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
  }
]
```

En una sol·licitud multipart, tota la matriu és un únic valor de formulari:

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

La resposta reprodueix els `fields` normalitzats i retorna `extracted_data` indexat pels valors de `key` que has enviat, amb `null` per a qualsevol cosa que el model no hagi pogut trobar. `name`, `instruction` i `type` són opcionals a cada element (`type` és `text` per defecte); `key` és obligatori. Si envies `fields` com a claus de formulari amb format de claudàtor (`fields[0][key]=...`) o com a qualsevol cosa que no sigui un array JSON, es retorna `400` abans que s'executi cap extracció, de manera que no es factura res.

## Codis QR i codis de barres

Cada resposta satisfactòria inclou `document_ai.detected_codes`. Cada element conté:

| Camp | Descripció |
| - | - |
| `type` | Simbologia detectada, com ara `QR_CODE`, `CODE_128`, `EAN_13`, `DATA_MATRIX` o `PDF_417` |
| `page_number` | Número de pàgina, amb una numeració que comença per 1 |
| `position` | Polígon detectat en píxels de la pàgina renderitzada, o `null` quan no hi ha cap ubicació fiable |
| `x`, `y`, `width`, `height` | Caixa delimitadora en píxels de la pàgina renderitzada, o `null` quan no hi ha cap ubicació fiable |
| `page_width`, `page_height` | Dimensions de la pàgina renderitzada que utilitzen les coordenades |
| `parsed_payload` | Cadena descodificada o valor estructurat, o `null` quan el codi només es pot localitzar |
| `raw_payload` | Payload en brut del descodificador com a cadena base64 quan està disponible; en cas contrari, una cadena buida |

La matriu cobreix totes les pàgines processades d'un PDF i és buida quan no es troba cap codi compatible. Didit no endevina mai cap payload: els codis QR malmesos es poden retornar amb la seva ubicació i `parsed_payload: null`, i els errors en la detecció de codis no fan fallar la sol·licitud de Document AI.

## Coincidència de noms

Marca com a màxim un camp amb `is_full_name: true` i envia la persona o l'empresa a qui esperes que pertanyi el document:

| Estàs verificant | Envia | El nom es compara amb |
| - | - | - |
| Una persona | `expected_first_name` + `expected_last_name` | el nom complet de la persona |
| Una empresa | `expected_company_name` (+ `expected_company_country` opcional, un codi ISO de 2 lletres) | el nom de l'empresa |

Envia un grup o l'altre, no tots dos. Quan s'extreu un nom i hi ha un nom esperat, la resposta inclou `name_match_score` (de 0 a 100) i `name_on_document`. Una puntuació inferior a `document_ai_name_match_score_threshold` (predeterminat `80`) activa l'advertència `DOCUMENT_AI_NAME_MISMATCH` i aplica `document_ai_name_mismatch_action`. Si cap camp no està marcat com a `is_full_name`, Didit utilitza el primer camp de text la clau del qual sembli un nom (`name`, `holder`, `full_name`, `account_holder`); marca el camp explícitament quan vulguis controlar quin valor es compara. Quan no es troba cap valor de nom al document, o no s'envia cap nom esperat, la comprovació del nom s'omet i `name_match_score` és `null`.

## Riscos i accions

Cada risc següent correspon a un paràmetre d'acció que pots definir per sol·licitud: `DECLINE`, `REVIEW` o `NO_ACTION`. L'acció més estricta activada determina `document_ai.status` (`Declined` > `In Review` > `Approved`), i cada risc activat apareix a `document_ai.warnings`. Els valors predeterminats coincideixen amb els del pas de flux de treball allotjat; consulta [Regles i advertències de Document AI](https://docs.didit.me/ca/core-technology/document-ai/warnings-document-ai.md) per saber com es detecta cada risc.

| Risc | Paràmetre | Predeterminat |
| - | - | - |
| `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` |

## Fitxers, desament i facturació

* **Fitxers acceptats:** PDF (són compatibles els de diverses pàgines), JPG, JPEG, PNG, TIFF, WebP o un ZIP que contingui el document, de fins a 30 MB. Els PDF xifrats retornen `400`; puja un PDF desxifrat o una fotografia.
* **`save_api_request`** (predeterminat `true`): la sol·licitud, els camps extrets i els codis detectats apareixen a la Business Console, a **Comprovacions manuals**, on el teu equip els pot revisar. Defineix-lo com a `false` per no desar-los.
* **`vendor_data`** i **`metadata`** es retornen sense canvis a la resposta perquè puguis vincular el resultat amb els teus propis registres.
* **Preu:** \$0.20 per document, facturat quan el document es processa i es retorna un estat. S'aplica el descompte del teu pla. Consulta [Preus](https://docs.didit.me/ca/getting-started/pricing.md#preus-de-les-api-independents-servidor-a-servidor).

> [!NOTE]
>
> Necessites que l'usuari pugi el document ell mateix, que es recullin fins a 3 documents en un sol flux, que es tradueixi automàticament la pantalla de pujada o que es creuin els camps extrets amb dades d'identitat o de qüestionaris? Utilitza en lloc d'això el [pas de flux de treball de Document AI](https://docs.didit.me/ca/core-technology/document-ai/overview.md) allotjat.


## OpenAPI

````yaml ca/openapi-25.json POST /v3/document-ai/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: API de verificació d'identitat. Autentica't amb la capçalera x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/document-ai/:
    post:
      tags:
        - Standalone APIs
      summary: >-
        Document AI (extracció de camps personalitzats + comprovacions de
        manipulació)
      description: >-
        Extreu els camps que **tu** defineixis de qualsevol document acreditatiu
        — nòmines, comprovants de fons, cartes d'origen del patrimoni,
        declaracions d'impostos, contractes, factures — en una sola crida. Envia
        el fitxer juntament amb una definició de `fields` (clau, nom, instrucció
        d'extracció, tipus) i rep valors tipats (`text`, `number`, `date` com a
        `YYYY-MM-DD`), una puntuació de coincidència de nom opcional respecte a
        la persona o empresa esperada, senyals de manipulació de PDF/EXIF, un
        `status` `Approved`/`Declined`/`In Review`, i una llista de `warnings`
        que explica cada problema detectat. Aquest és l'equivalent de servidor a
        servidor del pas del flux de treball allotjat de Document AI (consulta
        `/core-technology/document-ai/overview`); utilitza el model d'extracció
        per defecte de Didit i no permet la selecció de proveïdor.


        **Latència.** L'extracció es basa en LLM: les crides típiques triguen
        **5–15 segons**, i els PDF multipàgina fins a **~30 segons**. Configura
        un temps d'espera del client d'**almenys 45 segons** i no reintentis
        abans que la crida hagi finalitzat.


        **Format de la sol·licitud.** Només `multipart/form-data`. `fields` és
        **una única cadena d'array codificada en JSON** (1–30 elements, com a
        màxim 16 KB); els arrays de formulari amb claudàtors es rebutgen amb un
        `400`. Cada element és `{key, name, instruction, type, required,
        is_full_name}` — `key` és la clau JSON que reps (`^[a-z0-9_]{1,64}$`,
        única), `instruction` indica al model què ha de llegir, `type` és `text`
        (per defecte) | `number` | `date`, `required` genera
        `DOCUMENT_AI_MISSING_REQUIRED_FIELDS` quan el valor no es pot llegir, i
        com a màxim un camp pot tenir `is_full_name: true` per marcar el valor
        comparat amb el nom esperat.


        **Coincidència de noms.** Proporciona `expected_first_name` +
        `expected_last_name` (persona) **o** `expected_company_name` (+
        `expected_company_country` opcional) — no tots dos. El valor del camp
        `is_full_name` (o, si no n'hi ha cap de marcat, el primer camp de text
        la clau del qual sembli un nom) es compara de manera difusa;
        `name_match_score` (0–100) i `name_on_document` es retornen sempre quan
        existeixen ambdues parts, i una puntuació inferior a
        `document_ai_name_match_score_threshold` (per defecte 80) afegeix
        `DOCUMENT_AI_NAME_MISMATCH`, regit per
        `document_ai_name_mismatch_action`.


        **Lògica de decisió.** Cada risc s'associa a una acció configurable:
        `DECLINE` → `status: "Declined"`, `REVIEW` → `status: "In Review"`,
        `NO_ACTION` → només informatiu. Els valors per defecte reflecteixen el
        pas del flux de treball: document il·legible `REVIEW`, camps obligatoris
        absents `REVIEW`, sospita de manipulació `DECLINE`, discrepància de nom
        `NO_ACTION`, fitxer no admès `REVIEW`. Un document que no es pot
        processar de cap manera retorna un `400`; un document llegible però amb
        problemes retorna un `200` amb `Declined`/`In Review` — inspecciona
        sempre `document_ai.status` i `document_ai.warnings`, no només el codi
        HTTP.


        **Facturació.** Cada resposta `200` consumeix un crèdit de l'API de
        Document AI — **$0.20 per document** a preu de llista, que es paga amb
        el crèdit del teu pla o el saldo de recàrrega. Quan el saldo de
        l'organització no cobreix la crida, l'endpoint retorna un `403` abans de
        qualsevol processament. Les claus d'API de sandbox retornen una resposta
        simulada determinista i no es cobren.


        **Persistència.** Amb `save_api_request=true` (per defecte), la crida
        s'emmagatzema com una sessió de tipus API: el document, els valors
        extrets, les definicions de camps i la captura de coincidència de noms
        es conserven, la sessió apareix a la Business Console, i `request_id`
        funciona amb `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: >-
                    El document per llegir. Extensions permeses: `tiff`, `jpg`,
                    `jpeg`, `png`, `pdf`, `webp`, `zip`. Mida màxima de pujada:
                    **30 MB** (els fitxers més grans es rebutgen amb un `400`).
                    Els PDF multipàgina són compatibles (espera una latència més
                    alta); els PDF xifrats es rebutgen amb un `400`. Les imatges
                    es comprimeixen automàticament abans de processar-se.
                fields:
                  type: string
                  description: >-
                    Una cadena que codifica en JSON una matriu amb **1–30**
                    definicions de camp (màxim 16 KB). Cada element: `key`
                    (obligatori, `^[a-z0-9_]{1,64}$`, únic — la clau retornada a
                    `extracted_data`), `name` (≤100 caràcters, mostrat als
                    missatges), `instruction` (≤500 caràcters, el que ha de
                    llegir el model), `type` (`text` per defecte | `number` |
                    `date`), `required` (booleà, per defecte `false`),
                    `is_full_name` (booleà, per defecte `false`, com a màxim un
                    per sol·licitud). Les matrius de formulari amb claudàtors,
                    el JSON no vàlid, les claus duplicades o més d'un
                    `is_full_name` retornen `400` abans de qualsevol
                    processament o facturació.
                  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: >-
                    Nom de pila a verificar respecte al camp del nom del
                    document (coincidència difusa, compatible amb
                    transliteració). Utilitza'l juntament amb
                    `expected_last_name`; no es pot combinar amb
                    `expected_company_name`.
                  example: Sophia
                expected_last_name:
                  type: string
                  description: >-
                    Cognom a verificar contra el camp de nom del document,
                    combinat amb `expected_first_name` per a `name_match_score`.
                  example: Martinez
                expected_company_name:
                  type: string
                  description: >-
                    Nom de l'empresa a verificar respecte al camp de nom del
                    document (per a documents d'empresa). No es pot combinar amb
                    `expected_first_name` / `expected_last_name` (no hi ha cap
                    valor d'exemple expressament —la mostra de sol·licitud
                    generada utilitza els camps de persona física; canvia'ls per
                    aquest quan verifiquis un document d'empresa).
                expected_company_country:
                  type: string
                  description: >-
                    Codi de país ISO 3166-1 alfa-2 opcional (dues lletres ASCII,
                    p. ex., `FR`) que ajusta la normalització del nom de
                    l'empresa per a `expected_company_name`. Només s'utilitza
                    amb `expected_company_name`.
                document_ai_name_match_score_threshold:
                  type: integer
                  minimum: 0
                  maximum: 100
                  default: 80
                  description: >-
                    Puntuació mínima de `name_match_score` (0–100) per
                    considerar que el nom coincideix. Una puntuació inferior
                    afegeix `DOCUMENT_AI_NAME_MISMATCH`, regit per
                    `document_ai_name_mismatch_action`.
                  example: 80
                document_ai_unreadable_document_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    Què fer quan no s'ha pogut llegir cap camp del document
                    (`DOCUMENT_AI_UNREADABLE_DOCUMENT`).
                document_ai_missing_required_fields_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    Què fer quan no s'ha pogut llegir almenys un camp `required`
                    (`DOCUMENT_AI_MISSING_REQUIRED_FIELDS`;
                    `additional_data.missing_fields` els enumera).
                document_ai_document_tampering_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: DECLINE
                  description: >-
                    Què fer quan l'anàlisi forense de PDF/EXIF sospita de
                    manipulació — modificat després de la signatura digital,
                    editor de PDF conegut, manipulació de text superposat,
                    reexportació sospitosa, anomalies en la imatge
                    (`DOCUMENT_AI_SUSPECTED_MANIPULATION`).
                document_ai_name_mismatch_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: NO_ACTION
                  description: >-
                    Què fer quan `name_match_score` està per sota del llindar
                    (`DOCUMENT_AI_NAME_MISMATCH`).
                document_ai_unsupported_file_action:
                  type: string
                  enum:
                    - DECLINE
                    - REVIEW
                    - NO_ACTION
                  default: REVIEW
                  description: >-
                    Què fer quan la càrrega està buida o no és un fitxer
                    processable (`DOCUMENT_AI_UNSUPPORTED_FILE`).
                save_api_request:
                  type: boolean
                  default: true
                  description: >-
                    Quan és `true` (per defecte), persisteix la crida com una
                    sessió de tipus API — visible a la Business Console,
                    recuperable mitjançant `GET
                    /v3/session/{sessionId}/decision/` utilitzant el
                    `request_id` retornat, amb el document carregat, els valors
                    extrets, les definicions de camps i la instantània de
                    coincidència de noms emmagatzemats. Quan és `false`, no
                    s'emmagatzema res i `request_id` és un UUID transitori només
                    per a la correlació de la resposta; la crida es continua
                    facturant.
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    Cadena opaca opcional (el teu ID d'usuari intern, correu
                    electrònic, UUID…) desada a la sessió persistent i retornada
                    a la resposta. Utilitza-la per correlacionar crides a l'API
                    amb els teus propis registres i per filtrar sessions més
                    endavant.
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Objecte JSON opcional emmagatzemat amb la sessió (quan
                    `save_api_request=true`) i retornat a la resposta. En
                    sol·licituds multipart, envia'l com a camp de cadena
                    codificat en JSON (p. ex.,
                    `metadata={"flow":"onboarding"}`); s'analitza com un
                    objecte.
                  example:
                    flow: onboarding
      responses:
        '200':
          description: >-
            Document processat. `document_ai.status` és `Approved`, `Declined` o
            `In Review`; cada problema detectat es detalla a
            `document_ai.warnings`. Un document problemàtic continua retornant
            `200`; inspecciona el cos, no només el codi HTTP. Quan
            `save_api_request=true`, `request_id` és l'id de sessió persistit.
          content:
            application/json:
              examples:
                Approved:
                  summary: Nòmina llegida correctament, el nom coincideix
                  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: no s'ha pogut llegir `net_pay`; acció per defecte 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: >-
                    L'anàlisi forense del PDF ha detectat un editor conegut;
                    acció per defecte 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 de sessió persistida quan `save_api_request=true`
                      (utilitzable amb `GET /v3/session/{sessionId}/decision/`);
                      en cas contrari, un UUID de correlació transitori.
                  document_ai:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                          - In Review
                        description: >-
                          `Approved` quan cap advertència no es resol en un
                          rebuig o revisió; `Declined` quan almenys un risc
                          s'assigna a `DECLINE`; en cas contrari, `In Review`
                          quan almenys un s'assigna a `REVIEW`. La llista
                          `warnings` n'explica el motiu.
                      extracted_data:
                        type: object
                        additionalProperties: true
                        description: >-
                          Una entrada per clau de camp sol·licitada. Els valors
                          estan tipats segons el `type` del camp: cadenes per a
                          `text`, nombres per a `number`, cadenes `YYYY-MM-DD`
                          per a `date`, o `null` quan el valor no s'ha pogut
                          llegir.
                        example:
                          employer_name: Acme Payments Ltd
                          employee_name: Sophia Martinez
                          net_pay: 3120.5
                          pay_date: '2026-07-31'
                      detected_codes:
                        type: array
                        description: >-
                          Codis QR i codis de barres detectats a totes les
                          pàgines processades. Buit quan no se'n troba cap. Un
                          codi QR localitzat però no descodificable té
                          `parsed_payload: null`.
                        items:
                          $ref: '#/components/schemas/DocumentAIDetectedCode'
                      fields:
                        type: array
                        description: >-
                          Les definicions de camps normalitzades que s'han
                          utilitzat per a aquesta extracció, retornades com a
                          resposta (també s'emmagatzemen amb la sessió quan
                          `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: >-
                          Similitud difusa (0–100) entre `name_on_document` i el
                          nom esperat de la persona/empresa. Es retorna sempre
                          que existeixin tant un valor de nom com un nom esperat
                          — en coincidències **i** discrepàncies; `null` en cas
                          contrari.
                        example: 96
                      name_on_document:
                        type: string
                        nullable: true
                        description: >-
                          El valor del nom extret del document (el camp
                          `is_full_name`, o el primer camp de text similar a un
                          nom) que s'ha comparat amb el nom esperat. `null` quan
                          no hi havia cap valor de nom disponible.
                        example: Sophia Martinez
                      warnings:
                        type: array
                        description: >-
                          Buit en cas d'aprovació neta. Cada entrada explica un
                          risc detectat; les entrades amb `log_type: "error"`
                          estableixen `status` a `Declined`, les entrades amb
                          `log_type: "warning"` l'estableixen a `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: >-
                                Codi de risc llegible per màquina. Cadascun està
                                regulat per l'opció de sol·licitud
                                `document_ai_*_action` corresponent.
                              example: DOCUMENT_AI_MISSING_REQUIRED_FIELDS
                            feature:
                              type: string
                              enum:
                                - DOCUMENT_AI
                              description: >-
                                Funcionalitat que ha generat l'advertència.
                                Sempre `DOCUMENT_AI` en aquest endpoint.
                            additional_data:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: >-
                                Context addicional per al risc:
                                `{"missing_fields": ["Net pay"]}` per a camps
                                requerits que falten, `{"name_on_document",
                                "score", "threshold"}` per a una discrepància de
                                nom, i la troballa forense (`detection_method`,
                                detalls del productor/editor) en cas de sospita
                                de manipulació. `null` quan no hi ha res a
                                afegir.
                              example:
                                missing_fields:
                                  - Net pay
                            log_type:
                              type: string
                              enum:
                                - error
                                - warning
                                - information
                              description: >-
                                Gravetat derivada de l'acció configurada:
                                `error` (DECLINE), `warning` (REVIEW),
                                `information` (NO_ACTION).
                            short_description:
                              type: string
                              description: >-
                                Descripció breu d'una sola línia del risc,
                                llegible per a humans.
                              example: Required fields could not be extracted
                            long_description:
                              type: string
                              description: >-
                                Explicació fàcil de llegir, interpolada amb
                                `additional_data` quan correspongui.
                  vendor_data:
                    type: string
                    nullable: true
                    description: Ressò de les `vendor_data` que has enviat, o `null`.
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: Ressò de l'objecte `metadata` que has enviat, o `null`.
                  created_at:
                    type: string
                    format: date-time
                    description: Quan es va processar la sol·licitud (UTC, ISO 8601).
        '400':
          description: >-
            Error de validació o de processament. Els problemes a nivell de camp
            retornen l'embolcall estàndard de DRF (un array de missatges per
            camp afectat). Els documents xifrats o il·legibles i les fallades
            d'extracció retornen `{"error": ...}`.
          content:
            application/json:
              examples:
                Missing document:
                  summary: '`document` no s''ha inclòs a les dades del formulari'
                  value:
                    document:
                      - No file was submitted.
                Invalid fields payload:
                  summary: '`fields` no és una cadena d''array codificada en JSON'
                  value:
                    fields:
                      - fields must be a valid JSON array string.
                Duplicate field keys:
                  summary: Dos elements comparteixen la mateixa `key`
                  value:
                    fields:
                      - Every fields item must have a unique key.
                Conflicting expectations:
                  summary: Expectatives de persona i empresa enviades juntes
                  value:
                    non_field_errors:
                      - >-
                        Provide either person expected-name fields or
                        expected_company_name, not both.
                Invalid metadata:
                  summary: '`metadata` no és un objecte JSON (o conté un caràcter NUL)'
                  value:
                    metadata:
                      - Metadata must be a JSON object.
                Oversized vendor_data:
                  summary: '`vendor_data` supera el límit màxim de 2.000 bytes'
                  value:
                    vendor_data:
                      - vendor_data is too long (maximum 2000 bytes).
                Encrypted PDF:
                  summary: PDF protegit amb contrasenya
                  value:
                    error: >-
                      The PDF is encrypted. Please upload a decrypted PDF or a
                      photo instead.
                Extraction failed:
                  summary: El pipeline d'extracció no ha pogut processar el document
                  value:
                    error:
                      - Error extracting Document AI information
              schema:
                type: object
                additionalProperties: true
        '403':
          description: >-
            Permís denegat. Es retorna quan falta la capçalera `x-api-key`, i
            també quan el saldo de l'organització que fa la crida no pot cobrir
            la crida; una clau incorrecta, revocada o caducada retorna `401`. Si
            falta la clau es retorna `403` amb `{"detail": ...}`; una clau
            incorrecta, revocada o caducada retorna `401`. La manca de crèdit —i
            les organitzacions facturades per contracte la taula de tarifes de
            les quals no té cap entrada per a l'API de Document AI— retornen
            `403` amb `{"error": ...}` abans que es produeixi cap processament
            de documents.
          content:
            application/json:
              examples:
                Missing or invalid API key:
                  summary: >-
                    Sense capçalera `x-api-key`, o la clau no és vàlida/s'ha
                    revocat
                  value:
                    detail: You do not have permission to perform this action.
                Not enough credits:
                  summary: El saldo de l'organització no pot cobrir la crida
                  value:
                    error: >-
                      You don't have enough credits to perform this request.
                      Please top up at https://business.didit.me
                Contract rate missing:
                  summary: >-
                    Organització facturada per contracte la taula de tarifes de
                    la qual no té cap entrada per a l'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: >-
            S'ha superat el límit de freqüència. Els endpoints POST/PATCH/DELETE
            comparteixen un pressupost de 300 sol·licituds d'escriptura per
            minut per clau d'API (la creació de transaccions i la ingesta
            d'esdeveniments tenen un pressupost independent de 600). La resposta
            inclou les capçaleres `X-RateLimit-Limit`, `X-RateLimit-Remaining`,
            `X-RateLimit-Reset` i `Retry-After`.
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: Més de 300 sol·licituds d'escriptura en el minut actual
                  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: >-
            Simbologia detectada, per exemple `QR_CODE`, `CODE_128`, `EAN_13`,
            `DATA_MATRIX` o `PDF_417`.
        page_number:
          type: integer
          minimum: 1
          description: Número de pàgina, començant per 1.
        position:
          type: array
          nullable: true
          description: >-
            Polígon detectat en coordenades de píxels de la pàgina renderitzada.
            `null` quan no hi ha cap ubicació fiable disponible.
          items:
            type: array
            minItems: 2
            maxItems: 2
            items:
              type: integer
        x:
          type: integer
          nullable: true
          description: >-
            Vora esquerra del quadre delimitador en píxels de la pàgina
            renderitzada.
        'y':
          type: integer
          nullable: true
          description: >-
            Vora superior del quadre delimitador en píxels de la pàgina
            renderitzada.
        width:
          type: integer
          nullable: true
          description: Amplària del quadre delimitador en píxels de la pàgina renderitzada.
        height:
          type: integer
          nullable: true
          description: Alçària del quadre delimitador en píxels de la pàgina renderitzada.
        page_width:
          type: integer
          description: Amplària de la pàgina renderitzada en píxels.
        page_height:
          type: integer
          description: Alçària de la pàgina renderitzada en píxels.
        raw_payload:
          type: string
          description: >-
            Payload del descodificador en brut com a cadena en base64 quan
            estigui disponible; en cas contrari, una cadena buida.
        parsed_payload:
          nullable: true
          description: >-
            Cadena descodificada o valor estructurat. `null` quan el codi s'ha
            localitzat però no s'ha pogut descodificar.
  responses:
    DocumentProcessingBusy:
      description: >-
        Ara mateix s'estan processant massa documents, de manera que aquesta
        càrrega no s'ha processat: no s'ha emmagatzemat res i no s'ha consumit
        cap intent. Torna a enviar el mateix fitxer després del nombre de segons
        indicat a `Retry-After`. Bifurca segons `code`, no segons el text del
        missatge.
      headers:
        Retry-After:
          description: >-
            Nombre de segons que cal esperar abans de tornar a enviar la mateixa
            sol·licitud.
          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: >-
        La clau d'API de la teva aplicació, des de Developers -> API keys a la
        Business Console. La clau primària té accés complet. Una clau amb nom
        pot tenir l'abast limitat: cap, lectura o escriptura per recurs,
        limitada a determinats fluxos de treball o a sessions aprovades, a una
        llista d'adreces IP i a una data de caducitat. 401 significa que la clau
        és incorrecta, revocada o caducada; 403 significa que no s'ha enviat cap
        clau, que la clau no té accés a aquest recurs o acció, o que la
        sol·licitud prové d'una adreça fora de la seva llista d'IP; 404 en una
        ruta de sessió significa que la sessió està fora dels fluxos de treball
        o estats de la clau. Una clau sense accés a fitxers multimèdia rep els
        URL d'imatge, vídeo i PDF com a null, i una clau sense permís
        d'escriptura de sessions rep els enllaços de sessió i els tokens com a
        null. Consulta https://docs.didit.me/console/api-keys.

````

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