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

# Webhook Payload Reference

> Glossary of every key in the file.enrichment.success webhook payload, with its type and an example value

Every key delivered in a `file.enrichment.success` payload, with the type of its value and a short example. For delivery and signature verification, see [Webhooks](/guides/webhooks).

## How to read this page

Nested keys are written as paths. `file_info.mimetype` means a `mimetype` key inside the `file_info` object. A `[]` means the key holds an array, so `modules[].module_id` is the `module_id` of each entry in `modules`.

Types are described plainly: string, number, boolean, object, array, and null. Two qualifiers matter:

| Qualifier                 | What it means                                                                                            |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| **may be null**           | The key is always present. Its value is `null` when that part of the analysis did not apply to the file. |
| **may be absent or null** | The key may be missing entirely, or present with the value `null`. Treat both the same way.              |

<Warning>
  Where a key is marked "may be absent or null", do not distinguish the two. Both forms occur, and checking for only one will break on the other.
</Warning>

<Info>
  Keys are added over time. Ignore any key you do not recognise rather than rejecting the payload.
</Info>

## Top level

| Key                 | Type                                   | Example                                            |
| ------------------- | -------------------------------------- | -------------------------------------------------- |
| `event_type`        | string                                 | `"file.enrichment.success"`                        |
| `event_id`          | string                                 | `"enrichment_01a039f1...:file.enrichment.success"` |
| `case_id`           | string (UUID)                          | `"01a039f1-1e01-7b0b-a952-4e6d907ab221"`           |
| `case_label`        | string                                 | `"Smith Fraud Investigation"`                      |
| `file_id`           | string (UUID)                          | `"01a039f1-1e46-79ee-a5c1-fc653b9f8f64"`           |
| `file_label`        | string                                 | `"utility_bill.pdf"`                               |
| `trace_id`          | string, may be absent or null          | `"enrichment_01a039f1_01a039f1"`                   |
| `started_at`        | string (ISO 8601)                      | `"2026-08-25T17:21:40.912430+00:00"`               |
| `completed_at`      | string (ISO 8601)                      | `"2026-08-25T17:23:21.342763+00:00"`               |
| `file_info`         | object                                 | See [file\_info](#file_info)                       |
| `analysis_metadata` | object                                 | See [analysis\_metadata](#analysis_metadata)       |
| `ocr_summary`       | string, may be absent or null          | `"This is a photograph of a utility bill..."`      |
| `results`           | object, may be absent or null          | See [results](#results)                            |
| `modules`           | array of object                        | See [modules](#modules)                            |
| `artifacts`         | object                                 | See [artifacts](#artifacts)                        |
| `integrity_signals` | object, may be absent or null          | See [integrity\_signals](#integrity_signals)       |
| `highlights`        | array of string, may be absent or null | `["The document is a legitimate utility bill."]`   |
| `caveats`           | array of object, always present        | See [caveats](#caveats)                            |
| `version`           | string                                 | `"2"`                                              |

<Info>
  `event_id` is the same on every redelivery of an event, which makes it the right value for recognising a duplicate. Treat it as an opaque string.
</Info>

<Warning>
  `version` is `"2"`, a payload schema version rather than a semantic version. Compare it exactly rather than parsing it.
</Warning>

<Info>
  `case_label` and `file_label` are human-readable labels for the case and file. `file_label` falls back to the name parsed from the S3 upload key when no file label is available; `case_label` has no such fallback. Each field is an empty string (never null) if nothing could be resolved. They were added to notifications going forward; payloads sent before this addition do not include them.
</Info>

Timestamps carry a UTC offset and microsecond precision, as in `2026-08-25T17:21:40.912430+00:00`, rather than a `Z` suffix.

## file\_info

| Key                      | Type                | Example                              |
| ------------------------ | ------------------- | ------------------------------------ |
| `file_info.mimetype`     | string              | `"image/jpeg"`, `"application/pdf"`  |
| `file_info.md5`          | string, may be null | `"82cc5e174bf6fb87dfd87e98ab965120"` |
| `file_info.raw_metadata` | object, may be null | Depends on the file type; see below  |

`raw_metadata` holds whatever metadata the file itself carried, so its keys depend on the file type. The three shapes below share no keys, so check `mimetype` before reading it.

### Images

| Key                   | Type                         | Example                                      |
| --------------------- | ---------------------------- | -------------------------------------------- |
| `file_size`           | number                       | `70059`                                      |
| `image_format`        | string, may be absent        | `"JPEG"`                                     |
| `image_width`         | number, may be absent        | `544`                                        |
| `image_height`        | number, may be absent        | `768`                                        |
| `image_mode`          | string, may be absent        | `"RGB"`                                      |
| `metadata.success`    | boolean                      | `true`                                       |
| `metadata.tags`       | object, may be null          | `{ "Image Mode": "RGB", "Jfif Unit": 0 }`    |
| `metadata.tags_count` | number                       | `10`                                         |
| `metadata.message`    | string, may be null          | `"Found 6 JFIF tag(s), 4 basic info tag(s)"` |
| `c2pa.has_c2pa`       | boolean, group may be absent | `false`                                      |
| `c2pa.data`           | object, may be null          | `null`                                       |

`metadata.tags` is free-form: its keys are whatever the file carried, so read the ones you care about by name and expect the rest to vary between files. The `c2pa` group appears only when the file carries a content credentials manifest.

### PDFs

| Key                 | Type                | Example                       |
| ------------------- | ------------------- | ----------------------------- |
| `title`             | string, may be null | `null`                        |
| `author`            | string, may be null | `null`                        |
| `creator_software`  | string, may be null | `"Microsoft Word"`            |
| `producer_software` | string, may be null | `"Quartz PDFContext"`         |
| `creation_date`     | string, may be null | `"2026-03-30T11:16:56+00:00"` |
| `modification_date` | string, may be null | `null`                        |
| `pages`             | number              | `1`                           |

### Word documents

| Key                                              | Type                | Example                 |
| ------------------------------------------------ | ------------------- | ----------------------- |
| `author`, `title`, `subject`, `category`         | string, may be null | `"A. Smith"`            |
| `comments`, `keywords`, `language`               | string, may be null | `"en-GB"`               |
| `identifier`, `content_status`, `version`        | string, may be null | `null`                  |
| `creation_date`, `modified_date`, `last_printed` | string, may be null | `"2026-03-30T11:16:56"` |
| `last_modified_by`                               | string, may be null | `"A. Smith"`            |
| `revision`                                       | number, may be null | `3`                     |
| `paragraphs_count`                               | number              | `42`                    |
| `tables_count`                                   | number              | `2`                     |

## analysis\_metadata

Raw output from each step of the analysis. Every key below is always present, and is `null` when that step does not apply to the file, so an image has no `pdf_structure` and a PDF has no `ela`.

| Key                                 | Type                         | Applies to                |
| ----------------------------------- | ---------------------------- | ------------------------- |
| `analysis_metadata.ela`             | object, may be null          | Images                    |
| `analysis_metadata.reverse_search`  | object, may be null          | Images                    |
| `analysis_metadata.thumbnail`       | object, may be null          | All files                 |
| `analysis_metadata.barcode_results` | array of object, may be null | Files containing barcodes |
| `analysis_metadata.ocr`             | object, may be null          | All files                 |
| `analysis_metadata.pdf_structure`   | object, may be null          | PDFs                      |
| `analysis_metadata.annotations`     | object, may be null          | PDFs                      |

### ela

Error Level Analysis, which looks for uneven compression across an image.

| Key               | Type                | Example                                 |
| ----------------- | ------------------- | --------------------------------------- |
| `mean_diff`       | number              | `0.184`                                 |
| `std_diff`        | number              | `0.779`                                 |
| `percent_anomaly` | number              | `4.277`                                 |
| `image_path`      | string              | `"ela/01a039f1.../01a039f1....ela.jpg"` |
| `was_scaled`      | boolean             | `false`                                 |
| `scaling_info`    | object, may be null | `null`                                  |

### reverse\_search

| Key                                | Type                         | Example                       |
| ---------------------------------- | ---------------------------- | ----------------------------- |
| `matches`                          | array of object, may be null | `null`                        |
| `total`                            | number                       | `0`                           |
| `external_services[].service_name` | string                       | `"tineye"`                    |
| `external_services[].usage_units`  | object                       | `{ "searches_performed": 1 }` |
| `error`                            | string, may be null          | `null`                        |

### thumbnail

| Key                 | Type                  | Example                                |
| ------------------- | --------------------- | -------------------------------------- |
| `path`              | string                | `"thumbs/01a039f1.../01a039f1....jpg"` |
| `format`            | string                | `"JPEG"`                               |
| `dimensions.width`  | number, may be absent | `106`                                  |
| `dimensions.height` | number, may be absent | `150`                                  |
| `size_bytes`        | number                | `4227`                                 |
| `quality`           | number, may be absent | `80`                                   |

### barcode\_results

| Key                           | Type                | Example                                |
| ----------------------------- | ------------------- | -------------------------------------- |
| `barcode_results[].type`      | string              | `"QR Code"`, `"GS1 Application Data"`  |
| `barcode_results[].symbology` | string              | `"QRCode"`, `"DataMatrix"`, `"PDF417"` |
| `barcode_results[].value`     | string              | `",/,SK6 8EB,British Gas,..."`         |
| `barcode_results[].status`    | string              | `"HANDLED"`, `"UNHANDLED"`, `"FAILED"` |
| `barcode_results[].fields`    | object, may be null | `{ "content_type": "Text" }`           |
| `barcode_results[].info`      | string, may be null | `"Detected by the barcode reader"`     |

<Info>
  For barcode types that encode personal data, `value` is redacted and the readable content appears in `fields` instead.
</Info>

### ocr

Content read from the file, and the entities recognised in it.

| Key                                           | Type                | Example                                                                                                                  |
| --------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `ocr.file_category`                           | string              | `"PHOTO_OF_DOCUMENT"`, `"DIGITAL_DOCUMENT"`, `"GENERAL_PHOTOGRAPH"`, `"PHOTO_OF_PHOTOGRAPH"`, `"DIGITAL_ART"`, `"OTHER"` |
| `ocr.contains_embedded_images`                | boolean             | `false`                                                                                                                  |
| `ocr.classifications[].category`              | string              | `"Other"`, `"Receipt"`                                                                                                   |
| `ocr.classifications[].custom_guess`          | string, may be null | `"Utility Bill"`                                                                                                         |
| `ocr.extracted_details.reasoned_summary`      | string              | `"This is a photograph of a paper utility bill..."`                                                                      |
| `ocr.extracted_details.primary_jurisdiction`  | string, may be null | `"GB"`                                                                                                                   |
| `ocr.extracted_details.key_persons`           | array of object     | Entity; see below                                                                                                        |
| `ocr.extracted_details.key_organizations`     | array of object     | Entity; see below                                                                                                        |
| `ocr.extracted_details.key_locations`         | array of object     | Entity; see below                                                                                                        |
| `ocr.extracted_details.key_reference_numbers` | array of object     | Entity; see below                                                                                                        |
| `ocr.extracted_details.key_dates`             | array of object     | Date; see below                                                                                                          |

`classifications[].custom_guess` is filled in when `category` is `"Other"`. The available categories depend on the document classes configured for your organisation.

Entities, in `key_persons`, `key_organizations`, `key_locations` and `key_reference_numbers`:

| Key            | Type                | Example                         |
| -------------- | ------------------- | ------------------------------- |
| `value`        | string              | `"British Gas Trading Limited"` |
| `label`        | string, may be null | `"Energy Supplier"`             |
| `raw_ocr_text` | string, may be null | `"GBL-O0123-456l"`              |
| `country_code` | string, may be null | `"GB"`                          |
| `legible`      | boolean             | `true`                          |

`raw_ocr_text` is filled in when a reading correction was applied, and holds the original text. `legible` is `false` when the value could not be read confidently from the image.

Dates, in `key_dates`:

| Key                    | Type                           | Example                      |
| ---------------------- | ------------------------------ | ---------------------------- |
| `date_value`           | string (ISO date)              | `"2023-11-07"`               |
| `precision`            | string                         | `"day"`, `"month"`, `"year"` |
| `label`                | string                         | `"Bill date and tax point"`  |
| `legible`              | boolean                        | `true`                       |
| `illegible_components` | array of string, may be absent | `["year"]`                   |
| `year_inferred`        | boolean                        | `false`                      |
| `raw_ocr_text`         | string, may be null            | `"01 December 20205"`        |

<Warning>
  An unread date component is not evidence. When `precision` is `"month"` or `"year"`, the finer parts of `date_value` are placeholders. When `legible` is `false` or `year_inferred` is `true`, the named component was not read from the document. A check that depends on such a component is unverifiable rather than passing: an illegible expiry year never means "not expired".
</Warning>

### pdf\_structure

| Key                                          | Type                  | Example                                          |
| -------------------------------------------- | --------------------- | ------------------------------------------------ |
| `document_summary.dominant_font`             | array, may be absent  | `["Helvetica", 293]`                             |
| `document_summary.dominant_size`             | array, may be absent  | `[11.0, 293]`                                    |
| `document_summary.font_usage`                | object, may be absent | `{ "Helvetica": 293, "Helvetica-Bold": 6 }`      |
| `document_summary.size_usage`                | object, may be absent | `{ "11.0": 293, "14.0": 6 }`                     |
| `document_summary.error`                     | string, may be absent | `"No text-based content found in the document."` |
| `potential_anomalies[].type`                 | string                | `"RARE_FONT_USAGE"`, `"RARE_FONT_SIZE_USAGE"`    |
| `potential_anomalies[].details`              | object                | `{ "font_name": "Arial", "usage_count": 2 }`     |
| `potential_anomalies[].context.line_text`    | string                | `"Total amount due"`                             |
| `potential_anomalies[].location.page_number` | number                | `1`                                              |
| `potential_anomalies[].location.bbox`        | array of number       | `[72.0, 310.5, 240.1, 322.0]`                    |

`dominant_font` and `dominant_size` each pair a value with its occurrence count. `font_usage` is keyed by font name and `size_usage` by point size written as a string. `document_summary.error` appears instead of the other keys when the PDF has no text layer.

### annotations

| Key                                       | Type                | Example                        |
| ----------------------------------------- | ------------------- | ------------------------------ |
| `annotations.analysis.findings`           | array of object     | `[]`                           |
| `annotations.analysis.total_findings`     | number              | `0`                            |
| `annotations.analysis.analysis_timestamp` | string              | `"2026-08-25T17:29:46.371331"` |
| `annotations.highlighted_pdf`             | string, may be null | `null`                         |

## results

The report written for a reviewer.

| Key                                         | Type                | Example                                                          |
| ------------------------------------------- | ------------------- | ---------------------------------------------------------------- |
| `results.summary`                           | string              | `"This document is a photograph of a utility bill..."`           |
| `results.overall_risk_score`                | string              | `"Informational"`, `"Low"`, `"Medium"`, `"High"`                 |
| `results.observations`                      | array of string     | `["File Category: Photo of Document."]`                          |
| `results.audit_trail`                       | array of string     | `["Error Level Analysis: Measured pixel compression variance."]` |
| `results.modules_run`                       | array of string     | `["content_verification", "ela_fraud_detection"]`                |
| `results.suggested_actions[].action`        | string              | `"Verify VAT status manually"`                                   |
| `results.suggested_actions[].justification` | string              | `"The automated check was unavailable."`                         |
| `results.findings`                          | array of object     | See below                                                        |
| `results.search_evidence_summary`           | object, may be null | See [Evidence](#evidence)                                        |
| `results.verification_evidence_summary`     | object, may be null | See [Evidence](#evidence)                                        |
| `results.case_context_at_analysis`          | string, may be null | `null`                                                           |

<Warning>
  `results.overall_risk_score` and every `severity` are title-case, as in `"High"` and `"Informational"`. Compare them exactly.
</Warning>

`results.findings` holds only the findings that fired, summarised for a reviewer:

| Key                      | Type                | Example                                        |
| ------------------------ | ------------------- | ---------------------------------------------- |
| `heading`                | string              | `"Metadata Stripped"`                          |
| `category`               | string              | `"Manipulation & Forgery Detection"`           |
| `description`            | string              | `"The file lacks camera EXIF metadata."`       |
| `supporting_evidence`    | array of string     | `["Image Metadata: tags_count: 10"]`           |
| `source_analysis`        | string, may be null | `"manipulation_detection"`                     |
| `alert_type`             | string, may be null | `"METADATA_STRIPPED"`                          |
| `custom_alert_type`      | string, may be null | `null`                                         |
| `severity`               | string, may be null | `"Informational"`                              |
| `severity_justification` | string              | `"Informational for missing camera metadata."` |

`source_analysis` matches a `modules[].module_id`. `custom_alert_type` is filled in when `alert_type` is `"OTHER"`.

## modules

One entry per part of the analysis that ran. Which modules appear depends on the file type, its content, and the modules enabled for your organisation, so both the length and the order of this array vary between analyses.

<Warning>
  Look modules up by `module_id`, and findings by `alert_type`. Do not read either array by position.
</Warning>

| Key                               | Type                | Example                              |
| --------------------------------- | ------------------- | ------------------------------------ |
| `modules[].module_id`             | string              | `"manipulation_detection"`           |
| `modules[].module_name`           | string              | `"Manipulation & Forgery Detection"` |
| `modules[].error`                 | string, may be null | `null`                               |
| `modules[].findings`              | array of object     | See below                            |
| `modules[].search_evidence`       | object, may be null | See [Evidence](#evidence)            |
| `modules[].verification_evidence` | object, may be null | See [Evidence](#evidence)            |

When `modules[].error` is set, that module did not complete. Its findings are absent rather than clean, and a `caveats` entry will normally say so.

`modules[].findings` holds one entry for every check the module ran, whether or not it fired:

| Key                      | Type                | Example                                                     |
| ------------------------ | ------------------- | ----------------------------------------------------------- |
| `alert_type`             | string              | `"METADATA_STRIPPED"`                                       |
| `alert_type_name`        | string              | `"Metadata Stripped"`                                       |
| `found`                  | boolean             | `true`                                                      |
| `custom_alert_type`      | string, may be null | `null`                                                      |
| `severity`               | string              | `"Informational"`, `"Low"`, `"Medium"`, `"High"`            |
| `severity_justification` | string              | `"Informational for missing camera metadata."`              |
| `description`            | string              | `"The file lacks camera EXIF metadata."`                    |
| `evidence[].source`      | string              | `"Image Metadata"`                                          |
| `evidence[].detail`      | string              | `"tags_count: 10, only basic JFIF tags"`                    |
| `evidence[].explanation` | string              | `"Absence of camera EXIF suggests the image was re-saved."` |
| `evidence_refs`          | array of string     | `["v1", "q1.1"]`                                            |

<Info>
  Filter on `found` being `true` to get the alerts that actually triggered. The entries where `found` is `false` are the record of what was checked and came back clean, which is useful evidence in itself.
</Info>

Values of `module_id` you may see include `content_verification`, `manipulation_detection`, `document_consistency`, `software_anomalies`, `reverse_search_findings`, `pdf_structure_anomaly`, `barcode_analysis`, `reference_validation` and `ela_fraud_detection`. Read `results.modules_run` rather than assuming a fixed set.

## Evidence

Findings are backed by two kinds of evidence, which carry different weight. `search_evidence` is web research, so it corroborates. `verification_evidence` is a direct check against an authoritative registry or API, so it confirms or contradicts. Keep them distinct when you display them.

### search\_evidence

| Key                        | Type                | Example                               |
| -------------------------- | ------------------- | ------------------------------------- |
| `queries[].query_id`       | string              | `"q1"`                                |
| `queries[].query_text`     | string              | `"Is ACME Ltd registered in the UK?"` |
| `queries[].answer`         | string, may be null | `"No active registration found."`     |
| `results[].result_id`      | string              | `"q1.1"`                              |
| `results[].query_id`       | string              | `"q1"`                                |
| `results[].url`            | string              | `"https://example.com/registry/acme"` |
| `results[].title`          | string, may be null | `"Company search"`                    |
| `results[].snippet`        | string, may be null | `"No active company found..."`        |
| `results[].published_date` | string, may be null | `null`                                |
| `results[].last_updated`   | string, may be null | `"2026-02-17"`                        |
| `failures[].query_id`      | string              | `"q2"`                                |
| `failures[].error`         | string              | `"timeout"`                           |
| `failures[].status_code`   | number, may be null | `504`                                 |
| `failures[].rate_limited`  | boolean             | `false`                               |
| `elapsed_ms`               | number              | `4678`                                |
| `request_count`            | number              | `0`                                   |

### verification\_evidence

| Key                          | Type                 | Example                                                 |
| ---------------------------- | -------------------- | ------------------------------------------------------- |
| `checks[].check_id`          | string               | `"v1"`                                                  |
| `checks[].provider`          | string, may be null  | `"companies_house"`                                     |
| `checks[].check_type`        | string               | `"company"`, `"vat"`, `"address"`                       |
| `checks[].subject`           | string               | `"03078711"`                                            |
| `checks[].subject_date`      | string, may be null  | `null`                                                  |
| `checks[].country_code`      | string, may be null  | `"GB"`                                                  |
| `checks[].is_valid`          | boolean, may be null | `true`                                                  |
| `checks[].canonical_name`    | string, may be null  | `"BRITISH GAS TRADING LIMITED"`                         |
| `checks[].canonical_address` | string, may be null  | `null`                                                  |
| `checks[].checked_at`        | string, may be null  | `"2026-08-25T17:22:22.132531+00:00"`                    |
| `checks[].extracted`         | string, may be null  | `"03078711"`                                            |
| `checks[].outputs`           | object               | `{ "company_status": "active", "postcode": "SL4 5GD" }` |
| `checks[].attests`           | string, may be null  | `"Company registered per Companies House"`              |
| `checks[].country_mismatch`  | boolean              | `false`                                                 |
| `checks[].error`             | string, may be null  | `null`                                                  |

<Warning>
  `is_valid` has three states. `true` means confirmed and `false` means contradicted, but `null` means **could not be verified**, which is not the same as invalid. It usually means the authoritative source was unreachable or does not cover the subject, and a `caveats` entry will normally say so. Presenting `null` as a negative result will mislead your reviewers.
</Warning>

`outputs` holds fields specific to whichever source answered, so its keys vary with `provider`. `attests` states in one line what a verdict from that source actually proves. `extracted` is the value as read from the document, before it was normalised into `subject`.

### Tracing a finding back to its evidence

The values in a finding's `evidence_refs` point into its own module's evidence:

* `q1.1` matches a `results[].result_id` in that module's `search_evidence`. The number after the dot starts at 1, and matches the `[1]` markers in that query's `answer`.
* `v1` matches a `checks[].check_id` in that module's `verification_evidence`.

An empty `evidence_refs` on a finding that fired means it rests on the file's own metadata rather than on external evidence.

### Cross-module summaries

The same evidence rolled up across modules, so you can show an overview without walking every module.

| Key                                                  | Type   | Example              |
| ---------------------------------------------------- | ------ | -------------------- |
| `results.search_evidence_summary.total_queries`      | number | `7`                  |
| `results.search_evidence_summary.total_results`      | number | `21`                 |
| `results.search_evidence_summary.per_module`         | object | Keyed by `module_id` |
| `results.verification_evidence_summary.total_checks` | number | `4`                  |
| `results.verification_evidence_summary.resolved`     | number | `3`                  |
| `results.verification_evidence_summary.failed`       | number | `1`                  |
| `results.verification_evidence_summary.per_module`   | object | Keyed by `module_id` |

`resolved` counts checks that got an authoritative answer. `failed` counts those that could not be verified, which is the `is_valid` of `null` case above. Each entry under `per_module` holds `queries`, `results` and `cited_result_ids`, or `checks`, in the same shapes as above.

## artifacts

Files produced by the analysis, given as storage paths rather than URLs. Exchange the `file_id` for a short-lived signed URL with [Get Asset URL](/api-reference/endpoints/files-asset-url-get), passing the matching `asset_type`.

| Key                       | Type                | Example                                    | `asset_type`              |
| ------------------------- | ------------------- | ------------------------------------------ | ------------------------- |
| `artifacts.report_pdf`    | string, may be null | `"reports/01a039f1.../01a039f1....pdf"`    | `pdf_report`              |
| `artifacts.report_log`    | string, may be null | `"logs/output-enrichment_01a039f1....txt"` | `log_output`              |
| `artifacts.thumbnail`     | string, may be null | `"thumbs/01a039f1.../01a039f1....jpg"`     | `thumbnail`               |
| `artifacts.ela_overlay`   | string, may be null | `"ela/01a039f1.../01a039f1....ela.jpg"`    | `ela_overlay`             |
| `artifacts.annotated_pdf` | string, may be null | `null`                                     | Not currently retrievable |

## integrity\_signals

A summary of the forensic verdict, so you can route a file without walking every module.

| Key                                      | Type                  | Example                                    |
| ---------------------------------------- | --------------------- | ------------------------------------------ |
| `integrity_signals.reasoning`            | string, may be absent | `"No evidence of manipulation was found."` |
| `integrity_signals.image_manipulated`    | boolean, may be null  | `false`                                    |
| `integrity_signals.content_edited`       | boolean, may be null  | `false`                                    |
| `integrity_signals.metadata_manipulated` | boolean, may be null  | `false`                                    |
| `integrity_signals.ai_generated`         | boolean, may be null  | `false`                                    |
| `integrity_signals.ai_edited`            | boolean, may be null  | `false`                                    |
| `integrity_signals.reuse_online`         | boolean, may be null  | `false`                                    |
| `integrity_signals.risk_category`        | string, may be null   | `"Low"`                                    |

Each boolean has three states:

| Value   | Meaning                                         |
| ------- | ----------------------------------------------- |
| `true`  | Clear evidence found                            |
| `false` | The analysis ran and found nothing              |
| `null`  | Uncertain, or the relevant analysis did not run |

<Warning>
  Do not treat `null` as `false`. "We did not determine this" and "we determined this is not the case" carry very different weight in a fraud decision.
</Warning>

## caveats

Limits on how far an analysis should be trusted, such as an authoritative source being unreachable or text being hard to read. Always present; an empty array means no caveats apply. Caveats sit alongside the findings rather than being findings themselves.

| Key                           | Type                         | Example                                            |
| ----------------------------- | ---------------------------- | -------------------------------------------------- |
| `caveats[].type`              | string                       | `"external_service_failed"`, `"ocr_low_quality"`   |
| `caveats[].severity`          | string                       | `"info"`, `"warn"`, `"critical"`                   |
| `caveats[].title`             | string                       | `"Verification could not be completed"`            |
| `caveats[].message`           | string                       | `"The authoritative source could not be reached."` |
| `caveats[].scope`             | string                       | `"document"`, `"finding"`                          |
| `caveats[].scope_ref`         | string, may be null          | `"v2"`                                             |
| `caveats[].affected_modules`  | array of string, may be null | `["content_verification"]`                         |
| `caveats[].affected_findings` | array of string, may be null | `null`                                             |

| `severity` | How to treat it                                 |
| ---------- | ----------------------------------------------- |
| `info`     | Awareness only                                  |
| `warn`     | Results may be unreliable                       |
| `critical` | Do not rely on the result without manual review |

<Info>
  A `critical` caveat on a low-risk analysis is the case worth surfacing: it means the clean verdict itself is not dependable.
</Info>

`type` is an open list, so handle values beyond the examples above gracefully. `scope_ref` names whatever the caveat attaches to, such as a `check_id`.

## Reserved fields

Some keys arrive in the payload but are not part of the published contract. They exist for Veridox diagnostics, may change without notice, and should be ignored:

| Field                                          | Use instead                                                                                                                                |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `degraded_sections`                            | `caveats`, which is the supported way to see what limits an analysis.                                                                      |
| `blob_name`                                    | An internal reference to the stored file, not a URL. Use [Get Asset URL](/api-reference/endpoints/files-asset-url-get) with the `file_id`. |
| `integrity_signals.reuse_farmed`               | Reserved. Currently always `false`.                                                                                                        |
| `integrity_signals.metadata_manipulation_date` | Reserved. Currently always `null`.                                                                                                         |
| `integrity_signals.exif_rag_status`            | Reserved. Currently always `null`.                                                                                                         |

<Info>
  This list is not exhaustive, which is why it is worth ignoring keys you do not recognise rather than rejecting the payload.
</Info>
