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

> Every warning Didit's ID verification module emits — auto-decline triggers, configurable risk groups, mismatch and tampering codes — with cause and remediation.

export const WarningTypes = () => <div style={{
  display: "flex",
  flexDirection: "column",
  gap: "12px",
  margin: "16px 0"
}}>
    {WARNING_TYPES.map(w => <div key={w.type} style={{
  display: "flex",
  alignItems: "flex-start",
  gap: "12px",
  padding: "12px 16px",
  borderRadius: "8px",
  background: w.bg
}}>
        <span style={{
  fontSize: "16px",
  lineHeight: "24px"
}}>{w.icon}</span>
        <div>
          <div style={{
  fontWeight: 600,
  color: w.color,
  marginBottom: "2px"
}}>
            <code style={{
  background: "transparent",
  color: w.color,
  fontWeight: 600,
  padding: 0
}}>
              {w.type}
            </code>
          </div>
          <div style={{
  fontSize: "14px",
  lineHeight: "20px",
  color: "#374151"
}}>
            {w.description}
          </div>
        </div>
      </div>)}
  </div>;

## Overview

Warnings on the ID verification report flag every condition Didit observed while reading and validating the document. They land in the `warnings[]` array on each item of `id_verifications[]` (see [ID verification report](/core-technology/id-verification/report-id-verification)), with the shape described in [Data models — Warning object](/reference/data-models#warning-object): `feature`, `risk`, `additional_data`, `log_type`, `short_description`, `long_description`, `node_id`.

Every warning has three layers:

1. **The `risk` code** — a stable identifier you can match on in your code.
2. **The `log_type`** — derived from the action your configuration assigns to the risk at evaluation time: **Decline → `error`**, **Review → `warning`**, anything else → `information`.
3. **The decision impact** — set by the workflow's configurable risk groups. The same `risk` code can be routed to **Approve**, **Review**, or **Decline** depending on how your application is configured.

## Auto-decline conditions

In workflows, the following risks always force the ID report (and the session) to `Declined`. They cannot be configured:

| Risk | Trigger |
| - | - |
| `DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` | The submitted document type is not on your application's allowed-documents list. `additional_data` includes `issuing_state`, `document_type`, `document_subtype`, `document_region`, and `document_region_with_subtype` so you can enable the exact document in your workflow. |
| `DOCUMENT_EXPIRED` | The document's expiration date has passed at capture time. |
| `PORTRAIT_IMAGE_NOT_DETECTED` | No portrait image could be located on the document. |
| `ID_DOCUMENT_IN_BLOCKLIST` | The document matches an entry on your application's blocklist. |
| `FRONT_CAMERA_FACE_IN_BLOCKLIST` | The selfie the front camera took during document capture matches a face in your face blocklist. |
| `AGE_BELOW_MINIMUM` | Adaptive age-verification workflows only: extracted age is below the minimum. |
| `AGE_NOT_DETECTED` | Adaptive age-verification workflows only: age could not be extracted from the document. |

For the **standalone OCR API**, the unconditional-decline set is `DOCUMENT_EXPIRED`, `MINIMUM_AGE_NOT_MET`, `PORTRAIT_IMAGE_NOT_DETECTED`, `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`, `PORTRAIT_MANIPULATION_DETECTED`, and `PUBLIC_DOCUMENT_IMAGE_DETECTED`. In workflows, minimum age is configurable (default Decline) and the three document-liveness risks are threshold-driven (see below).

That API returns only Approved or Declined, so its configurable risks take `DECLINE` or `NO_ACTION` rather than a Review verdict, as request parameters:

| Request parameter | Risks | Default |
| - | - | - |
| `invalid_mrz_action` | `MRZ_VALIDATION_FAILED`, `MRZ_NOT_DETECTED` | `DECLINE` |
| `inconsistent_data_action` | `DATA_INCONSISTENT`, `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME`, `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS` | `DECLINE` |
| `expiration_date_not_detected_action` | `EXPIRATION_DATE_NOT_DETECTED` | `NO_ACTION` |
| `critical_field_occlusion_action` | `CRITICAL_FIELD_OCCLUSION_DETECTED` | `DECLINE` |
| `document_or_personal_number_format_mismatch_action` | `DOCUMENT_NUMBER_FORMAT_MISMATCH`, `PERSONAL_NUMBER_FORMAT_MISMATCH` | `NO_ACTION` |

## Configurable verification settings

In the Didit console, the remaining ID risks are grouped into settings you can route to **Approve**, **Review**, or **Decline** (per workflow, and per node in graph workflows):

| Group | Risks | Default action |
| - | - | - |
| **Minimum Age** | `MINIMUM_AGE_NOT_MET` | Decline |
| **Maximum Age** | `MAXIMUM_AGE_EXCEEDED` | Decline |
| **Duplicated User** | `POSSIBLE_DUPLICATED_USER` (skipped when the document number is in your document allowlist) | Approve (information) |
| **Invalid Code** | `QR_NOT_DETECTED`, `BARCODE_NOT_DETECTED`, `QR_VALIDATION_FAILED`, `BARCODE_VALIDATION_FAILED` | Approve (information) |
| **Invalid MRZ** | `MRZ_VALIDATION_FAILED`, `MRZ_NOT_DETECTED` | Approve (information) |
| **Data Inconsistency** | `DATA_INCONSISTENT`, `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME`, `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS`, `DOCUMENT_SIDES_MISMATCH`, `ID_VERIFICATION_DATA_MISMATCH_BETWEEN_DOCUMENTS` | Approve (information) |
| **Invalid Validation** | `INVALID_DATE`, `COULD_NOT_RECOGNIZE_DOCUMENT`, `DOCUMENT_NUMBER_NOT_DETECTED`, `COULD_NOT_DETECT_DOCUMENT_TYPE`, `NAME_NOT_DETECTED`, `DATE_OF_BIRTH_NOT_DETECTED` | Review |
| **Expected Details Mismatch** | `FULL_NAME_MISMATCH_WITH_PROVIDED`, `GENDER_MISMATCH_WITH_PROVIDED`, `DOB_MISMATCH_WITH_PROVIDED`, `COUNTRY_MISMATCH_WITH_PROVIDED`, `NATIONALITY_MISMATCH_WITH_PROVIDED`, `IDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDED` | Review |
| **Expiration Date Not Detected** | `EXPIRATION_DATE_NOT_DETECTED` | Approve (information) |
| **Document or Personal Number Format Mismatch** | `DOCUMENT_NUMBER_FORMAT_MISMATCH`, `PERSONAL_NUMBER_FORMAT_MISMATCH` (one shared action) | Review |
| **Critical Field Covered** | `CRITICAL_FIELD_OCCLUSION_DETECTED` | Review |
| **Unparsed Address** | `UNPARSED_ADDRESS` | Approve (information) |
| **Image Quality** | `IMAGE_TOO_BLURRY`, `IMAGE_TOO_DARK`, `IMAGE_TOO_BRIGHT` (one action per risk) | Approve (information) |
| **Document Without Portrait** | `DOCUMENT_HAS_NO_PORTRAIT` | Review |
| **Duplicated face in Silent Capture** | `FRONT_CAMERA_DUPLICATED_FACE`, `POSSIBLE_FRONT_CAMERA_DUPLICATED_FACE` (one shared action) | Approve (information) |
| **Silent Capture duplicate with a different name** | `FRONT_CAMERA_DUPLICATED_FACE_NAME_MISMATCH` (can only make the duplicated-face outcome stricter) | Review |
| **Silent Capture duplicate with a different date of birth** | `FRONT_CAMERA_DUPLICATED_FACE_DOCUMENT_MISMATCH` (can only make the duplicated-face outcome stricter) | Review |

The Silent Capture duplicate and blocklist risks come from the [Face Search on the selfie taken during document capture](/core-technology/face-search/overview#the-selfie-taken-during-document-capture). The search runs while **Silent Capture Face Search** (`document_selfie_face_search_enabled`) is on, which is the default, and Face Search is not switched off on the Liveness step; otherwise none of these six risks is raised.

Two ID risk families are **threshold-driven** instead of Approve/Review/Decline toggles:

* **Document liveness** — `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`, `PORTRAIT_MANIPULATION_DETECTED`. Each fraud type has its own decline and review thresholds: score below the decline threshold → `error` + Declined; below the review threshold → `warning` + In Review; otherwise `information`.
* **Cross-camera face match** — `LOW_FRONT_CAMERA_FACE_MATCH_SIMILARITY`, governed by `document_selfie_portrait_match_decline_threshold` / `document_selfie_portrait_match_review_threshold`.

### Configuring document liveness thresholds

In the workflow editor these thresholds live on the **Forgery** tab of the ID Verification step, one card per fraud type: **Portrait replacement**, **Printed copy** and **Screen capture**.

Each check gives the document a score from `0` to `100` for how genuine it looks. **A higher score means the document is more likely genuine.** The two values on a card split that scale into three bands:

| Score | Result |
| - | - |
| Below the **Decline** value | `error`, the session is Declined |
| At or above the **Decline** value and below the **Review** value | `warning`, the session goes to In Review |
| At or above the **Review** value | `information`, the check passes |

Raising either value makes the check stricter: more sessions land in the band above it. Lowering a value lets more sessions through. In the editor the Decline value cannot move past the Review value. Through the API, a Decline value above the Review value removes the In Review band.

Platform defaults, used when a workflow does not set a value:

| Fraud type | Decline below | Review below | Workflow config keys |
| - | - | - | - |
| Portrait replacement | `35` | `70` | `document_liveness_portrait_replace_decline_threshold`, `document_liveness_portrait_replace_review_threshold` |
| Printed copy | `35` | `77` | `document_liveness_printed_copy_decline_threshold`, `document_liveness_printed_copy_review_threshold` |
| Screen capture | `30` | `70` | `document_liveness_screen_replay_decline_threshold`, `document_liveness_screen_replay_review_threshold` |

Start from the defaults and move one value at a time. Each card shows its default and a **Reset to default** button, so you can always return to it. The editor also warns you about these configurations:

* **Review at `100`.** Only a perfect score passes, so almost every session goes to In Review or is declined.
* **Decline at `100`.** Only a perfect score avoids a decline, so almost every session is declined.
* **Both values at `0`.** No score is ever flagged, so the check is effectively off.

Setting both values to the same number removes the In Review band: a score below it is declined and any other score passes.

When both **Printed copy** and **Screen capture** would flag the same document, only `SCREEN_CAPTURE_DETECTED` is reported.

The cross-camera face match uses the same idea with one difference at the boundary: a score equal to its review threshold still goes to In Review.

Four ID risks are neither configurable nor threshold-driven. `POSSIBLE_FRONT_CAMERA_FACE_IN_BLOCKLIST` always routes to **Review**: a selfie that is close to a blocklisted face, without being a confirmed match, is for a person to judge, never an automatic decline and never ignored. `BARCODE_SIGNATURE_INVALID` always routes to **Review**. It fires only when a barcode carries an issuing-authority signature that fails cryptographic verification, so there is no configuration in which a proven forgery is ignored. `DOCUMENT_BACK_SIDE_NOT_AVAILABLE` is always **information** and never affects the decision: it reports a limitation of Didit's document catalog, not a property of the document presented, so there is no configuration in which it can decline or review a genuine holder.
`FRONT_CAMERA_CAPTURED_DOCUMENT` always routes to **Review**.
It fires only when the front-camera frame taken while the document is scanned shows an identity document and no person, so a capture that says nothing about who held the document always reaches a human.
It is checked whenever the document capture selfie match (`is_document_selfie_portrait_match_enabled`) is on.

## Warnings produced

Verified against `collect_ocr_logs`, the document-capture flow, and `process_ocr_logs_and_get_status`. Short descriptions below are the exact `short_description` strings returned by the API.

### Document recognition and quality

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `COULD_NOT_RECOGNIZE_DOCUMENT` | Could not validate Document | The system could not confirm the authenticity or validity of the submitted document — often poor image quality or an unsupported document type. Also used as the fallback for unrecognized processing failures. | Configurable — Invalid Validation, default Review |
| `COULD_NOT_DETECT_DOCUMENT_TYPE` | Could not detect document type | The OCR engine could not classify the document family (passport vs ID vs DL). When this fires, `DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` is suppressed (the type is unknown, so "not supported" would be contradictory). | Configurable — Invalid Validation, default Review |
| `DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` | Document not supported for your application | The recognized document type is not on the application's allowed list. `additional_data` carries the country, document type, subtype, and region-aware subtype. | `error` — **auto-decline** |
| `DOCUMENT_EXPIRED` | Document expired | At capture time: the document's expiration date is in the past (`error`, auto-decline). Post-approval: ongoing expiration monitoring appends this warning with `log_type: "warning"` when an approved document's date passes, and the report status becomes `Expired`. | `error` at capture; `warning` from monitoring |
| `DOCUMENT_SIDES_MISMATCH` | Document sides mismatch | Front and back images do not belong to the same document. | Configurable — Data Inconsistency, default information |
| `DOCUMENT_BACK_SIDE_NOT_AVAILABLE` | Back side not available for this document | The workflow requested both sides, the front was recognized, and Didit's document catalog registers no back side for that exact document, so only the front could be collected. The report's evidence is one-sided. Nothing is wrong with the document presented, the holder is never asked to retake it, and re-scanning cannot add a back side. `additional_data` carries the recognized `front_document_name`. | `information` — never affects the decision |
| `PORTRAIT_IMAGE_NOT_DETECTED` | Portrait image not detected | No portrait could be located on a document that should have one (deferred when the user uploads the non-portrait side first). | `error` — **auto-decline** |
| `DOCUMENT_HAS_NO_PORTRAIT` | Document has no portrait | The recognized document family never carries a portrait photo on any side (some residence permits, health cards, registration certificates, tax cards, and a subset of DLs/IDs). This is a catalog-level fact about the document type, not an image-quality issue — re-scanning the document cannot change the outcome. | Configurable — Document Without Portrait, default Review |
| `IMAGE_TOO_BLURRY` / `IMAGE_TOO_DARK` / `IMAGE_TOO_BRIGHT` | Document image is too blurry / too dark / too bright | The image-quality gate rejected an upload (the user is asked to retake). `additional_data` carries the failing `side`. A successful retake clears the stale warning; the gate is skipped on the user's final allowed attempt so they are never hard-blocked. | Configurable — per-risk Image Quality action, default information |

<Note>
  The capture flow can also reject an upload with the feedback codes `IMAGE_RESOLUTION_TOO_LOW`, `DOCUMENT_NOT_FULLY_VISIBLE`, `IMAGE_QUALITY_TOO_LOW`, and `DOCUMENT_OCCLUSION_DETECTED` (a finger or object is judged to be physically covering printed text). Each prompts a retake in the SDK and is recorded on the report as its own risk, routed by the Image Quality settings — `DOCUMENT_OCCLUSION_DETECTED` and `IMAGE_QUALITY_TOO_LOW` share one action. They describe the *capture*: a retake that succeeds clears the warning. Whether a covered field should affect the decision is the separate, integrity-side `CRITICAL_FIELD_OCCLUSION_DETECTED` below, which is raised at decision time and defaults to Review.
</Note>

<Tip>
  If your workflow anchors identity on Face Match rather than the document portrait, consider routing **Document Without Portrait** to Decline — otherwise a portrait-less document family reaches Face Match with nothing to compare against.
</Tip>

### Field extraction

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `NAME_NOT_DETECTED` | First name and/or last name not detected | First name and last name could not be extracted. Exempt when the holder legitimately has a single name (one-name countries, or the MRZ itself carries a single name) and at least one name value was extracted. | Configurable — Invalid Validation, default Review |
| `DATE_OF_BIRTH_NOT_DETECTED` | Date of birth not detected | Date of birth could not be extracted from a document that should have one. | Configurable — Invalid Validation, default Review |
| `DOCUMENT_NUMBER_NOT_DETECTED` | Document number not detected | Neither the document number nor a personal number could be extracted. | Configurable — Invalid Validation, default Review |
| `EXPIRATION_DATE_NOT_DETECTED` | Expiration date not detected | Expiration date could not be extracted from a document that should have one. | Configurable — Expiration Date Not Detected, default information |
| `INVALID_DATE` | Invalid Date | A date on the document (date of birth or expiry) doesn't parse to a valid date. In the current capture flow this surfaces as a retake prompt during upload rather than a stored warning; the code remains in the Invalid Validation routing group and may appear on older sessions. | Configurable — Invalid Validation, default Review |
| `DOCUMENT_NUMBER_FORMAT_MISMATCH` | Document number format mismatch | Document number does not match the expected format configured for this document type. `additional_data` carries `expected_format` and `extracted_value`. | Configurable — Format Mismatch, default Review |
| `PERSONAL_NUMBER_FORMAT_MISMATCH` | Personal number format mismatch | Personal number does not match the expected format configured for this document type. | Configurable — Format Mismatch, default Review |
| `CRITICAL_FIELD_OCCLUSION_DETECTED` | A critical document field is covered | The occlusion check reported that a critical printed field was physically covered on the capture — an identity number, a name, the date of birth, or the expiry date. This is a document-integrity signal, not a capture-quality one: covering the very numbers a report is reconciled against is what a redacted or tampered document looks like. The value read for a covered field is dropped from the extraction rather than returned as a confirmed one, so the matching `*_NOT_DETECTED` risk usually accompanies this warning. `additional_data` carries the covered field names in `covered_fields`, and `covered_identifiers` when one of them feeds `document_number` or `personal_number`. | Configurable — Critical Field Covered, default Review |

### MRZ, QR, barcode

All three MRZ risks are skipped for document types with known-unreliable MRZs.

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `MRZ_NOT_DETECTED` | MRZ not detected | MRZ could not be located on a document that should have one. | Configurable — Invalid MRZ, default information |
| `MRZ_VALIDATION_FAILED` | MRZ is not valid | MRZ failed checksum / format validation. Often a low-quality capture; can indicate tampering. | Configurable — Invalid MRZ, default information |
| `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` | MRZ and data extracted from OCR have some discrepancies | MRZ contents disagree with the VIZ (visible-zone) OCR. Possible alteration. | Configurable — Data Inconsistency, default information |
| `QR_NOT_DETECTED` | QR not detected | QR code could not be located on a document that should have one. | Configurable — Invalid Code, default information |
| `QR_VALIDATION_FAILED` | QR validation failed | QR contents could not be validated against the rest of the document. | Configurable — Invalid Code, default information |
| `BARCODE_NOT_DETECTED` | Barcode not detected | Barcode could not be located on a document that should have one. | Configurable — Invalid Code, default information |
| `BARCODE_VALIDATION_FAILED` | Barcode validation failed | Barcode contents could not be validated against the rest of the document. | Configurable — Invalid Code, default information |
| `BARCODE_SIGNATURE_INVALID` | Barcode signature invalid | The barcode carries a digital signature from the issuing authority, and that signature did not verify - the data in the barcode is not the data the authority signed, which points to a forged or altered document. Currently checked for **French 2D-Doc (ANTS)** barcodes, where a verified signature lets Didit promote fields without needing MRZ corroboration; AAMVA (US/Canada driving licences and IDs) signatures are detected and logged only, not yet enforced. | Fixed - Review (own action group `invalid_barcode_signature_action`; not yet console/API-configurable) |
| `DATA_INCONSISTENT` | OCR data in the document is not consistent | Data extracted from different parts of the document disagrees — typically the front and back sides of the same document. | Configurable — Data Inconsistency, default information |

<Note>
  Barcode signature verification currently covers French national ID cards, whose ANTS 2D-Doc barcode is signed by the issuing authority. `BARCODE_SIGNATURE_INVALID` is raised only when the signature check itself rejects the payload. A barcode with no signature, one signed by an authority not yet in Didit's trust store, or one whose signature cannot be decoded is treated as unauthenticated data and validated against the MRZ and printed text as before, without raising this risk.

  US and Canadian driving licence (AAMVA) barcodes are not cryptographically verified: digital signing there is optional and jurisdiction-specific, and no jurisdiction publishes verification keys, so Didit only detects and logs whether a payload carries a signature; the signature itself is never checked. AAMVA signature failures are not a risk signal today. A tampered AAMVA payload only surfaces as `BARCODE_VALIDATION_FAILED`, and only if the tampering also makes the barcode disagree with the MRZ or printed/OCR data - a forged signature on an otherwise internally consistent payload passes with no signal at all.

  The user is never asked to re-capture on `BARCODE_SIGNATURE_INVALID`: a signature that does not match the payload cannot be fixed by taking a better photo.
</Note>

### Identity matching

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `ID_DOCUMENT_IN_BLOCKLIST` | ID document in blocklist | The document matches a blocklisted document (same date of birth, issuing country, and exact document number) or a manually blocklisted document number. `additional_data` carries the blocklisted session reference. | `error` — **auto-decline** |
| `ID_DOCUMENT_IN_ALLOWLIST` | ID document in allowlist | The document number matches your document allowlist, so the duplicate-user action was skipped. `additional_data` carries the `document_number`. | `information` |
| `POSSIBLE_DUPLICATED_USER` | Possible duplicated user from other session | Another document in your application has the same date of birth, the same issuing country, and a highly similar full name — under a different user (`vendor_data`), regardless of that session's status. `additional_data` carries the duplicate session reference. | Configurable — Duplicated User, default information |
| `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS` | Document name differs from other approved documents | Name on this document differs from previously approved documents for the same user. Only produced for Didit-protocol (UserKYC) accounts, not standard API sessions. | Configurable — Data Inconsistency, default information |
| `ID_VERIFICATION_DATA_MISMATCH_BETWEEN_DOCUMENTS` | Data mismatch between ID verification documents | Two ID documents in the same session disagree on name / date of birth. | Configurable — Data Inconsistency, default information |
| `LOW_FRONT_CAMERA_FACE_MATCH_SIMILARITY` | Selfie during document capture doesn't match document portrait | The face captured from the user's front camera during document capture does not match the portrait on the document well. | Threshold-driven: `error` below the decline threshold, `warning` at or below the review threshold |
| `FRONT_CAMERA_FACE_IN_BLOCKLIST` | Selfie during document capture matches a blocklisted face | The face in a selfie taken by the front camera during document capture confidently matches a face in your face blocklist, whether that face was added from a liveness check, from another session's document-capture selfie, or by upload. `additional_data` carries the blocklisted session reference (`blocklisted_session_id`, `blocklisted_session_number`) when the blocklisted face came from a session, and `face_image_source` (`front_image_camera_front` or `back_image_camera_front`) for the selfie that matched. | `error` — **auto-decline** |
| `POSSIBLE_FRONT_CAMERA_FACE_IN_BLOCKLIST` | Selfie during document capture may match a blocklisted face | The face in a document-capture selfie is similar to a face in your face blocklist, but not similar enough to be a confirmed match. Same `additional_data` as above. | `warning` — **always Review** |
| `FRONT_CAMERA_DUPLICATED_FACE` | Selfie during document capture matches an approved user | The face in the selfie taken by the front camera during document capture confidently matches the face of a user already approved in your application, so the same person may be verifying again under another account. `additional_data` carries the matched session (`duplicated_session_id`, `duplicated_session_number`) and `face_image_source` for the selfie that matched. | Per **Duplicated face in Silent Capture** (default Approve, `information`) |
| `POSSIBLE_FRONT_CAMERA_DUPLICATED_FACE` | Selfie during document capture may match an approved user | The face in a document-capture selfie is similar to the face of a user already approved in your application, but not similar enough to be a confirmed match. Same `additional_data` as above. | Per **Duplicated face in Silent Capture** (default Approve, `information`) |
| `FRONT_CAMERA_DUPLICATED_FACE_NAME_MISMATCH` | Document capture selfie matches a user with a different name | Raised on top of `FRONT_CAMERA_DUPLICATED_FACE` when the approved user was verified under a different name. `additional_data` adds `name_match_score`; it never carries the other user's name. | Per **Silent Capture duplicate with a different name** (default Review, `warning`) |
| `FRONT_CAMERA_DUPLICATED_FACE_DOCUMENT_MISMATCH` | Document capture selfie matches a user with a different date of birth | Raised on top of `FRONT_CAMERA_DUPLICATED_FACE` when the approved user's identity document shows a different date of birth. A different document of the same person (for example a passport after an ID card), a renewed document, or the same document number from the same country is not flagged. `additional_data` adds `mismatch_dimensions`, never the other user's document data. | Per **Silent Capture duplicate with a different date of birth** (default Review, `warning`) |
| `FRONT_CAMERA_CAPTURED_DOCUMENT` | Front camera captured an ID document instead of the user | The front-camera frame taken while the document was scanned shows an identity document (for example a card held up to the camera) and no person. The document capture selfie match is not computed for that frame. | Always **Review** |

### Document liveness (tampering)

Threshold-driven per fraud type in workflows; unconditionally declining on the standalone OCR API.

The scores themselves are on every V3 report as [`document_liveness`](/core-technology/id-verification/report-id-verification#document-liveness-scores), including when no warning fired, so an approved document can still be audited.

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `SCREEN_CAPTURE_DETECTED` | Screen capture of document detected | Document was captured from a screen rather than a physical document. | `error` below the decline threshold, `warning` below the review threshold, else `information` |
| `PRINTED_COPY_DETECTED` | Printed copy of document detected | Document appears to be a printed copy rather than the original. | Same tri-bucket thresholds |
| `PORTRAIT_MANIPULATION_DETECTED` | Portrait manipulation detected | The portrait region appears to have been replaced or altered. | Same tri-bucket thresholds |

### Known public document images

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `PUBLIC_DOCUMENT_IMAGE_DETECTED` | Known public internet document image detected | The submitted document image matches a known publicly available internet image (for example a specimen, press, or stock photo of a document), so it cannot be a photo of the user's own physical document. Matching uses exact and perceptual (pHash/dHash) fingerprinting against Didit's corpus of known public document images; `additional_data` carries `match_type` (`exact` or `perceptual`), `source`, `source_url`, and a `similarity_score` (0-100). | Fixed - Review in workflows; **auto-decline** on the standalone `/id-verification` API |

### Expected-details mismatches

When you pass `expected_details` to a session, Didit raises a mismatch warning per field that does not match. One grouping (`expected_details_mismatch_action`, default Review) controls routing for all of these:

| Risk | Short description | Cause |
| - | - | - |
| `FULL_NAME_MISMATCH_WITH_PROVIDED` | Full name mismatch with provided information | Provided name scores below the name-match threshold against the document. |
| `DOB_MISMATCH_WITH_PROVIDED` | Date of birth mismatch with provided information | Provided date of birth does not match. |
| `GENDER_MISMATCH_WITH_PROVIDED` | Gender mismatch with provided information | Provided gender does not match. |
| `COUNTRY_MISMATCH_WITH_PROVIDED` | Country mismatch with provided information | Provided country does not match `issuing_state`. |
| `NATIONALITY_MISMATCH_WITH_PROVIDED` | Nationality mismatch with provided information | Provided nationality does not match. |
| `IDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDED` | Identification number mismatch with provided information | Provided ID number does not match the document number, personal number, or tax number. |

Each mismatch warning carries the expected and extracted values in `additional_data`.

### Age

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `MINIMUM_AGE_NOT_MET` | Minimum age not met | Holder is below the configured minimum age (global or per-country/state). `additional_data` carries `min_age_allowed` and `user_age`. | Configurable — Minimum Age, default Decline (`error`); unconditional decline on the standalone OCR API |
| `MAXIMUM_AGE_EXCEEDED` | Maximum age exceeded | Holder is above the configured maximum age. `additional_data` carries `max_age_allowed` and `user_age`. | Configurable — Maximum Age, default Decline (`error`) |
| `AGE_NOT_DETECTED` | Age not detected | Adaptive age-verification workflows: age could not be extracted from the document. | `error` — **auto-decline** |
| `AGE_BELOW_MINIMUM` | Age below minimum | Adaptive age-verification workflows: extracted age is below the minimum. | `error` — **auto-decline** |

### Address

| Risk | Short description | Cause | Severity |
| - | - | - | - |
| `UNPARSED_ADDRESS` | Unable to determine address location | The document defines an address field, but the extracted address could not be parsed or geolocated. | Configurable — Unparsed Address, default information |

## Cross-session document matches

In addition to the warnings above, the V3 ID report ships a `matches[]` array — up to 5 other documents in your application with the same date of birth, the same issuing country, and a highly similar full name (blocklisted documents additionally require an exact document-number match), excluding sessions that belong to the same user. Documents added to your blocklist appear with `is_blocklisted: true`. Documents on your allowlist still appear in matches, but their duplicate-user action is skipped.

Each match includes `session_id`, `session_number`, `vendor_data`, `verification_date`, `user_details` (`name`, `document_type`, `document_number`), `status`, `is_blocklisted`, `api_service`, and a signed `front_image_url`.

## Examples

### Configurable warning at its default routing (information)

```json theme={null}
"warnings": [
  {
    "feature": "ID_VERIFICATION",
    "risk": "QR_NOT_DETECTED",
    "additional_data": null,
    "log_type": "information",
    "short_description": "QR not detected",
    "long_description": "The system couldn't find or read the QR code on the document. This could be due to poor image quality or an unsupported document type.",
    "node_id": "id_primary"
  }
]
```

### Auto-decline on expired document

```json theme={null}
"warnings": [
  {
    "feature": "ID_VERIFICATION",
    "risk": "DOCUMENT_EXPIRED",
    "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.",
    "node_id": "id_primary"
  }
]
```

### Expected-details mismatch with payload

```json theme={null}
"warnings": [
  {
    "feature": "ID_VERIFICATION",
    "risk": "DOB_MISMATCH_WITH_PROVIDED",
    "additional_data": {
      "expected_dob": "1990-01-01",
      "extracted_dob": "1991-03-15"
    },
    "log_type": "warning",
    "short_description": "Date of birth mismatch with provided information",
    "long_description": "The provided date of birth in `expected_details` doesn't match the date extracted from the document.",
    "node_id": "id_primary"
  }
]
```

## Warning types

Each risk is assigned a severity based on your application's configuration. The three severities are:

<WarningTypes />

## Related

* [ID verification report](/core-technology/id-verification/report-id-verification) — full report schema and statuses.
* [Document monitoring](/core-technology/id-verification/document-monitoring-id-verification) — how Didit detects tampering and cross-session duplicates.
* [Webhooks](/integration/webhooks) — `session.status.updated` carries the warnings as soon as the ID step finishes.
* [Data models — ID verification](/reference/data-models#id-verification) — canonical field-by-field schema.
* [Data models — Warning object](/reference/data-models#warning-object) — the shape of every entry in `warnings[]`.


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