View as Markdown

Document Verification API: A Developer's Guide to Integrating AI Document Checks

Everything a developer needs to integrate AI document verification into a production workflow: API authentication, request structure, response parsing, webhook events, and error handling.

Published Dec 30, 2025 • Updated Sep 14, 2026

Document Verification API: A Developer's Guide to Integrating AI Document Checks. TamperCheck.ai blog cover
Document Verification API: A Developer's Guide to Integrating AI Document Checks. TamperCheck.ai blog cover

Document verification is a solved problem at the API level - see the document verification API overview for what a production endpoint looks like. You submit a document, get back a structured JSON verdict in ~1 minute on average, and route your workflow based on the result. This guide covers everything you need to integrate from scratch - or migrate from a manual review queue.

~1m avg
median API response time
100+
document types supported
1
API endpoint for all document types
Document verification API request-response flow diagram showing POST endpoint, forensic analysis stages, and JSON verdict output
Submit any document to a single endpoint, receive a structured JSON verdict in ~1 minute on average. Route PASS directly to onboarding; FLAG to manual review queue.

Prerequisites

  • An API key from your TamperCheck account (Settings → API Keys)
  • A document to submit: PDF, JPEG, PNG, WEBP, BMP, or TIFF, up to 40 MB

Authentication

All requests use bearer token authentication. Include your API key in the Authorization header:

Authorization: Bearer tc_live_your_key_here

Use environment variables - never commit API keys to source control.

# .env
TAMPERCHECK_API_KEY=tc_live_your_key_here

Submitting a Document

Multipart Upload

The API accepts multipart/form-data with the document as a file field:

import httpx
import os
 
def verify_document(file_path: str) -> dict:
    with open(file_path, "rb") as f:
        response = httpx.post(
            "https://api.tampercheck.ai/api/v1/documents/",
            headers={"Authorization": f"Bearer {os.environ['TAMPERCHECK_API_KEY']}"},
            files={"document": f},
            data={"mode": "async"},
            timeout=30,
        )
    response.raise_for_status()
    return response.json()

The API auto-classifies every document and returns document_type in the response. No need to specify it upfront.

Parsing the Response

Submitting with mode=async returns HTTP 202 Accepted with a job ID and status: "processing". Poll GET /api/v1/documents/<id>/status/ until the job completes, then fetch the full result from GET /api/v1/documents/<id>/:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "document_type": "bank_statement",
  "document_subtype": "Indian Savings Account Statement",
  "verdict": "tampered",
  "risk_score": 64,
  "confidence": 0.87,
  "findings": [
    {
      "category": "ela_anomaly",
      "severity": "high",
      "description": "Compression anomalies detected in balance field region.",
      "confidence": 0.89
    },
    {
      "category": "font_inconsistency",
      "severity": "medium",
      "description": "Closing balance character spacing is a statistical outlier.",
      "confidence": 0.72
    }
  ],
  "human_summary": "ELA analysis found compression artefacts consistent with value replacement in the closing balance region. Font metrics reinforce the signal. Manual review recommended before proceeding."
}

Verdict Values

VerdictMeaningRecommended Action
authenticNo tampering detectedAuto-approve
tamperedOne or more high-confidence forensic findingsEscalate or reject

Working with Findings

Each finding object contains:

  • category: the forensic check that flagged (e.g. ela_anomaly, font_inconsistency)
  • severity: "low", "medium", or "high"
  • description: human-readable explanation
  • confidence: numeric confidence for this finding
def route_document(result: dict, exposure: float) -> str:
    score = result["risk_score"]
    if score >= 70:
        return "reject"
    if score >= 30 or exposure > HIGH_VALUE_THRESHOLD:
        return "manual_review"
    return "approve"
 
def get_high_severity_findings(result: dict) -> list:
    return [
        f for f in result["findings"]
        if f.get("severity") == "high"
    ]

Webhooks

For high-volume workflows, register a webhook in the Dashboard (Developers → Webhooks) and pass its UUID when uploading. TamperCheck POSTs the completed result to your endpoint when analysis finishes:

import httpx, os
 
# 1. Submit with a webhook
response = httpx.post(
    "https://api.tampercheck.ai/api/v1/documents/",
    headers={"Authorization": f"Bearer {os.environ['TAMPERCHECK_API_KEY']}"},
    files={"document": open("statement.pdf", "rb")},
    data={
        "mode": "async",
        "webhook_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    },
)
job_id = response.json()["id"]  # store this
 
# 2. Receive the webhook payload at your registered URL
# POST https://yourapp.com/webhooks/tampercheck
# Headers: X-Webhook-ID, X-Webhook-Signature
# Body: same shape as GET /api/v1/documents/<id>/

Webhook Security

Verify that webhooks originate from TamperCheck by checking the X-Webhook-Signature header:

import hmac
import hashlib
 
def verify_webhook(payload: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256,
    ).hexdigest()
    provided = signature_header.removeprefix("sha256=")
    return hmac.compare_digest(expected, provided)

Always verify webhook signatures before processing the payload. Unverified webhooks can be forged to trigger approval of fraudulent documents.

Error Handling

The API returns standard HTTP status codes:

StatusMeaningHandling
202Accepted (async)Poll for results
400Invalid requestFix payload (check error field)
401Invalid API keyCheck key and permissions
402Insufficient wallet balanceAdd funds at /dashboard/billing
422Document unreadableRequest resubmission
503Service unavailableRetry with backoff
import time
 
def verify_with_retry(file_path: str, max_retries: int = 3) -> dict:
    for attempt in range(max_retries):
        try:
            return verify_document(file_path)
        except httpx.HTTPStatusError as e:
            if e.response.status_code >= 500:
                time.sleep(2 ** attempt)
            else:
                raise  # don't retry client errors
    raise RuntimeError("Max retries exceeded")

TypeScript / Node.js Example

import fs from "fs";
 
interface SubmitResult {
  id: string;
  status: string;
}
 
interface VerificationResult {
  id: string;
  status: string;
  verdict: "authentic" | "tampered";
  risk_score: number;
  confidence: number;
  findings: Array<{
    category: string;
    severity: "low" | "medium" | "high";
    description: string;
    confidence: number;
  }>;
  human_summary: string;
}
 
async function submitDocument(filePath: string): Promise<SubmitResult> {
  const formData = new FormData();
  formData.append("document", new Blob([fs.readFileSync(filePath)]), filePath);
  formData.append("mode", "async");
 
  const response = await fetch("https://api.tampercheck.ai/api/v1/documents/", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.TAMPERCHECK_API_KEY}`,
    },
    body: formData,
  });
 
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.detail}`);
  }
 
  return response.json();
}

Get your API key

We match your first top-up in free credits - no contract, no minimum commitment. Integrate in under an hour.

Test a fake document →

FAQ

What's the rate limit for the document verification API?

Default rate limits are 60 requests per minute per API key. Contact support to discuss higher limits for production workflows.

Can I use my own AI provider key with the API?

No: AI inference is managed by TamperCheck on audited models, so there is no provider account to connect and no keys for you to rotate. Inference is included in the per-document price, so there is no separate provider bill to reconcile. New accounts include free trial credits to get started.

Is document data stored after analysis?

By default, document content is processed in memory and not persisted beyond the analysis job. Job metadata (verdict, findings, timestamps) is retained for audit purposes. See the Privacy Policy for full data handling details.

What file formats are supported?

PDF, JPEG, PNG, WEBP, BMP, and TIFF. Multi-page PDFs are supported. Scanned documents and digital PDFs are both accepted; the AI adjusts its analysis approach based on detected document origin.

What forensic checks does the API actually run?

The API runs 200+ independent forensic checks per document - including ELA, font metrics, arithmetic integrity, metadata analysis, MRZ validation, template matching, and AI generation detection. For a plain-English explanation of each check and what fraud it catches, see How AI Agents Detect Forged Documents and the Complete Guide to Document Tampering and Fraud.

Which industries use document verification APIs?

The primary use cases are KYC and financial onboarding, lending (mortgage and personal credit), insurance claims processing, rental application screening, and employment credential verification. See dedicated guides for each: KYC automation, insurance claims, rental applications, and HR credential checks.

Frequently asked questions

What's the rate limit for the document verification API?
Default rate limits are 60 requests per minute per API key. Contact support to discuss higher limits for production workflows.
Can I use my own AI provider key with the API?
No: AI inference is managed by TamperCheck on audited models, so there is no provider account to connect and no keys for you to rotate. Inference is included in the per-document price, so there is no separate provider bill to reconcile. New accounts include free trial credits to get started.
Is document data stored after analysis?
By default, document content is processed in memory and not persisted beyond the analysis job. Job metadata (verdict, findings, timestamps) is retained for audit purposes. See the Privacy Policy for full data handling details.
What file formats are supported?
PDF, JPEG, PNG, WEBP, BMP, and TIFF. Multi-page PDFs are supported. Scanned documents and digital PDFs are both accepted; the AI adjusts its analysis approach based on detected document origin.
What forensic checks does the API actually run?
The API runs 200+ independent forensic checks per document - including ELA, font metrics, arithmetic integrity, metadata analysis, MRZ validation, template matching, and AI generation detection. For a plain-English explanation of each check and what fraud it catches, see How AI Agents Detect Forged Documents and the Complete Guide to Document Tampering and Fraud.
Which industries use document verification APIs?
The primary use cases are KYC and financial onboarding, lending (mortgage and personal credit), insurance claims processing, rental application screening, and employment credential verification. See dedicated guides for each: KYC automation, insurance claims, rental applications, and HR credential checks.

Share this article

Think you can spot a fake?

Upload a suspicious document and let TamperCheck do the forensics - a clear verdict within seconds. Free credits to start, no contract.

Filed under

document verification APIdeveloper guideAPI integrationdocument fraud detection APIdocument verification API integrationfraud detection API PythonKYC API developerdocument analysis REST API