Using the Verify API
Upload a document, create a Verify job, retrieve its authenticity assessment, and inspect supporting evidence with the Verify Preview API from the SDKs or REST.
The Verify API runs an asynchronous authenticity review for a document or image. API access is limited during the Preview and the API may change.
Before you begin
Section titled “Before you begin”To call the Verify API, you need:
- A LlamaCloud API key with access to Verify
- The ID of the LlamaCloud project that will own the job
- A PDF, DOCX, PNG, JPEG, or WebP file to review
Set the API key and project ID as environment variables:
export LLAMA_CLOUD_API_KEY="llx-..."export PROJECT_ID="YOUR_PROJECT_ID"Set up an SDK client for Verify
Section titled “Set up an SDK client for Verify”The SDKs expose Verify as client.alpha.verify, starting in Python and
TypeScript 2.18.0, Java 1.9.0 and Go 1.10.0. The alpha namespace means these
methods can change between minor releases. Each step below also shows the
equivalent REST call.
pip install "llama-cloud>=2.18"import osimport time
from llama_cloud import LlamaCloud
client = LlamaCloud(api_key=os.environ["LLAMA_CLOUD_API_KEY"])npm install @llamaindex/llama-cloudimport fs from "fs";import LlamaCloud from "@llamaindex/llama-cloud";
const client = new LlamaCloud({ apiKey: process.env.LLAMA_CLOUD_API_KEY });go get github.com/run-llama/llama-parse-goimport ( "context" "fmt" "log" "os" "time"
llamacloud "github.com/run-llama/llama-parse-go")
ctx := context.Background()client := llamacloud.NewClient() // reads LLAMA_CLOUD_API_KEYimplementation("ai.llamaindex:llama-cloud:1.9.0")import ai.llamaindex.llamacloud.client.LlamaCloudClient;import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyCreateParams;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyCreateResponse;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyGetDetailsResponse;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyGetParams;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyGetResponse;import ai.llamaindex.llamacloud.models.alpha.verify.VerifyListParams;import ai.llamaindex.llamacloud.models.files.FileCreateParams;import ai.llamaindex.llamacloud.models.files.FileCreateResponse;import java.nio.file.Paths;
LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();Run a Verify job
Section titled “Run a Verify job”1. Upload the file
Section titled “1. Upload the file”Download a sample PDF with edited totals to review:
curl -fL -o document.pdf https://cloud.llamaindex.ai/assets/demos/verify/overrun-totals-fraud.pdfUpload the document with the Files API:
file_obj = client.files.create(file="document.pdf", purpose="user_data")file_id = file_obj.idconst fileObj = await client.files.create({ file: fs.createReadStream("document.pdf"), purpose: "user_data",});const fileId = fileObj.id;f, err := os.Open("document.pdf")if err != nil { log.Fatal(err)}defer f.Close()
fileObj, err := client.Files.New(ctx, llamacloud.FileNewParams{ File: f, Purpose: "user_data",})if err != nil { log.Fatal(err)}fileID := fileObj.IDFileCreateResponse fileObj = client.files().create( FileCreateParams.builder() .file(Paths.get("document.pdf")) .purpose("user_data") .build());String fileId = fileObj.id();curl --request POST \ "https://api.cloud.llamaindex.ai/api/v1/beta/files?project_id=${PROJECT_ID}" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}" \ --form "file=@document.pdf" \ --form "purpose=user_data"Save the file’s id as FILE_ID.
2. Create the job
Section titled “2. Create the job”Create a Verify job for the uploaded file:
job = client.alpha.verify.create( file_input=file_id, configuration={"tier": "agentic"},)print(job.id, job.status)const job = await client.alpha.verify.create({ file_input: fileId, configuration: { tier: "agentic" },});console.log(job.id, job.status);job, err := client.Alpha.Verify.New(ctx, llamacloud.AlphaVerifyNewParams{ FileInput: fileID, Configuration: llamacloud.AlphaVerifyNewParamsConfiguration{Tier: "agentic"},})if err != nil { log.Fatal(err)}fmt.Println(job.ID, job.Status)VerifyCreateResponse job = client.alpha().verify().create( VerifyCreateParams.builder() .fileInput(fileId) .configuration(VerifyCreateParams.Configuration.builder() .tier(VerifyCreateParams.Configuration.Tier.AGENTIC) .build()) .build());System.out.println(job.id() + " " + job.status());curl --request POST \ "https://api.cloud.llamaindex.ai/api/alpha/verify?project_id=${PROJECT_ID}" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}" \ --header "Content-Type: application/json" \ --data '{ "file_input": "FILE_ID", "configuration": { "tier": "agentic" } }'The response includes the Verify job id and its initial status. Save the
id as JOB_ID.
The request body accepts:
| Field | Description |
|---|---|
file_input | Required. The ID of the uploaded file to review. Files are currently the only supported input, and the job’s document_input_type always reflects a file input. |
configuration | Optional review configuration; defaults apply when omitted. |
transaction_id | Optional idempotency key, scoped to the project. Reusing a key returns the original job; the new request body is ignored. |
webhook_configurations | Optional list of outbound webhook endpoints to notify on job status changes. Verify jobs send verify.* events; see Webhooks for the event list and payload. |
webhook_configuration_ids | Optional list of up to 4 saved webhook configuration IDs to notify for this job. See Reusing a saved configuration. |
The configuration object accepts:
| Field | Description |
|---|---|
tier | fast for a quick initial screen or agentic for a more comprehensive review. The default is agentic. The fast tier is designed for scans and born-digital documents; photographed documents, such as phone captures, should use the agentic tier for reliable results. |
target_pages | Optional comma-separated, 1-based PDF page numbers or ranges, such as 1,3,5-7. Omit it to review every page. This field is ignored for other file types. |
3. Retrieve the result
Section titled “3. Retrieve the result”Verify jobs move through PENDING and RUNNING before reaching COMPLETED,
FAILED, or CANCELLED. Poll the job until it leaves those states, asking for
the result with expand=result:
job = client.alpha.verify.get(job.id, expand=["result"])while job.status in ("PENDING", "RUNNING"): time.sleep(5) job = client.alpha.verify.get(job.id, expand=["result"])
if job.status == "COMPLETED" and job.result: print(job.result.verdict, job.result.overall_score)let current = await client.alpha.verify.get(job.id, { expand: ["result"] });while (current.status === "PENDING" || current.status === "RUNNING") { await new Promise((resolve) => setTimeout(resolve, 5000)); current = await client.alpha.verify.get(job.id, { expand: ["result"] });}
if (current.status === "COMPLETED" && current.result) { console.log(current.result.verdict, current.result.overall_score);}getParams := llamacloud.AlphaVerifyGetParams{Expand: []string{"result"}}current, err := client.Alpha.Verify.Get(ctx, job.ID, getParams)if err != nil { log.Fatal(err)}for current.Status == "PENDING" || current.Status == "RUNNING" { time.Sleep(5 * time.Second) current, err = client.Alpha.Verify.Get(ctx, job.ID, getParams) if err != nil { log.Fatal(err) }}
if current.Status == "COMPLETED" { fmt.Println(current.Result.Verdict, current.Result.OverallScore)}VerifyGetParams getParams = VerifyGetParams.builder().addExpand("result").build();VerifyGetResponse current = client.alpha().verify().get(job.id(), getParams);while (current.status().equals(VerifyGetResponse.Status.PENDING) || current.status().equals(VerifyGetResponse.Status.RUNNING)) { Thread.sleep(5000); current = client.alpha().verify().get(job.id(), getParams);}
current.result().ifPresent(result -> System.out.println(result.verdict() + " " + result.overallScore()));curl --request GET \ "https://api.cloud.llamaindex.ai/api/alpha/verify/JOB_ID?project_id=${PROJECT_ID}&expand=result" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}"When the status is COMPLETED, the result object includes:
| Field | Description |
|---|---|
verdict | The overall authenticity assessment. |
overall_score | The document’s doctoring likelihood from 0 to 1. |
confidence | How strongly the available evidence supports the verdict, from 0 to 1. |
tampering_score | Likelihood that a real document was edited locally, from 0 to 1. |
synthetic_score | Likelihood that the document was fabricated as a whole, from 0 to 1. |
reasoning | A plain-language explanation of the verdict. |
composite_scores | Scores for the different authenticity questions that applied to the document. |
suspect_regions | Ranked document areas that contributed to the assessment, when findings can be localized. |
See Interpreting Verify findings for guidance on using these fields in a review workflow.
4. Inspect supporting evidence
Section titled “4. Inspect supporting evidence”After a job completes, retrieve the detailed findings behind the result:
details = client.alpha.verify.get_details(job.id)for heatmap in details.heatmaps or []: print(heatmap.page, heatmap.kind, heatmap.url, heatmap.expires_at)const details = await client.alpha.verify.getDetails(job.id);for (const heatmap of details.heatmaps ?? []) { console.log(heatmap.page, heatmap.kind, heatmap.url, heatmap.expires_at);}details, err := client.Alpha.Verify.GetDetails(ctx, job.ID, llamacloud.AlphaVerifyGetDetailsParams{})if err != nil { log.Fatal(err)}for _, heatmap := range details.Heatmaps { fmt.Println(heatmap.Page, heatmap.Kind, heatmap.URL, heatmap.ExpiresAt)}VerifyGetDetailsResponse details = client.alpha().verify().getDetails(job.id());details.heatmaps().ifPresent(heatmaps -> heatmaps.forEach(heatmap -> System.out.println(heatmap.page() + " " + heatmap.kind() + " " + heatmap.url())));curl --request GET \ "https://api.cloud.llamaindex.ai/api/alpha/verify/JOB_ID/details?project_id=${PROJECT_ID}" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}"The details include supporting evidence, grouped scores, localized regions, visual overlays, and checks that could not run. A check listed as unavailable did not produce a clean result; it did not run successfully for that file.
Each entry in evidence describes one finding: the tool that produced it,
its signal family, a machine-readable code, a human-readable detail, a
score, and hard, which is true when the finding is conclusive on its own.
metadata holds the raw values from that tool. Its keys vary by tool, so
treat it as supporting detail for display or audit rather than a fixed shape.
The page field on regions, heatmaps, page_dimensions, and
suspect_regions counts from 0: the first page of a PDF, or a standalone image,
is page 0. target_pages counts from 1, so a job whose configuration sets
target_pages to "3" reports those regions on page 2. Page numbers inside
metadata or a detail message come from the individual tool and can
count from 1.
Each localized region carries a review field with the reviewer’s verdict on
that candidate: confirmed, dismissed, or unsure, or an empty string when
the region was not individually reviewed. A review_note explains the verdict.
Dismissed candidates are excluded from the curated suspect_regions list in
the job result but remain visible here.
Heatmap URLs expire
Section titled “Heatmap URLs expire”Visual overlays are returned as presigned URLs that expire about an hour after
the response is generated; each overlay’s expires_at gives the exact time.
Treat them as temporary download links: if you need overlays for an audit trail
or later review, download the image bytes and store them yourself. Do not persist the URLs — a stored URL will stop working.
Re-requesting the details endpoint issues fresh URLs for as long as the job is
retained.
Manage Verify jobs
Section titled “Manage Verify jobs”| Action | Method and path |
|---|---|
| Create a job | POST /api/alpha/verify |
| Retrieve a job | GET /api/alpha/verify/{job_id} |
| Retrieve supporting evidence | GET /api/alpha/verify/{job_id}/details |
| List jobs | GET /api/alpha/verify |
| Cancel a running job | POST /api/alpha/verify/{job_id}/cancel |
project_id selects the project; without it, requests use the API key’s
project. List requests can be filtered by status, job ID, or creation time and
use page_size and page_token for pagination.
List the jobs that are still running, and cancel one by ID. Only PENDING and
RUNNING jobs can be cancelled:
for listed in client.alpha.verify.list(status="RUNNING"): print(listed.id, listed.file_input)
client.alpha.verify.cancel("JOB_ID")for await (const listed of client.alpha.verify.list({ status: "RUNNING" })) { console.log(listed.id, listed.file_input);}
await client.alpha.verify.cancel("JOB_ID");iter := client.Alpha.Verify.ListAutoPaging(ctx, llamacloud.AlphaVerifyListParams{ Status: llamacloud.AlphaVerifyListParamsStatusRunning,})for iter.Next() { fmt.Println(iter.Current().ID, iter.Current().FileInput)}if err := iter.Err(); err != nil { log.Fatal(err)}
if _, err := client.Alpha.Verify.Cancel(ctx, "JOB_ID", llamacloud.AlphaVerifyCancelParams{}); err != nil { log.Fatal(err)}client.alpha().verify() .list(VerifyListParams.builder().status(VerifyListParams.Status.RUNNING).build()) .autoPager() .forEach(listed -> System.out.println(listed.id() + " " + listed.fileInput()));
client.alpha().verify().cancel("JOB_ID");curl --request GET \ "https://api.cloud.llamaindex.ai/api/alpha/verify?project_id=${PROJECT_ID}&status=RUNNING" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}"
curl --request POST \ "https://api.cloud.llamaindex.ai/api/alpha/verify/JOB_ID/cancel?project_id=${PROJECT_ID}" \ --header "Authorization: Bearer ${LLAMA_CLOUD_API_KEY}"Creating and cancelling a job need write access to the project. A user or API
key with read-only access gets 403 Forbidden from those two requests and can
still retrieve, list, and inspect jobs.