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

# ID Verification API

> OCR an identity document and run document fraud checks in one call — returns the extracted holder fields, the parsed MRZ, an `Approved`/`Declined` `status`, and a `warnings` list explaining every issue found. Supports 14,000+ document types from 220+ countries and territories.

**How it works.** Send the document's `front_image` (required) and, for two-sided documents, the `back_image`. Upload uncropped photos with all four corners of the document visible — the service detects, aligns, and crops the document itself, so do not pre-crop. The document is classified automatically (you never declare the country or document type), the visual zone is read with OCR, and the MRZ and any barcodes are decoded. Cross-checks then validate dates, number formats, and MRZ check digits, and compare the visual zone against the MRZ. With `perform_document_liveness=true`, the images are additionally screened for screen replays, printed copies, and portrait manipulation.

**Decision logic.** `status` is `Approved` unless at least one warning resolves to a decline. Fraud and hard-failure risks always decline: `DOCUMENT_EXPIRED`, `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`, `PORTRAIT_MANIPULATION_DETECTED`, plus extraction failures (`NAME_NOT_DETECTED`, `DATE_OF_BIRTH_NOT_DETECTED`, `DOCUMENT_NUMBER_NOT_DETECTED`). (`PORTRAIT_IMAGE_NOT_DETECTED`, `COULD_NOT_DETECT_DOCUMENT_TYPE`, `INVALID_DATE`, and `MRZ_NOT_DETECTED` exist in workflow sessions but are never produced by this standalone endpoint.) Three risk groups are configurable per request via `invalid_mrz_action`, `inconsistent_data_action`, and `expiration_date_not_detected_action` (`DECLINE` or `NO_ACTION`). All other warnings (e.g. `POSSIBLE_DUPLICATED_USER`) are informational and never decline on their own. A document that cannot be processed at all returns `400` with `{"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}`; a readable but problematic document returns `200` with `status: "Declined"` — always inspect `id_verification.status` and `id_verification.warnings`, not just the HTTP code.

**Billing.** Each `200` response consumes one ID Verification API credit (standalone APIs have no free tier). When the organization's balance cannot cover the call, the endpoint returns `403` with the not-enough-credits error before any image processing.

**Session persistence (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session: it appears in the Business Console, the returned `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/`, the cropped document/portrait images are stored and returned as short-lived media URLs (`https://<media-host>/ocr/...`), and a `status.updated` webhook is emitted to your configured webhook endpoints. When `false`, nothing is stored, `request_id` is a one-off correlation UUID, and `portrait_image`/`front_image`/`back_image` are returned inline as base64-encoded JPEG strings.

**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload (a fictional "Sandbox User" USA identity card), no session is persisted, and no credits are consumed.

**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{"detail": "You do not have permission to perform this action."}`) — this API never returns `401`.

**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.



## OpenAPI

````yaml POST /v3/id-verification/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/id-verification/:
    post:
      tags:
        - Standalone APIs
      summary: ID Verification (document OCR + fraud checks)
      description: >-
        OCR an identity document and run document fraud checks in one call —
        returns the extracted holder fields, the parsed MRZ, an
        `Approved`/`Declined` `status`, and a `warnings` list explaining every
        issue found. Supports 14,000+ document types from 220+ countries and
        territories.


        **How it works.** Send the document's `front_image` (required) and, for
        two-sided documents, the `back_image`. Upload uncropped photos with all
        four corners of the document visible — the service detects, aligns, and
        crops the document itself, so do not pre-crop. The document is
        classified automatically (you never declare the country or document
        type), the visual zone is read with OCR, and the MRZ and any barcodes
        are decoded. Cross-checks then validate dates, number formats, and MRZ
        check digits, and compare the visual zone against the MRZ. With
        `perform_document_liveness=true`, the images are additionally screened
        for screen replays, printed copies, and portrait manipulation.


        **Decision logic.** `status` is `Approved` unless at least one warning
        resolves to a decline. Fraud and hard-failure risks always decline:
        `DOCUMENT_EXPIRED`, `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`,
        `PORTRAIT_MANIPULATION_DETECTED`, plus extraction failures
        (`NAME_NOT_DETECTED`, `DATE_OF_BIRTH_NOT_DETECTED`,
        `DOCUMENT_NUMBER_NOT_DETECTED`). (`PORTRAIT_IMAGE_NOT_DETECTED`,
        `COULD_NOT_DETECT_DOCUMENT_TYPE`, `INVALID_DATE`, and `MRZ_NOT_DETECTED`
        exist in workflow sessions but are never produced by this standalone
        endpoint.) Three risk groups are configurable per request via
        `invalid_mrz_action`, `inconsistent_data_action`, and
        `expiration_date_not_detected_action` (`DECLINE` or `NO_ACTION`). All
        other warnings (e.g. `POSSIBLE_DUPLICATED_USER`) are informational and
        never decline on their own. A document that cannot be processed at all
        returns `400` with `{"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}`; a
        readable but problematic document returns `200` with `status:
        "Declined"` — always inspect `id_verification.status` and
        `id_verification.warnings`, not just the HTTP code.


        **Billing.** Each `200` response consumes one ID Verification API credit
        (standalone APIs have no free tier). When the organization's balance
        cannot cover the call, the endpoint returns `403` with the
        not-enough-credits error before any image processing.


        **Session persistence (`save_api_request`, default `true`).** When
        `true`, the call is persisted as an API-type session: it appears in the
        Business Console, the returned `request_id` is a real session id you can
        pass to `GET /v3/session/{sessionId}/decision/`, the cropped
        document/portrait images are stored and returned as short-lived media
        URLs (`https://<media-host>/ocr/...`), and a `status.updated` webhook is
        emitted to your configured webhook endpoints. When `false`, nothing is
        stored, `request_id` is a one-off correlation UUID, and
        `portrait_image`/`front_image`/`back_image` are returned inline as
        base64-encoded JPEG strings.


        **Sandbox.** Sandbox API keys skip all processing and billing: after
        request validation (malformed input still returns `400`), the endpoint
        returns a static `Approved` mock payload (a fictional "Sandbox User" USA
        identity card), no session is persisted, and no credits are consumed.


        **Authentication.** Send your application's API key in the `x-api-key`
        header. Missing or invalid credentials return `403` (`{"detail": "You do
        not have permission to perform this action."}`) — this API never returns
        `401`.


        **Rate limit.** Shared write budget of 300 requests/min per API key
        across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.
      operationId: post_v3id-verification
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - front_image
              properties:
                front_image:
                  type: string
                  format: binary
                  description: >-
                    Front side of the identity document. Allowed extensions:
                    `tiff`, `jpg`, `jpeg`, `png`, `webp`, `pdf`. Maximum upload
                    size: **10 MB** (larger files are rejected with `400`). PDFs
                    are rendered to an image before OCR; encrypted PDFs require
                    `front_image_password`. Images are automatically compressed
                    to ~0.5 MB and EXIF orientation is applied. Upload the full,
                    uncropped capture with all four corners of the document
                    visible.
                front_image_password:
                  type: string
                  description: >-
                    Password to decrypt `front_image` when it is an encrypted
                    PDF. Sending an encrypted PDF without (or with a wrong)
                    password returns `400`.
                  writeOnly: true
                back_image:
                  type: string
                  format: binary
                  description: >-
                    Back side of the document — send it whenever the document
                    has one (many ID cards carry the MRZ or a barcode on the
                    back; omitting it simply leaves the MRZ and back-side fields
                    empty in the response — this endpoint does not raise a
                    missing-MRZ warning). Same format and size limits as
                    `front_image`. When omitted, `back_image` and back-side
                    fields are `null` in the response.
                back_image_password:
                  type: string
                  description: >-
                    Password to decrypt `back_image` when it is an encrypted
                    PDF.
                  writeOnly: true
                perform_document_liveness:
                  type: boolean
                  default: false
                  description: >-
                    When `true`, also screens both images for presentation
                    fraud: screen replays (`SCREEN_CAPTURE_DETECTED`), printed
                    copies (`PRINTED_COPY_DETECTED`), and portrait manipulation
                    (`PORTRAIT_MANIPULATION_DETECTED`). Any of these
                    auto-declines. Adds latency, so enable it only when you need
                    fraud screening.
                  example: true
                minimum_age:
                  type: integer
                  nullable: true
                  default: null
                  minimum: 1
                  maximum: 120
                  description: >-
                    Accepted and validated (1–120) but **currently not applied**
                    by this endpoint — it never produces a `MINIMUM_AGE_NOT_MET`
                    warning from this field. Enforce age rules from the returned
                    `date_of_birth`/`age`, or use a verification-session
                    workflow with age restrictions.
                expiration_date_not_detected_action:
                  type: string
                  enum:
                    - NO_ACTION
                    - DECLINE
                  default: NO_ACTION
                  description: >-
                    What to do when no expiration date can be read
                    (`EXPIRATION_DATE_NOT_DETECTED`). Default `NO_ACTION`
                    because many identity documents print no expiry date. Note:
                    a *detected and past* expiry date always declines
                    (`DOCUMENT_EXPIRED`), regardless of this option.
                invalid_mrz_action:
                  type: string
                  enum:
                    - NO_ACTION
                    - DECLINE
                  default: DECLINE
                  description: >-
                    What to do when the extracted MRZ fails check-digit
                    validation (`MRZ_VALIDATION_FAILED`). A missing MRZ raises
                    no warning on this endpoint. Only relevant for documents
                    that carry an MRZ. `REVIEW` is not supported on this
                    endpoint and returns `400`.
                inconsistent_data_action:
                  type: string
                  enum:
                    - NO_ACTION
                    - DECLINE
                  default: DECLINE
                  description: >-
                    What to do when extracted data is internally inconsistent:
                    `DATA_INCONSISTENT`,
                    `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` (visual zone
                    disagrees with the MRZ), or
                    `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS`.
                preferred_characters:
                  type: string
                  enum:
                    - latin
                    - non_latin
                  default: latin
                  description: >-
                    Preferred script for name/address fields on documents that
                    print both Latin and non-Latin text (Arabic, Cyrillic, CJK,
                    …). `latin` returns transliterated/Latin values; `non_latin`
                    prefers the native script.
                save_api_request:
                  type: boolean
                  default: true
                  description: >-
                    When `true` (default), persists the call as an API-type
                    session — visible in the Business Console, retrievable via
                    `GET /v3/session/{sessionId}/decision/` using the returned
                    `request_id`, announced through a `status.updated` webhook,
                    and with document images returned as media URLs. When
                    `false`, nothing is stored, `request_id` is a transient
                    UUID, and images are returned inline as base64 JPEG strings.
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    Optional opaque string (your internal user id, email, UUID…)
                    stored on the persisted session and echoed back in the
                    response. Use it to correlate API calls with your own
                    records and to filter sessions later.
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    Optional JSON object stored with the session (when
                    `save_api_request=true`) and echoed back in the response. In
                    multipart requests, send it as a JSON-encoded string field
                    (e.g. `metadata={"flow":"onboarding"}`) — it is parsed into
                    an object.
                  example:
                    flow: onboarding
            example:
              front_image: (binary JPEG/PNG/PDF of the document front)
              back_image: (binary JPEG/PNG/PDF of the document back)
              perform_document_liveness: true
              save_api_request: true
              vendor_data: user-123
              metadata:
                flow: onboarding
      responses:
        '200':
          description: >-
            Document processed. `id_verification.status` is `Approved` or
            `Declined`; every detected issue is itemized in
            `id_verification.warnings`. A problematic document still returns
            `200` with `status: "Declined"` — inspect the body, not just the
            HTTP code. When `save_api_request=true`, `request_id` is the
            persisted session id and image fields are short-lived media URLs;
            with `save_api_request=false` they are inline base64 JPEG strings.
          content:
            application/json:
              examples:
                Approved:
                  summary: >-
                    Two-sided ID card read cleanly (saved — images as media
                    URLs)
                  value:
                    request_id: 11d219ed-d59c-4b1d-8d65-9b933f12d5b8
                    id_verification:
                      status: Approved
                      document_type: Identity Card
                      document_subtype: ID_CARD_GENERIC
                      document_number: CBX164224
                      personal_number: 20446581H
                      portrait_image: >-
                        https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-portrait_image-8c2f.jpg?signature=...
                      front_image: >-
                        https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-front_image-4a1e.jpg?signature=...
                      back_image: >-
                        https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-back_image-77b0.jpg?signature=...
                      front_image_camera_front: null
                      back_image_camera_front: null
                      front_image_camera_front_face_match_score: null
                      back_image_camera_front_face_match_score: null
                      front_image_quality_score:
                        focus_score: 78
                        brightness_score: 83.2
                        brightness_issue: ok
                        is_document_fully_visible: true
                        resolution_score: 40.7
                        overall_score: 70.2
                      back_image_quality_score:
                        focus_score: 100
                        brightness_score: 95.6
                        brightness_issue: ok
                        is_document_fully_visible: true
                        resolution_score: 43
                        overall_score: 84.4
                      date_of_birth: '1980-01-13'
                      age: 46
                      expiration_date: '2032-03-31'
                      date_of_issue: '2022-03-31'
                      issuing_state: ESP
                      issuing_state_name: Spain
                      first_name: Julio Francisco
                      last_name: Fores Sena
                      full_name: Julio Francisco Fores Sena
                      gender: M
                      address: >-
                        Brda. Urb. El Cardonal 0052 52 Po3 B,Taco,San Cristobal
                        De La Laguna,Santa Cruz De Tenerife
                      formatted_address: >-
                        Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de
                        Tenerife, Spain
                      place_of_birth: Valencia, Valencia
                      marital_status: UNKNOWN
                      nationality: ESP
                      extra_fields:
                        first_surname: Fores
                        second_surname: Sena
                      mrz:
                        surname: FORES SENA
                        name: JULIO FRANCISCO
                        country: ESP
                        nationality: ESP
                        birth_date: '800113'
                        expiry_date: '320331'
                        sex: M
                        document_type: ID
                        document_number: CBX164224
                        optional_data: 20446581H
                        optional_data_2: ''
                        birth_date_hash: '9'
                        expiry_date_hash: '8'
                        document_number_hash: '3'
                        final_hash: '3'
                        personal_number: 20446581H
                        warnings: []
                        errors: []
                        mrz_type: TD1
                        mrz_string: |-
                          IDESPCBX164224320446581H<<<<<<
                          8001139M3203318ESP<<<<<<<<<<<3
                          FORES<SENA<<JULIO<FRANCISCO<<<
                        mrz_key: CBX164224380011393203318
                      parsed_address:
                        street_1: Avenida el Cardonal 52
                        street_2: b
                        city: La Laguna
                        region: Canarias
                        country: ES
                        postal_code: '38108'
                        address_type: Avenida
                        formatted_address: >-
                          Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de
                          Tenerife, Spain
                        raw_results:
                          address_components:
                            - long_name: b
                              short_name: b
                              types:
                                - subpremise
                            - long_name: '52'
                              short_name: '52'
                              types:
                                - street_number
                            - long_name: Avenida el Cardonal
                              short_name: Av. el Cardonal
                              types:
                                - route
                            - long_name: La Laguna
                              short_name: La Laguna
                              types:
                                - locality
                                - political
                            - long_name: Spain
                              short_name: ES
                              types:
                                - country
                                - political
                            - long_name: '38108'
                              short_name: '38108'
                              types:
                                - postal_code
                          formatted_address: >-
                            Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz
                            de Tenerife, Spain
                          geometry:
                            location:
                              lat: 28.4501161
                              lng: -16.3004407
                            location_type: ROOFTOP
                          types:
                            - street_address
                            - subpremise
                        document_location:
                          latitude: 28.4501161
                          longitude: -16.3004407
                        label: Spain Identity Card Address
                        is_verified: true
                        category: Residential
                      warnings: []
                      barcodes: []
                    vendor_data: user-123
                    metadata:
                      flow: onboarding
                    created_at: '2026-06-12T02:21:56.013573+00:00'
                Declined - expired document:
                  summary: Front-only upload of an expired ID card
                  value:
                    request_id: f61681b8-9422-4378-ac3e-04c6a247fb45
                    id_verification:
                      status: Declined
                      document_type: Identity Card
                      document_subtype: ID_CARD_GENERIC
                      document_number: BNK123072
                      personal_number: 21771255F
                      portrait_image: >-
                        https://<media-host>/ocr/f61681b8-9422-4378-ac3e-04c6a247fb45-portrait_image-1d9a.jpg?signature=...
                      front_image: >-
                        https://<media-host>/ocr/f61681b8-9422-4378-ac3e-04c6a247fb45-front_image-5c2b.jpg?signature=...
                      back_image: null
                      front_image_camera_front: null
                      back_image_camera_front: null
                      front_image_camera_front_face_match_score: null
                      back_image_camera_front_face_match_score: null
                      front_image_quality_score:
                        focus_score: 100
                        brightness_score: 95.7
                        brightness_issue: ok
                        is_document_fully_visible: true
                        resolution_score: 22.2
                        overall_score: 79.3
                      back_image_quality_score: null
                      date_of_birth: '1997-01-30'
                      age: 29
                      expiration_date: '2025-11-26'
                      date_of_issue: null
                      issuing_state: ESP
                      issuing_state_name: Spain
                      first_name: Lucia
                      last_name: Marin Castro
                      full_name: Lucia Marin Castro
                      gender: F
                      address: null
                      formatted_address: null
                      place_of_birth: null
                      marital_status: UNKNOWN
                      nationality: ESP
                      extra_fields:
                        first_surname: Marin
                        second_surname: Castro
                      mrz: {}
                      parsed_address: null
                      warnings:
                        - risk: DOCUMENT_EXPIRED
                          feature: ID_VERIFICATION
                          additional_data: null
                          log_type: error
                          short_description: Document expired
                          long_description: >-
                            The document's expiration date has passed, rendering
                            it no longer valid for use.
                      barcodes: []
                    vendor_data: user-123
                    metadata: null
                    created_at: '2026-06-12T02:25:48.117204+00:00'
              schema:
                type: object
                properties:
                  request_id:
                    type: string
                    format: uuid
                    description: >-
                      Persisted session id when `save_api_request=true` (usable
                      with `GET /v3/session/{sessionId}/decision/`); otherwise a
                      transient correlation UUID.
                  id_verification:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                        description: >-
                          `Approved` when no warning resolves to a decline;
                          `Declined` otherwise — the `warnings` list explains
                          why.
                      document_type:
                        type: string
                        nullable: true
                        description: >-
                          Detected document type display name: `Identity Card`,
                          `Passport`, `Driver's License`, `Residence Permit`,
                          `Health Insurance Card`, or `Tax Card`. `null` when
                          the document could not be classified.
                        example: Identity Card
                      document_subtype:
                        type: string
                        nullable: true
                        description: >-
                          Finer-grained subtype when available (e.g.
                          `ID_CARD_GENERIC`, `EPASSPORT`).
                        example: ID_CARD_GENERIC
                      document_number:
                        type: string
                        nullable: true
                        example: CBX164224
                      personal_number:
                        type: string
                        nullable: true
                        description: >-
                          Secondary personal/national number printed on some
                          documents.
                        example: 20446581H
                      portrait_image:
                        type: string
                        nullable: true
                        description: >-
                          Cropped portrait photo from the document. A
                          short-lived media URL (`https://<media-host>/ocr/...`)
                          when `save_api_request=true` (default); an inline
                          base64-encoded JPEG string when
                          `save_api_request=false`. `null` when no portrait was
                          detected.
                      front_image:
                        type: string
                        nullable: true
                        description: >-
                          Aligned crop of the document front. Media URL when
                          saved, inline base64 JPEG otherwise.
                      back_image:
                        type: string
                        nullable: true
                        description: >-
                          Aligned crop of the document back. `null` when no
                          `back_image` was uploaded.
                      front_image_camera_front:
                        type: string
                        nullable: true
                        description: >-
                          Always `null` on this endpoint (populated only in
                          camera-capture verification sessions).
                      back_image_camera_front:
                        type: string
                        nullable: true
                        description: Always `null` on this endpoint.
                      front_image_camera_front_face_match_score:
                        type: number
                        nullable: true
                        description: Always `null` on this endpoint.
                      back_image_camera_front_face_match_score:
                        type: number
                        nullable: true
                        description: Always `null` on this endpoint.
                      front_image_quality_score:
                        type: object
                        nullable: true
                        description: >-
                          Capture-quality diagnostics for the uploaded image
                          (`null` when the side was not provided or scoring
                          failed). All scores are 0–100.
                        properties:
                          focus_score:
                            type: number
                            format: float
                            description: >-
                              Sharpness of the document crop (higher is
                              sharper).
                          brightness_score:
                            type: number
                            format: float
                            description: Exposure quality (higher is better).
                          brightness_issue:
                            type: string
                            nullable: true
                            description: >-
                              `ok` when exposure is fine, otherwise the detected
                              issue (e.g. too dark / too bright).
                          is_document_fully_visible:
                            type: boolean
                            nullable: true
                            description: >-
                              Whether all four corners of the document are
                              inside the frame.
                          resolution_score:
                            type: number
                            format: float
                            description: Effective resolution of the document area.
                          overall_score:
                            type: number
                            format: float
                            description: Aggregate quality score.
                      back_image_quality_score:
                        type: object
                        nullable: true
                        description: >-
                          Capture-quality diagnostics for the uploaded image
                          (`null` when the side was not provided or scoring
                          failed). All scores are 0–100.
                        properties:
                          focus_score:
                            type: number
                            format: float
                            description: >-
                              Sharpness of the document crop (higher is
                              sharper).
                          brightness_score:
                            type: number
                            format: float
                            description: Exposure quality (higher is better).
                          brightness_issue:
                            type: string
                            nullable: true
                            description: >-
                              `ok` when exposure is fine, otherwise the detected
                              issue (e.g. too dark / too bright).
                          is_document_fully_visible:
                            type: boolean
                            nullable: true
                            description: >-
                              Whether all four corners of the document are
                              inside the frame.
                          resolution_score:
                            type: number
                            format: float
                            description: Effective resolution of the document area.
                          overall_score:
                            type: number
                            format: float
                            description: Aggregate quality score.
                      date_of_birth:
                        type: string
                        format: date
                        nullable: true
                        example: '1980-01-13'
                      age:
                        type: integer
                        nullable: true
                        description: Holder age in years, computed from `date_of_birth`.
                        example: 46
                      expiration_date:
                        type: string
                        format: date
                        nullable: true
                        example: '2032-03-31'
                      date_of_issue:
                        type: string
                        format: date
                        nullable: true
                        example: '2022-03-31'
                      issuing_state:
                        type: string
                        nullable: true
                        description: Issuing country (ISO 3166-1 alpha-3).
                        example: ESP
                      issuing_state_name:
                        type: string
                        nullable: true
                        example: Spain
                      first_name:
                        type: string
                        nullable: true
                        example: Julio Francisco
                      last_name:
                        type: string
                        nullable: true
                        example: Fores Sena
                      full_name:
                        type: string
                        nullable: true
                        example: Julio Francisco Fores Sena
                      gender:
                        type: string
                        nullable: true
                        description: '`M`, `F`, or `null` when not printed/detected.'
                        example: M
                      address:
                        type: string
                        nullable: true
                        description: Address exactly as printed on the document.
                      formatted_address:
                        type: string
                        nullable: true
                        description: Geocoded, normalized version of `address`.
                      place_of_birth:
                        type: string
                        nullable: true
                        example: Valencia, Valencia
                      marital_status:
                        type: string
                        nullable: true
                        description: '`UNKNOWN` unless the document prints marital status.'
                        example: UNKNOWN
                      nationality:
                        type: string
                        nullable: true
                        description: Holder nationality (ISO 3166-1 alpha-3).
                        example: ESP
                      extra_fields:
                        type: object
                        nullable: true
                        additionalProperties: true
                        description: >-
                          Document-specific extras that have no dedicated column
                          (e.g. `first_surname`/`second_surname` on Spanish IDs,
                          license classes on driving licenses).
                      mrz:
                        type: object
                        description: >-
                          Parsed machine-readable zone. An **empty object**
                          (`{}`) when the document has no MRZ or it could not be
                          read — also check the `warnings` list in that case.
                          Dates inside the MRZ use the raw `YYMMDD` format.
                        properties:
                          surname:
                            type: string
                            example: FORES SENA
                          name:
                            type: string
                            example: JULIO FRANCISCO
                          country:
                            type: string
                            description: Issuing country (ISO 3166-1 alpha-3).
                            example: ESP
                          nationality:
                            type: string
                            description: Holder nationality (ISO 3166-1 alpha-3).
                            example: ESP
                          birth_date:
                            type: string
                            description: Raw MRZ date of birth (`YYMMDD`).
                            example: '800113'
                          expiry_date:
                            type: string
                            description: Raw MRZ expiry date (`YYMMDD`).
                            example: '320331'
                          sex:
                            type: string
                            example: M
                          document_type:
                            type: string
                            description: MRZ document-type code (e.g. `ID`, `P`).
                            example: ID
                          document_number:
                            type: string
                            example: CBX164224
                          optional_data:
                            type: string
                            nullable: true
                            example: 20446581H
                          optional_data_2:
                            type: string
                            nullable: true
                            example: ''
                          birth_date_hash:
                            type: string
                            description: MRZ check digit for the birth date.
                            example: '9'
                          expiry_date_hash:
                            type: string
                            description: MRZ check digit for the expiry date.
                            example: '8'
                          document_number_hash:
                            type: string
                            description: MRZ check digit for the document number.
                            example: '3'
                          final_hash:
                            type: string
                            description: Composite MRZ check digit.
                            example: '3'
                          personal_number:
                            type: string
                            nullable: true
                            example: 20446581H
                          warnings:
                            type: array
                            items:
                              type: string
                            description: Non-fatal MRZ parsing warnings.
                          errors:
                            type: array
                            items:
                              type: string
                            description: >-
                              MRZ check-digit/parsing errors. Non-empty errors
                              surface as an `MRZ_VALIDATION_FAILED` warning.
                          mrz_type:
                            type: string
                            description: >-
                              MRZ layout: `TD1` (ID cards, 3 lines), `TD2`, or
                              `TD3` (passports, 2 lines).
                            example: TD1
                          mrz_string:
                            type: string
                            description: Raw MRZ text as read, lines separated by `\n`.
                          mrz_key:
                            type: string
                            description: >-
                              Composite key (document number + check digits)
                              used for cross-checks.
                      parsed_address:
                        type: object
                        nullable: true
                        description: >-
                          Structured, geocoded breakdown of `address`. `null`
                          when the document carries no address or it could not
                          be parsed.
                        properties:
                          street_1:
                            type: string
                            nullable: true
                            example: Avenida el Cardonal 52
                          street_2:
                            type: string
                            nullable: true
                            example: b
                          city:
                            type: string
                            nullable: true
                            example: La Laguna
                          region:
                            type: string
                            nullable: true
                            example: Canarias
                          country:
                            type: string
                            nullable: true
                            description: ISO 3166-1 alpha-2 country code.
                            example: ES
                          postal_code:
                            type: string
                            nullable: true
                            example: '38108'
                          address_type:
                            type: string
                            nullable: true
                            example: Avenida
                          formatted_address:
                            type: string
                            nullable: true
                            description: Canonical geocoded address string.
                            example: >-
                              Av. el Cardonal, 52, b, 38108 La Laguna, Santa
                              Cruz de Tenerife, Spain
                          raw_results:
                            type: object
                            additionalProperties: true
                            description: >-
                              Raw geocoding payload (`address_components`,
                              `geometry.location`, `place_id`, …) for advanced
                              consumers.
                          document_location:
                            type: object
                            nullable: true
                            properties:
                              latitude:
                                type: number
                              longitude:
                                type: number
                            description: Geocoded coordinates of the document address.
                          label:
                            type: string
                            nullable: true
                            description: Which document field the address was read from.
                            example: Spain Identity Card Address
                          is_verified:
                            type: boolean
                            description: Whether geocoding confirmed the address exists.
                          category:
                            type: string
                            nullable: true
                            description: >-
                              Address category (e.g. `Residential`,
                              `Commercial`).
                            example: Residential
                      warnings:
                        type: array
                        description: >-
                          Empty on a clean approval. Every entry explains one
                          detected risk; entries with `log_type: "error"` set
                          `status` to `Declined`.
                        items:
                          type: object
                          properties:
                            risk:
                              type: string
                              description: >-
                                Machine-readable risk code. Always-decline
                                risks: `DOCUMENT_EXPIRED`,
                                `MINIMUM_AGE_NOT_MET`,
                                `PORTRAIT_IMAGE_NOT_DETECTED`,
                                `SCREEN_CAPTURE_DETECTED`,
                                `PRINTED_COPY_DETECTED`,
                                `PORTRAIT_MANIPULATION_DETECTED`,
                                `INVALID_DATE`, `COULD_NOT_RECOGNIZE_DOCUMENT`
                                (400-only, never a warning),
                                `DOCUMENT_NUMBER_NOT_DETECTED`,
                                `COULD_NOT_DETECT_DOCUMENT_TYPE`,
                                `NAME_NOT_DETECTED`,
                                `DATE_OF_BIRTH_NOT_DETECTED`. Governed by
                                request options: `MRZ_NOT_DETECTED` /
                                `MRZ_VALIDATION_FAILED` (`invalid_mrz_action`),
                                `DATA_INCONSISTENT` /
                                `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` /
                                `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS`
                                (`inconsistent_data_action`),
                                `EXPIRATION_DATE_NOT_DETECTED`
                                (`expiration_date_not_detected_action`). Other
                                risks (e.g. `POSSIBLE_DUPLICATED_USER`) are
                                informational.
                              example: DOCUMENT_EXPIRED
                            feature:
                              type: string
                              enum:
                                - ID_VERIFICATION
                              description: >-
                                Feature that raised the warning. Always
                                `ID_VERIFICATION` on this endpoint.
                            additional_data:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: >-
                                Extra context for some risks (e.g.
                                `POSSIBLE_DUPLICATED_USER` includes
                                `duplicated_session_id`); `null` for most.
                            log_type:
                              type: string
                              enum:
                                - error
                                - warning
                                - information
                              description: >-
                                Severity. `error` warnings drive `status` to
                                `Declined`; `information` entries are advisory
                                and never decline on their own. (`warning` is
                                not produced by this endpoint — its options only
                                accept `DECLINE` or `NO_ACTION`.)
                            short_description:
                              type: string
                              description: Human-readable one-line summary of the risk.
                            long_description:
                              type: string
                              description: Human-readable explanation of the risk.
                      barcodes:
                        type: array
                        description: >-
                          Barcodes decoded from the document (PDF417, QR, …).
                          Empty when the document has none or none could be
                          read.
                        items:
                          type: object
                          properties:
                            type:
                              type: string
                              description: >-
                                Barcode type (e.g. `PDF417`, `QR_CODE`,
                                `UNKNOWN`).
                            position:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: >-
                                Location of the barcode in the image, when
                                available.
                            data:
                              type: string
                              description: Decoded payload.
                            data_raw:
                              type: string
                              description: Raw (undecoded) payload, when different.
                            side:
                              type: string
                              nullable: true
                              description: '`front` or `back`.'
                  vendor_data:
                    type: string
                    nullable: true
                    description: Echo of the `vendor_data` you sent, or `null`.
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: Echo of the `metadata` object you sent, or `null`.
                  created_at:
                    type: string
                    format: date-time
                    description: >-
                      ISO 8601 timestamp (UTC) of when the response was
                      generated.
        '400':
          description: >-
            Validation or processing error. Field-level problems return DRF's
            standard envelope (one array of messages per offending field).
            Encrypted-PDF problems return `{"detail": ...}`. A document image in
            which no document can be recognized at all returns `{"error":
            "COULD_NOT_RECOGNIZE_DOCUMENT"}`. PDF uploads can additionally fail
            with "The submitted PDF file is corrupted or invalid." or a no-pages
            error.
          content:
            application/json:
              examples:
                Missing front image:
                  summary: '`front_image` not included in the form data'
                  value:
                    front_image:
                      - No file was submitted.
                Unsupported file extension:
                  summary: File extension outside tiff/jpg/jpeg/png/webp/pdf
                  value:
                    front_image:
                      - >-
                        File extension “txt” is not allowed. Allowed extensions
                        are: tiff, jpg, jpeg, png, webp, pdf.
                File too large:
                  summary: Upload exceeds the 10 MB limit
                  value:
                    front_image:
                      - File size should not exceed 10 MB
                Invalid option value:
                  summary: Options only accept DECLINE or NO_ACTION
                  value:
                    invalid_mrz_action:
                      - '"REVIEW" is not a valid choice.'
                Encrypted PDF:
                  summary: PDF uploaded without the required password
                  value:
                    detail: >-
                      The PDF is encrypted. Please upload a decrypted PDF or a
                      photo instead.
                Wrong PDF password:
                  summary: >-
                    `front_image_password` / `back_image_password` does not
                    decrypt the PDF
                  value:
                    detail: >-
                      The PDF password is incorrect. Please provide the correct
                      password.
                Document not recognized:
                  summary: No identity document could be detected in the image
                  value:
                    error: COULD_NOT_RECOGNIZE_DOCUMENT
                PDF conversion failure:
                  summary: Uploaded PDF could not be converted to an image
                  value:
                    error: Failed to convert front image PDF.
        '403':
          description: >-
            Permission denied. Returned when the `x-api-key` header is missing,
            malformed, revoked, or belongs to another environment — and also
            when the calling organization's balance cannot cover the call.
            Authentication failures return `403` with `{"detail": ...}`; this
            API never returns `401`. Credit shortfalls return `403` with
            `{"error": ...}` before any image processing happens.
          content:
            application/json:
              examples:
                Missing or invalid API key:
                  summary: No `x-api-key` header, or the key is invalid/revoked
                  value:
                    detail: You do not have permission to perform this action.
                Not enough credits:
                  summary: Organization balance cannot cover the call
                  value:
                    error: >-
                      You don't have enough credits to perform this request.
                      Please top up at https://business.didit.me
        '429':
          description: >-
            Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget
            of 300 write requests per minute per API key. The response carries
            `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`,
            and `Retry-After` headers.
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: More than 300 write requests in the current minute
                  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: curl
          label: cURL
          source: |-
            curl -X POST 'https://verification.didit.me/v3/id-verification/' \
              -H 'x-api-key: YOUR_API_KEY' \
              -F 'front_image=@./id_front.jpg' \
              -F 'back_image=@./id_back.jpg' \
              -F 'perform_document_liveness=true' \
              -F 'save_api_request=true' \
              -F 'vendor_data=user-123'
        - lang: python
          label: Python
          source: >-
            import requests


            url = 'https://verification.didit.me/v3/id-verification/'

            headers = {'x-api-key': 'YOUR_API_KEY'}


            with open('id_front.jpg', 'rb') as front_f, open('id_back.jpg',
            'rb') as back_f:
                files = {
                    'front_image': ('id_front.jpg', front_f, 'image/jpeg'),
                    'back_image': ('id_back.jpg', back_f, 'image/jpeg'),
                }
                data = {
                    'perform_document_liveness': 'true',
                    'save_api_request': 'true',
                    'vendor_data': 'user-123',
                }
                resp = requests.post(url, headers=headers, files=files, data=data, timeout=120)

            resp.raise_for_status()

            id_v = resp.json()['id_verification']

            print('status:', id_v['status'])

            print('name:', id_v.get('full_name'))

            print('document:', id_v.get('document_type'),
            id_v.get('document_number'))

            for w in id_v.get('warnings', []):
                print('warning:', w['risk'], '-', w['log_type'])
        - lang: javascript
          label: JavaScript
          source: >-
            import fs from 'node:fs';


            const form = new FormData();

            form.append('front_image', new
            Blob([fs.readFileSync('./id_front.jpg')]), 'id_front.jpg');

            form.append('back_image', new
            Blob([fs.readFileSync('./id_back.jpg')]), 'id_back.jpg');

            form.append('perform_document_liveness', 'true');

            form.append('save_api_request', 'true');

            form.append('vendor_data', 'user-123');


            const response = await
            fetch('https://verification.didit.me/v3/id-verification/', {
              method: 'POST',
              headers: { 'x-api-key': 'YOUR_API_KEY' },
              body: form,
            });


            if (!response.ok) throw new Error(`ID verification failed:
            ${response.status}`);

            const body = await response.json();

            console.log('status:', body.id_verification.status);

            console.log('warnings:', body.id_verification.warnings.map((w) =>
            w.risk));
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````