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.
| Method | Path | What 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.
| Strategy | How to call | Returns |
|---|---|---|
tampering_detectionDefault | POST /documents/ | authentic / tampered, risk score, findings |
deepfake_detection | POST /documents/ + strategy=deepfake_detection | authentic / ai_generated / face_swap / uncertain, plus artifact_breakdown |
document_extraction | POST /extract-documents/ | Page-scoped pages[].images[] crops (no verdict) |
Analyze
Multipart upload. File field document (PDF, JPG, JFIF, PNG, WEBP, BMP, TIFF; max 40 MB).
| Field | Required | Description |
|---|---|---|
document | Yes | File to analyze |
strategy | No | tampering_detection (default; PDF or image) or deepfake_detection (images only) |
document_identifier | No | Your correlation id (max 512) |
webhook_id | No | Notify this webhook UUID. Omit to skip delivery. |
suppress_categories | No | JSON array of finding keys to exclude |
pdf_password | No | Password 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
{
"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
{
"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
{
"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
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
{
"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
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"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"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
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.pdfOpening 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
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
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_idif unknown, inactive, or not yours.
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).
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
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
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
{
"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.
| Status | Meaning | Action |
|---|---|---|
400 | Validation / invalid webhook | Fix file type, size, or webhook UUID |
401 | Missing or invalid API key | Check Bearer token |
402 | No payment method, or suspended wallet | Top up at Dashboard → Billing |
404 | Unknown job for this key | Verify UUID and API key |
410 | PDF download link already used | Create a new report-link |
422 | Unprocessable file (no charge) | Re-export / re-scan the file |
503 | AI 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.
- Transport: Streamable HTTP (stateless, JSON responses).
- Auth:
Authorization: Bearer dt_...orX-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:
| Header | Value |
|---|---|
Authorization | Bearer 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):
{
"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:
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:
- In Add custom connector, set the name to TamperCheck.ai and the URL to
https://mcp.tampercheck.ai/mcp, then Continue. - Under Authentication, choose No sign-in - do not use the OAuth sign-in options.
- Under Request headers, add
x-api-keywith yourdt_...key and keep Required checked, then Add.
Claude stores the header value securely and never shows it again after you save the connector.
LiteLLM
mcp_servers:
tampercheck:
url: "https://mcp.tampercheck.ai/mcp"
transport: "http"
auth_type: "bearer_token"
auth_value: "dt_..."Tools
| Tool | Maps to |
|---|---|
tampercheck_analyze_document | POST /api/v1/documents/ |
tampercheck_create_upload | POST /api/v1/documents/ (one-time upload URL) |
tampercheck_get_job | GET /api/v1/documents/<id>/ |
tampercheck_list_jobs | GET /api/v1/documents/list/ |
tampercheck_search_documents | GET /api/v1/documents/search/ |
tampercheck_usage | GET /api/v1/usage/ |
tampercheck_invite_team_member | POST /api/v1/team/invites/ |
tampercheck_add_job_note | POST /api/v1/documents/<id>/notes/ |
tampercheck_get_report_link | POST /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.
| Input | Notes |
|---|---|
document_url + optional filename | Publicly reachable HTTPS URL. The MCP server fetches it (SSRF-checked); nothing uploads through the chat. |
| Local file | Use 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".
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.
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_urltotampercheck_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.