For decision makers: TamperCheck connects to your stack over a standard REST API. Most teams finish the integration in about one sprint. No proprietary format, and no mandatory dashboard for compliance work. The reference below is for engineers building the integration.

API & MCP documentation

REST API & MCP for using TamperCheck's document fraud analysis, deepfake detection, and scan extraction all from your platform or integration with MCP.

Copy for AI

Paste into Cursor, Claude, or ChatGPT so it can wire up the TamperCheck REST API with the right auth, endpoints, and response shapes.

Authentication

Send your API key as Authorization: Bearer dt_... (or X-API-Key). Create keys under Dashboard → Developers.

API reference

Base URL: https://api.tampercheck.ai. Every route needs your API key except the PDF download URL returned by report-link.

MethodPathWhat it does
POST/api/v1/documents/Upload a file and start analysis
POST/api/v1/extract-documents/Split a multi-page scan into cropped images
GET/api/v1/documents/list/List past jobs visible to your key
GET/api/v1/documents/search/Search by job id, file name or your own identifier
GET/api/v1/documents/<uuid>/status/Check if a job is still running
GET/api/v1/documents/<uuid>/Get the full result for a job
POST/api/v1/documents/<uuid>/report-link/Create a temporary link to the PDF report
GET/api/v1/reports/download/Download the PDF from that temporary link
GET/api/v1/documents/<uuid>/notes/List notes on a job
POST/api/v1/documents/<uuid>/notes/Add a note on a job
POST/api/v1/team/invites/Email an invite to join your team
GET/api/v1/usage/Usage totals for billing
GET/api/v1/wallet/usage/Credit and debit history for your wallet

Strategies

Choose what kind of work a job does. Analyze accepts a strategy field; extraction always uses its own endpoint.

StrategyHow to callReturns
tampering_detection
Default
POST /documents/authentic / tampered, risk score, findings
deepfake_detectionPOST /documents/ + strategy=deepfake_detectionauthentic / ai_generated / face_swap / uncertain, plus artifact_breakdown
document_extractionPOST /extract-documents/Page-scoped pages[].images[] crops (no verdict)

Analyze

POSThttps://api.tampercheck.ai/api/v1/documents/

Multipart upload. File field document (PDF, JPG, JFIF, PNG, WEBP, BMP, TIFF; max 40 MB).

FieldRequiredDescription
documentYesFile to analyze
strategyNotampering_detection (default; PDF or image) or deepfake_detection (images only)
document_identifierNoYour correlation id (max 512)
webhook_idNoNotify this webhook UUID. Omit to skip delivery.
suppress_categoriesNoJSON array of finding keys to exclude
pdf_passwordNoPassword for encrypted PDFs. Returns pdf_password_required (400) if needed but missing, pdf_password_incorrect (400) if wrong.
curl -sS -X POST "https://api.tampercheck.ai/api/v1/documents/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "document=@./statement.pdf" \
  -F "strategy=tampering_detection" \
  -F "document_identifier=loan-app-12345"

Deepfake example

curl -sS -X POST "https://api.tampercheck.ai/api/v1/documents/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "document=@./portrait.jpg" \
  -F "strategy=deepfake_detection"

Getting results

Upload returns 202 with a job id while analysis runs. Poll status, then fetch the full detail, or use webhooks.

202 Accepted body

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "original_filename": "statement.pdf",
  "document_identifier": "loan-app-12345",
  "page_count": 3,
  "documents_billed": 3
}

Poll with exponential backoff (start ~1s, cap ~5-10s). Stop on completed or failed.

Completed responses

Tampering detection

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "strategy": "tampering_detection",
  "original_filename": "statement.pdf",
  "document_identifier": "loan-app-12345",
  "document_type": "bank_statement",
  "document_subtype": "Indian Savings Account Statement",
  "verdict": "tampered",
  "risk_score": 42,
  "confidence": 0.78,
  "page_count": 1,
  "documents_billed": 1,
  "findings": [
    {
      "category": "font_inconsistency",
      "severity": "medium",
      "description": "Mixed font metrics in the totals row.",
      "confidence": 0.71
    }
  ],
  "human_summary": "Plain-language summary of the main issues.",
  "created_at": "2026-04-02T12:00:00Z",
  "completed_at": "2026-04-02T12:00:03Z"
}

Deepfake detection

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "strategy": "deepfake_detection",
  "verdict": "ai_generated",
  "risk_score": 88,
  "confidence": 0.91,
  "findings": [
    {
      "category": "provenance",
      "severity": "high",
      "description": "Missing camera metadata typical of generator output."
    }
  ],
  "artifact_breakdown": {
    "provenance": {
      "score": 92,
      "issues": [
        "missing EXIF"
      ]
    }
  },
  "human_summary": "Strong signals of AI image generation."
}

Extract documents

POSThttps://api.tampercheck.ai/api/v1/extract-documents/

Split a multi-document scan into PNG crops. Same auth and optional webhook_id as analyze. Response strategy is document_extraction. Billed as extraction usage when the job completes.

curl -sS -X POST "https://api.tampercheck.ai/api/v1/extract-documents/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "document=@./scan.pdf"

Completed shape

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "strategy": "document_extraction",
  "original_filename": "scan.pdf",
  "page_count": 2,
  "documents_billed": 1,
  "pages": [
    {
      "page": 1,
      "images": [
        {
          "index": 1,
          "content_type": "image/png",
          "data": "<base64>",
          "bbox": {
            "x": 12,
            "y": 40,
            "width": 800,
            "height": 1200
          }
        }
      ]
    }
  ]
}

Suppress categories

On analyze only: exclude finding categories from the verdict and risk score. Unknown keys are ignored.

curl -sS -X POST "https://api.tampercheck.ai/api/v1/documents/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "document=@./bank_statement.pdf" \
  -F "suppress_categories=["signature_forgery", "jpeg_ghost_splicing"]"

Common keys: signature_forgery, jpeg_ghost_splicing, ela_anomaly, font_size_inconsistency, metadata_image_editor, double_jpeg_compression.

List, status & detail

GEThttps://api.tampercheck.ai/api/v1/documents/list/

Jobs visible to your key, newest first, with summary fields only (verdict, risk score, confidence, page count, identifiers, timestamps, and uploaded_by). Each key has a document access scope, chosen when you create it: an organization key (the default) sees every document uploaded by your team, and an individual key sees only documents uploaded by the key's owner. The same scope applies to search, status, results, report links, notes and usage. Add page and page_size (max 100) to get a paginated response with count, nextand results. Without them you get the full array, which can be large for accounts with many jobs, so passpage_size for listings.

curl -sS "https://api.tampercheck.ai/api/v1/documents/list/" \
  -H "Authorization: Bearer YOUR_API_KEY"
GEThttps://api.tampercheck.ai/api/v1/documents/<uuid>/status/

Check progress without pulling the full result: status, verdict and score when ready, page_count, and timestamps.

curl -sS "https://api.tampercheck.ai/api/v1/documents/YOUR_JOB_ID/status/" \
  -H "Authorization: Bearer YOUR_API_KEY"
GEThttps://api.tampercheck.ai/api/v1/documents/<uuid>/

Fetch one job's full result for completed jobs (analysis or extraction shape depending on strategy). Use the list or search endpoints to find the job id first, then request the detail here only for the jobs you need.

curl -sS "https://api.tampercheck.ai/api/v1/documents/YOUR_JOB_ID/" \
  -H "Authorization: Bearer YOUR_API_KEY"

PDF reports

POSThttps://api.tampercheck.ai/api/v1/documents/<uuid>/report-link/

For API clients, getting a PDF is two steps. First call this endpoint on a completed job. You get a download_url that works for 1 minute and can be opened once. Then GET that URL (or /api/v1/reports/download/?token=...) to save the PDF. That second request does not need your API key; the link itself is the credential.

curl -sS -X POST "https://api.tampercheck.ai/api/v1/documents/YOUR_JOB_ID/report-link/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

# Then download (no Authorization; single-use):
curl -sS -L "PASTE_download_url_HERE" -o report.pdf

Opening the same link twice returns 410. After 30 minutes the link expires; create a new one. The dashboard downloads PDFs with your login session instead of this link flow.

Job notes

POSThttps://api.tampercheck.ai/api/v1/documents/<uuid>/notes/

Add a team note on a job (body, 1-5000 characters). Author is the API key owner. Notes appear on the dashboard for everyone who can see the document.

curl -sS -X POST "https://api.tampercheck.ai/api/v1/documents/YOUR_JOB_ID/notes/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body": "Reviewed with compliance - looks clean."}'

List notes

curl -sS "https://api.tampercheck.ai/api/v1/documents/YOUR_JOB_ID/notes/" \
  -H "Authorization: Bearer YOUR_API_KEY"

Team invites

POSThttps://api.tampercheck.ai/api/v1/team/invites/

Invite a teammate by email. Requires an owner or admin API key. Optional role: member (default) or admin. The invite token is sent by email and is not returned in the response.

curl -sS -X POST "https://api.tampercheck.ai/api/v1/team/invites/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "teammate@acme.com", "role": "member"}'

Webhooks

Register URLs under Dashboard → Developers → Webhooks. On completed / failed, TamperCheck POSTs the same body as job detail.

  • With webhook_id: only that webhook is notified.
  • Without: no webhook is called.
  • 400 invalid_webhook_id if unknown, inactive, or not yours.
delivery
POST https://your-app.example/webhooks/tampercheck
Content-Type: application/json
X-Webhook-ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7
X-Webhook-Signature: sha256=a1b2c3d4e5f6...

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "strategy": "tampering_detection",
  "verdict": "tampered",
  "risk_score": 42,
  "confidence": 0.78,
  "findings": [],
  "created_at": "2026-04-02T12:00:00Z",
  "completed_at": "2026-04-02T12:00:03Z"
}

Headers: X-Webhook-ID, X-Webhook-Signature (sha256=<hex> HMAC of raw body).

python
import hmac
import hashlib

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

Endpoint authentication

Each webhook can optionally send an extra credential so your receiver's gateway accepts the request. Configure it when creating or editing the webhook in the dashboard. It is not a field on the upload. Three methods are supported:

  • API Key - a static key in a named header (default X-Api-Key).
  • Bearer Token - Authorization: Bearer <token>.
  • Basic Auth - Authorization: Basic <base64>.

These are sent in addition to X-Webhook-Signature. Signature verification is unchanged. Credentials are encrypted at rest and never appear in webhook logs.

Usage summary

GEThttps://api.tampercheck.ai/api/v1/usage/?since=YYYY-MM-DD&until=YYYY-MM-DD

Aggregates completed jobs for this API key: document counts and spend. Dates are inclusive calendar days in UTC.

curl -sS "https://api.tampercheck.ai/api/v1/usage/?since=2026-08-01&until=2026-08-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Wallet usage

GEThttps://api.tampercheck.ai/api/v1/wallet/usage/?since=YYYY-MM-DD&until=YYYY-MM-DD

Paginated wallet credits and debits for the account (API key owner). Free. Does not charge the wallet. Works even when services are suspended. Optional page / page_size (default 25, max 100). from / to accepted as aliases for since / until.

curl -sS "https://api.tampercheck.ai/api/v1/wallet/usage/?since=2026-08-01&until=2026-08-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example response

json
{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "entry_type": "document_fee",
      "amount": "-0.50",
      "balance_after": "46.06",
      "description": "Document analysis - statement.pdf (1 pages, 1 check)",
      "metadata": {},
      "job": "550e8400-e29b-41d4-a716-446655440000",
      "created_at": "2026-08-07T03:41:00Z"
    }
  ]
}

entry_type values include document_fee, document_extraction_fee, top_up, signup_credit. Amounts are positive for credits, negative for debits.

Errors

JSON body with error and detail. Some include job id / status.

StatusMeaningAction
400Validation / invalid webhookFix file type, size, or webhook UUID
401Missing or invalid API keyCheck Bearer token
402No payment method, or suspended walletTop up at Dashboard → Billing
404Unknown job for this keyVerify UUID and API key
410PDF download link already usedCreate a new report-link
422Unprocessable file (no charge)Re-export / re-scan the file
503AI service unavailable (no charge)Retry with backoff

MCP (Model Context Protocol)

Connect Claude Code, Claude Desktop, Claude.ai custom connectors, LiteLLM, or other MCP clients to TamperCheck over Streamable HTTP. Same API key and billing as the HTTPS API. No OAuth - use your dt_... key on every request.

POSThttps://mcp.tampercheck.ai/mcp
  • Transport: Streamable HTTP (stateless, JSON responses).
  • Auth: Authorization: Bearer dt_... or X-API-Key: dt_... - create keys under Dashboard → Developers.
  • Health check: GET /healthz → {"status":"ok"} (no auth).

Claude Desktop / Claude.ai connector

When adding a remote MCP connector (Settings → Connectors, or equivalent):

  • URL: https://mcp.tampercheck.ai/mcp
  • Authentication: choose No sign-in (API key - do not use "Sign in now" / OAuth).
  • Request headers (required) - one of:
HeaderValue
AuthorizationBearer dt_your_key_here
X-API-Key (or x-api-key)dt_your_key_here

Or put the same URL and headers in Claude Desktop's config file (claude_desktop_config.json):

json
{
  "mcpServers": {
    "tampercheck": {
      "url": "https://mcp.tampercheck.ai/mcp",
      "headers": {
        "Authorization": "Bearer dt_your_key_here"
      }
    }
  }
}

Claude Code

Add the server once from a terminal and it is available in every Claude Code session:

bash
claude mcp add --transport http tampercheck https://mcp.tampercheck.ai/mcp \
  --header "x-api-key: dt_your_key_here"

Or add it from the Connectors settings with the same values. The walkthrough below shows each screen:

  1. In Add custom connector, set the name to TamperCheck.ai and the URL to https://mcp.tampercheck.ai/mcp, then Continue.
  2. Under Authentication, choose No sign-in - do not use the OAuth sign-in options.
  3. Under Request headers, add x-api-key with your dt_... key and keep Required checked, then Add.
Name the connector TamperCheck.ai and point it at https://mcp.tampercheck.ai/mcp.
Pick No sign-in and send your key as a required x-api-key header.

Claude stores the header value securely and never shows it again after you save the connector.

LiteLLM

yaml
mcp_servers:
  tampercheck:
    url: "https://mcp.tampercheck.ai/mcp"
    transport: "http"
    auth_type: "bearer_token"
    auth_value: "dt_..."

Tools

ToolMaps to
tampercheck_analyze_documentPOST /api/v1/documents/
tampercheck_create_uploadPOST /api/v1/documents/ (one-time upload URL)
tampercheck_get_jobGET /api/v1/documents/<id>/
tampercheck_list_jobsGET /api/v1/documents/list/
tampercheck_search_documentsGET /api/v1/documents/search/
tampercheck_usageGET /api/v1/usage/
tampercheck_invite_team_memberPOST /api/v1/team/invites/
tampercheck_add_job_notePOST /api/v1/documents/<id>/notes/
tampercheck_get_report_linkPOST /api/v1/documents/<id>/report-link/

Analyze inputs

Max file size is 20 MB per document. tampercheck_analyze_document takes exactly one input: a public URL. Local files are never sent through the chat: they go through tampercheck_create_upload.

InputNotes
document_url + optional filenamePublicly reachable HTTPS URL. The MCP server fetches it (SSRF-checked); nothing uploads through the chat.
Local fileUse tampercheck_create_upload: returns a one-time upload URL plus a curl command to run where the file lives (10-minute expiry)

Troubleshooting

Claude can't execute code against the connector (curl fails with a proxy 403, or Claude says the action is blocked by "organization policy"): claude.ai runs code in a sandbox that can only reach an allowlist of domains, and mcp.tampercheck.ai is not on the default list.

To fix it in claude.ai, go to Settings → Capabilities → Code execution and file creation. Under network or domain access, either add mcp.tampercheck.ai to the allowed domains or switch to "All domains".

Personal accounts: type mcp.tampercheck.ai under Additional allowed domains, then Add.

On Team or Enterprise plans an org admin owns this setting, which is why the error mentions organization policy. The admin adds the domain under Organization settings → Capabilities → Code execution: keep the domain allowlist on "Package managers only" and add mcp.tampercheck.ai as an additional allowed domain.

Organization settings → Capabilities.
Add mcp.tampercheck.ai under Additional allowed domains.

Workarounds while the domain is blocked

MCP tool calls run on the hosted connector, outside Claude's sandbox, so they keep working. The block affects only the curl command from tampercheck_create_upload that uploads a local file. Until the domain is allowed:

  • If the document is already at a public URL, pass document_url to tampercheck_analyze_document - our server fetches it directly, outside the sandbox.
  • Otherwise upload the file in the TamperCheck dashboard.

API skill for Cursor and Claude Code

Copy the integration brief into your coding assistant, or download the skill file (Markdown with YAML frontmatter) for Cursor, Claude Code, and similar workflows. The skill also points at the hosted MCP URL.

Copy for AI

Paste into Cursor, Claude, or ChatGPT so it can wire up the TamperCheck REST API with the right auth, endpoints, and response shapes.