Skip to content

FraudScanner

Image and document verification.

Upload a ZIP file for fraud analysis

Request

Analyze image and document files for fraud indicators.

There are two ways to send your ZIP file, depending on its size:

ZIP sizeMethodHow
< 10 MBDirect uploadSend the ZIP as file in the request body (multipart/form-data)
10–50 MBPresigned S3 uploadFirst call POST /v2/getUploadUrl, upload to S3, then call this endpoint with s3_key as query parameter

For files under 10 MB, nothing changes — use the direct upload as before. For larger files, the presigned flow bypasses the 10 MB gateway limit.

And two ways to receive your attachments:

ModeYou getWhen
Inline (default)Attachments in the response itself — as ZIP parts (multipart/mixed) or Base64 (application/json), controlled by the Accept headerDefault for every account
Presigned downloadA plain JSON response plus attachmentDownloadUrl, a link to a single ZIP holding all attachmentsIf the presigned-download feature is enabled for you

If the presigned download is enabled, it applies to every response and takes precedence over the Accept header: you always receive application/json without inline attachments, and never a multipart/mixed body. The upside is that the ~9 MB response payload cap no longer applies to your attachments, so nothing gets dropped for large cases. See attachmentDownloadUrl in the response schema.

Minimal example (direct upload):

import requests

resp = requests.post(
    "https://api.vaarhaft.com/v2/fraudscanner",
    headers={"x-api-key": "YOUR_KEY", "caseNumber": "Case-123"},
    files={"file": open("images.zip", "rb")},
)
...

When an analysis takes longer than 120 seconds

Requests with many or large files can take longer, because the analysis is compute-heavy. The connection is closed after 120 seconds - but the analysis is not cancelled. It keeps running and finishes on our side.

You getWhat it meansWhat to do
504The 120s limit was reached. The analysis is still running.Wait ~30s, then send the identical request again.
202The analysis is still running and whoever started it is gone. Retry-After says how long to wait.Wait that many seconds, then send the identical request again.
409The same case is already being analysed for a caller who is still connected.Do not retry - wait for the answer to the first request.

Where results are kept for your account (see x-result-cache at the top of this document), the repeated request hands you the finished result straight away instead of starting a second analysis. Two things have to match for that: the same case number and the same files. Re-zipping the identical files is fine - we compare the contents, not the archive. Different files under the same case number are treated as a new question and analysed normally.

A run that was cut off at 120 seconds is not charged - you did not receive it. The repeated request that actually hands you the result is.

Security
apiKeyAuth
Query
s3_keystring

The S3 key returned by POST /v2/getUploadUrl. Use this instead of file for ZIPs larger than 10 MB. Either file (body) or s3_key (query) must be provided — not both, not neither.

Headers
x-api-keystring, = 40 charactersrequired

The API key for authentication.

caseNumberstring, [ 4 .. 50 ] charactersrequired

A case number to assign to the request. Typically matches the one that you use internally to track the files you're sending us. Between 4 and 50 characters.

issueDatestring

The issue date of the case, if available. Used as reference date for date-related checks (e.g. metadata timestamps). Accepted formats: DD.MM.YYYY, DD-MM-YYYY, DD/MM/YYYY, YYYY-MM-DD, YYYY.MM.DD, each optionally followed by HH:MM:SS. May not be more than 5 days in the future.

Example:24.02.2026
languagestring

The language setting for the request; used for the generated analysis report and for textual explanations in the response. Defaults to 'de' (German).

Enum:"de""en""pl"
contactEmailstring, (email)

Optional contact email address for this request, used for result notifications where that is part of your configuration.

Acceptstring

Optionally set the desired response media type. Use application/json for a JSON response with Base64-encoded attachments grouped by category (actual files: PDFs, PNGs, etc.; no ZIP bundles). If the header is not set, or if multipart/mixed or */* is set, the server will respond with JSON plus one or more ZIP attachments (e.g., heatmaps, reports), combined in a multipart response. This is the standard way to consume the FraudScanner API.

Enum:"application/json""multipart/mixed""*/*"
Example:application/json
Bodymultipart/form-data

Required for direct upload (files < 10 MB). Omit when using the presigned S3 upload flow with s3_key.

filestring, (binary)

The ZIP file to be uploaded for analysis. Required for direct upload (< 10 MB). Omit when using the presigned S3 upload flow.

curl -i -X POST \
  'https://api.vaarhaft.com/v2/fraudscanner?s3_key=string' \
  -H 'Accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -H 'caseNumber: string' \
  -H 'contactEmail: user@example.com' \
  -H 'issueDate: 24.02.2026' \
  -H 'language: de' \
  -H 'x-api-key: YOUR_API_KEY_HERE' \
  -F file=string

Responses

Success. The file was successfully uploaded and processed. May carry the header X-Payload-Truncated: true if attachments had to be dropped to stay within the payload limit. If the presigned-download feature is enabled for you, the response is always application/json and the attachments are not inline - use attachmentDownloadUrl instead.

Body
suspicion_levelstring(SuspicionLevel)

An indicator as to how suspicious the contents of the request were. Is calculated from the suspicion levels of the contained files.

Enum ValueDescription
-

No statement possible / not assessed (e.g. insufficient input quality, or the object was not relevant for the analysis).

Green

No findings.

Yellow

Findings that warrant a look.

Red

Strong findings.

Example:"Yellow"
Filesobject

A mapping of filename to file analysis results.

caseNumberstring

The case number assigned to the request.

Example:"Case 123A"
sessionIdstring, (uuid)

A unique identifier generated for the request. Please include it in support requests.

Example:"5a8d8fd2-3317-4964-8298-caa96cd5cfa3"
modelVersionsobject

Overview of the internal VAARHAFT AI models used for classification.

tokensConsumedinteger

The amount of API tokens that were consumed by this request, depending for example on the number and types of processed files.

Example:12
cross_file_analysesobject or null

Optional add-on: checks that compare the submitted documents against each other across the whole request. Only present if the corresponding feature is enabled for you. Contact us for the detailed schema.

agenticRecommendationobject or null

Optional add-on: a consolidated, case-level recommendation summarising the findings of the request. Only present if the corresponding feature is enabled for you. Contact us for the detailed schema.

attachmentDownloadUrlstring or null, (uri)

Link to download all attachments of this request as a single ZIP, instead of receiving them inline. Only present if the presigned-download feature is enabled for you; null / absent otherwise.

How it works:

  • Whenever this mode is active, the response is always plain application/json with no inline attachments - no multipart/mixed body and no Base64 attachments map, regardless of the Accept header. Because the attachments no longer travel in the response, the ~9 MB payload cap does not apply to them.
  • Download it with a simple GET. The link is already signed, so no x-api-key is needed - treat it as a secret.
  • The link is valid for 12 hours; the stored file is deleted automatically after 24 hours.
  • The download is one ZIP (attachments.zip) that contains the per-category ZIPs as entries, i.e. the same bundles as the multipart mode: analysis_report.zip, enfsi_report.zip, heatmaps.zip, thumbnails.zip, reverse_search_downloads.zip, pdf_versions.zip, pdf_diffs.zip - whichever were generated for the request.
Example:"https://downloads.vaarhaft.com/responses/company123/5a8d8fd2-3317-4964-8298-caa96cd5cfa3.zip?..."
pdfReportMappingobject or null

Maps each input filename to the 1-based page of its detail view in the analysis report PDF. Empty when no report was generated. Only present if the corresponding feature is enabled for you.

Example:
{ "damage_photo.jpg": 4, "invoice.pdf": 7 }
etagstring or null

Internal value used by our own frontend clients; null for API integrations.

pdfEditingToolsBlacklistArray of strings or null

Internal value used by our own frontend clients; null for API integrations.

attachmentsobject

Map of 'categories-to-lists' for attachment objects (only relevant for pure JSON responses; see the 'Accept' header). Attachments are base64 encoded strings of the raw files. Categories:

  • analysis_report (PDF files)
  • enfsi_report (PDF files)
  • heatmaps (PNG files)
  • thumbnails (PNG files)
  • downloads (reverse search results; different formats)
  • pdf_versions (PDF files)
  • pdf_diffs (PDF files)
Response
{ "suspicion_level": "Yellow", "Files": { "<FileName>1": { … }, "<FileName>2": { … } }, "caseNumber": "Case 123A", "sessionId": "5a8d8fd2-3317-4964-8298-caa96cd5cfa3", "modelVersions": { "imagesModelVersion": "vh-mo-images-alpha", "documentsModelVersion": "vh-mo-docs-alpha" }, "tokensConsumed": 12, "cross_file_analyses": {}, "agenticRecommendation": {}, "attachmentDownloadUrl": "https://downloads.vaarhaft.com/responses/company123/5a8d8fd2-3317-4964-8298-caa96cd5cfa3.zip?...", "pdfReportMapping": { "damage_photo.jpg": 4, "invoice.pdf": 7 }, "etag": "string", "pdfEditingToolsBlacklist": [ "string" ], "attachments": { "heatmaps": [ … ], "thumbnails": [ … ], "downloads": [ … ], "pdf_versions": [ … ], "pdf_diffs": [ … ], "analysis_report": [ … ], "enfsi_report": [ … ] } }