Verify Overview
Verify is in beta. The endpoints return 404 NOT_FOUND unless Verify is enabled for your organization. Contact support@extend.ai to request access. Verify runs are not metered during the beta, so usage is null on every run.
Verify checks one document for evidence of fraud: whole-document fabrication, localized edits, and suspicious file internals. You submit a PDF, JPEG, PNG, or WebP and get back a document-level riskLevel (LOW, MEDIUM, or HIGH), a plain-language summary, and the detected signals, each with typed, locatable evidence that a reviewer can check against the file. Use it to screen bank statements, pay stubs, invoices, identity credentials, and any other document a person could alter before uploading.
Verify analyzes the exact bytes you submit. It combines deterministic checks of file metadata and PDF internals (signatures, revision history, hidden layers, fonts) with detection models for image manipulation and AI generation, then an assessment model grades each detection in the context of the whole document. It does not perform identity verification, compare documents to each other, or claim that a document is genuine: a LOW risk level means the checks that ran found nothing, not that the document is authentic.
Quick start
We’ll verify a bank statement that has been tampered with. It is the sample statement from the Parsing quick start, digitally signed with a “no changes allowed” certification signature, then edited after signing to delete one row (a $15.00 incoming wire fee) from the Fees and Other Withdrawals table on page 6, leaving the printed section total unchanged. For this quick start we’ve uploaded the file here.
Grab a key from the Developers page and store it as the EXTEND_API_KEY environment variable. If you’re using an SDK, see the installation instructions.
The /verify endpoint takes a file and an optional config. With no config, it uses the default verify_agentic engine, which parses the document and runs every supported check.
Python
TypeScript
Java
Go
cURL
Want to verify your own document? Upload it first, then pass the returned file id instead of a url. Verify accepts PDF, JPEG, PNG, and WebP files.
Python
TypeScript
Java
Go
cURL
Example response
This is the response the run above returns, with repetitive evidence locations trimmed. Verify found the edit three different ways: the file’s revision history shows page 6 replaced after the signature, the signature check shows that the certification forbade any change, and the content check shows the fee rows no longer add up to the printed total. A fourth signal, about font subsets and clipped overflow text, was detected but graded LOW because the assessment recognised it as ordinary template behaviour. The sample statement is also missing page 2 of 10, which the content check reports as a page-number gap.
A document with nothing detected returns "riskLevel": "LOW", "summary": "No fraud signals were detected.", and an empty signals array.
Key fields
For every field, see Response Format. For full request/response details, see the Verify File API reference.
Use the output
Route on riskLevel, then surface the signals and their summaries to whoever reviews the document.
Python
TypeScript
Java
Go
Sync vs async
The example above calls the synchronous /verify endpoint, which times out after 5 minutes on both engines. A timed-out request usually fails with 504 Gateway Timeout and no runId, while the run keeps processing in the background. verify_agentic runs often take longer than that. For production workloads, use the asynchronous /verify_runs endpoint: it returns a run in the PROCESSING state immediately, and you poll GET /verify_runs/{id} until status is PROCESSED, FAILED, or CANCELLED. GET /verify_runs lists past runs with their risk levels, and DELETE /verify_runs/{id} removes a run and the data derived from its document.
Webhook events for verify runs are not available yet, and the SDKs do not yet include a create_and_poll / createAndPoll helper for verify runs. Poll the run as shown below. See Async Processing for the general pattern.
Python
TypeScript
Java
Go
What Verify checks
Findings are reported as Public Signal categories, a stable enum. The current engine release runs checks in these categories:
Configuration
The quick start uses default settings. To control a run, pass a config object alongside file. For the full reference, see Configuration.
Engine
Parsing on the light engine
verify_light skips the parse for speed. Set advancedOptions.requireParsing to add the checks that read the parse, such as the comparison of a scan’s hidden text layer against the page. verify_agentic always parses and rejects false.
Supported inputs
- File types: PDF, JPEG, PNG, and WebP. Other types fail with
FILE_TYPE_NOT_SUPPORTED. A file that claims to be a PDF but is not still runs, because the mismatch is itself a signal. - Input methods: a public
urlor an Extend fileid. - Data retention: a verify run inherits the retention mode of its file. For zero-retention files the result is delivered once, in the sync response or the first
GET, and purged afterwards, so store what you need from that response.DELETE /verify_runs/{id}removes any run’s derived data on demand.
Via Extend Studio
Studio includes a Verify playground where you can run a file, browse past runs, and inspect each signal’s evidence highlighted on the document. Open Verify in Studio (it is visible only to organizations enrolled in the beta). Studio runs use the same engine, configuration options, and result shape as the API.
What Verify is not
- Not identity verification. Verify says nothing about whether the person submitting a document is who they claim to be, and it never links a document to a person.
- Not cross-document analysis. Each run looks at one file. It does not compare submissions to each other or to previously seen documents.
- Not a certificate of authenticity. Signals are returned only when detected. An empty
signalsarray means the checks that ran found nothing; it does not mean every check applied, or that the document is genuine.

