Skip to main content

Document Forensics

Document forensics detects image tampering — spliced photos, clone-stamped regions, recompression artifacts, typography mismatches — that a plain "is this a document?" check would miss. It runs automatically as part of the document check and its result is available in the verification's checks_results under forensics.

Checks​

CheckWhat it detects
ela_spliceError-level-analysis anomalies indicating a spliced/pasted region (e.g. a swapped portrait)
copy_moveClone-stamped regions (the same patch duplicated within the image)
noise_residualRecompression / low-energy noise anomalies, including subtle low-contrast tampering
block_artifactsJPEG block-grid inconsistencies from re-saving an edited image
portrait_seamHard edges around the portrait photo — a pasted-in or replaced face
typographyFont/typography inconsistencies in printed fields (MRZ/VIZ) versus the rest of the document

Result structure​

{
"forensics": {
"passed": false,
"score": 0.42,
"checks": [
{ "name": "ela_splice", "passed": false, "score": 0.31, "reason": "splice artifact near portrait" },
{ "name": "copy_move", "passed": true, "score": 0.92, "reason": "no duplicated regions" },
{ "name": "noise_residual", "passed": true, "score": 0.88, "reason": "noise consistent" },
{ "name": "block_artifacts", "passed": true, "score": 0.85, "reason": "consistent block grid" },
{ "name": "portrait_seam", "passed": false, "score": 0.35, "reason": "hard edge around portrait" },
{ "name": "typography", "passed": true, "score": 0.90, "reason": "fonts consistent" }
]
}
}
FieldTypeDescription
passedbooleanOverall forensics outcome (score >= threshold)
scorefloatOverall tamper score (0.0–1.0)
checks[].namestringCheck identifier
checks[].passedbooleanPer-check outcome
checks[].scorefloatPer-check score
checks[].reasonstringHuman-readable explanation

Threshold​

The overall pass threshold is configurable via DOCUMENT_FORENSICS_THRESHOLD (default 0.5). Lowering it makes the check stricter.

Multispectral checks​

When you have multi-spectral captures (UV/IR), run the explicit check:

POST /verifications/{id}/documents/{doc_id}/multispectral

Send a multipart body with the available channels: visible (required), uv, ir, coaxial.

curl -X POST https://api.dev.valydar.com/verifications/{id}/documents/{doc_id}/multispectral \
-H "Authorization: Bearer YOUR_API_KEY" \
-F visible=@document.jpg \
-F uv=@document_uv.jpg \
-F ir=@document_ir.jpg

Response:

{
"passed": true,
"checks": [
{ "name": "uv_fluorescence", "passed": true, "score": 0.9, "reason": "..." },
{ "name": "ir_absorption", "passed": true, "score": 0.88, "reason": "..." }
]
}

Results are merged into the verification under checks_results.security_features. Multispectral requires the liveness:run permission.

When to use it​

Forensics runs by default on document upload — no extra call needed. Call the multispectral endpoint only when you also capture UV/IR channels; it adds security-feature verification (hologram/fluorescent ink behaviour) on top of the image-forensics checks.