API reference
Send a selfie and an ID image (and/or a bank-statement PDF) to one endpoint. Get back a fraud-risk score, a decision (pass / review / flag), and the evidence behind it. One call, server-to-server.
Authentication
Every request carries your API key in the X-API-Key header. Create and manage keys in your dashboard. The key is a server-side secret: call the API from your backend only, never from a browser, mobile app, or public code. If a key is exposed, revoke it in the dashboard; other keys keep working.
Optional IP allowlist. For each key you can set an allowlist of source IPs or CIDR ranges in the dashboard (for example 203.0.113.5 or 10.0.0.0/8). When set, the key works only from those addresses and a request from any other source is rejected with 403. Leave it blank for no restriction. This is a defense-in-depth control: even a leaked key is useless from an address you did not authorize.
Sandbox and test keys
Create a tsx_test_ key from the dashboard (tick "Test key") to integrate in a sandbox. A test key returns a deterministic simulated result, calls no detection engine, spends no credits and is never billed. The response has "mode": "test" (live keys return "mode": "live").
Force any decision by setting the reference field to flag, review or pass (any other value returns a pass), so you can test every code path before going live.
curl -X POST https://truesecurix.com/v1/verify \
-H "X-API-Key: tsx_test_your_key" \
-F "selfie=@selfie.jpg" \
-F "reference=flag" # returns a simulated FLAG, no billing
When your integration works against the sandbox, switch the key to a tsx_live_ key. Nothing else in your code changes. Prefer Postman? Import our collection.
Verify an identity
/v1/verify
A multipart/form-data request. Send at least one file. Each call costs one verification credit; the cost is charged only when the check runs.
| Field | Type | Notes |
|---|---|---|
| selfie | file | A live selfie image (JPG/PNG). Checked for AI / deepfake synthesis. |
| document | file | An ID image or a bank-statement PDF. Checked for tampering and structural validity. |
| video | file | Optional. A short selfie clip. Checked for temporal / video deepfake signals (frame consistency, blend and warp artifacts) over sampled frames. |
| reference | text | Optional. Your own user or case id. It is stored, echoed back in the response, and shown in your audit log so you can tie the verdict to the right user. |
| device_signals | text (JSON) | Optional. Device and capture signals collected by the capture SDK in the end user's browser or app, used for injection and virtual-camera detection. A detected virtual camera or emulator routes the check to review. |
curl -X POST https://truesecurix.com/v1/verify \
-H "X-API-Key: YOUR_KEY" \
-F "selfie=@selfie.jpg" \
-F "document=@id.jpg" \
-F "reference=user_12345"
{
"verification_id": "verif_3f2a9c1d",
"reference": "user_12345",
"risk_score": 4.8,
"decision": "pass",
"selfie": { "synthetic_score": 0.05, "verdict": "likely_authentic", "is_deepfake": false },
"document": {
"tamper_score": 0.07,
"verdict": "analyzed",
"is_tampered": false,
"deterministic": {
"doc_type": "aadhaar",
"ocr_ok": true,
"checks": [ { "field": "verhoeff", "valid": true, "reason": "Aadhaar checksum valid" } ]
}
},
"evidence": [
{ "check": "Document verhoeff", "finding": "Aadhaar checksum valid", "weight": 1.0 }
],
"recommendation": "Low fraud risk: media is consistent with authentic capture.",
"consensus_families": 0,
"signal_breakdown": [
{ "name": "CLIPDetector", "family": "deepfake", "raw_score": 0.05,
"calibrated_score": 0.05, "confidence": 0.72, "is_fitted": true,
"informative": true, "verdict": "likely_authentic" }
],
"credits_remaining": 982,
"processing_ms": 975
}
selfie and document are null when that input is not sent. deterministic is null when the document is not an ID image (for example a PDF statement).
| Field | Meaning |
|---|---|
| risk_score | 0-100. Higher means more likely fraud. |
| decision | pass / review / flag (see below). |
| selfie | Deepfake/synthesis result for the face, or null if no selfie was sent. |
| liveness | Passive liveness / presentation-attack result (pad_score, verdict, is_live), or null. |
| video | Temporal / video deepfake result (temporal_score, verdict) when a video was sent, else null. |
| injection | Injection result from device_signals (score, verdict, virtual_camera, reasons), or null. |
| face_match | Selfie-to-ID face match (ArcFace): match_probability (0 to 1), is_match, verdict. Returned when a selfie and an ID image (not a PDF) were both sent, else null. A clear mismatch routes the check to review. |
| document | Tampering result, or null. deterministic is an object (doc_type, ocr_ok, checks[]) when the document is an ID image, else null. Each check has field, valid (true/false/null), and a reason. |
| evidence | The signals behind the verdict, for your audit trail. |
| signal_breakdown | Every raw and calibrated signal, with whether it is informative. Only calibrated, informative signals can drive the decision. |
| consensus_families | How many independent signal families agreed. An AI-driven flag needs several. |
| recommendation | A plain-language summary you can log or show a reviewer. |
| verification_id, reference, processing_ms | The verdict id, your echoed reference, and how long the check took. |
| credits_remaining | Your balance after this call. |
Decisions
No fraud signals above threshold. Safe to approve automatically.
Uncertain. Route to a human; never auto-reject on this alone.
Strong fraud evidence (or a failed deterministic check). Hold and investigate.
Errors
| Status | Meaning |
|---|---|
| 400 | Bad request (no file sent, or an unreadable image). |
| 401 | Missing X-API-Key header. |
| 402 | No verification credits left. Top up in the dashboard. |
| 403 | Invalid or revoked key, the account is suspended, or the request came from an IP that is not on the key's allowlist. |
| 409 | A request with the same Idempotency-Key is still in flight. Retry once it completes to get the original result. |
| 413 | File too large (over 15 MB), or an image over 40 megapixels. |
| 429 | Rate limit exceeded. Slow down and retry. |
| 502 / 503 / 504 | The detection engine is briefly unavailable or timed out. No credit is charged; retry. |
Rate limits
Per-account, per-minute (shared across all of your keys). Exceeding it returns 429; the count resets each minute. Every error returns a JSON body { "error": { "code", "message" }, "request_id" }, and each response carries an X-Request-ID header you can quote in support. Send an Idempotency-Key header to make retries safe: a repeated request with the same key returns the original result and is never charged twice.
| Plan | Requests / minute |
|---|---|
| Free | 120 |
| Starter | 240 |
| Scale | 600 |
Questions about integrating? Write to contact@truesecurix.com.
Capture SDK (injection defense)
To catch injection attacks (a virtual camera such as OBS, an emulator, or a screen feed pushed into the camera) the server needs signals from the capture device. The capture SDK runs in the end user's browser or app: it opens the camera, captures the selfie, and collects device signals. Your backend forwards the selfie and the device_signals field to /v1/verify. The API key stays on your backend; the browser only collects and forwards.
- Web SDK: /sdk/truesecurix-capture.js
- Live sample: /capture.html
- Mobile capture (React Native, Expo, Capacitor): /sdk/mobile/truesecurix-capture-mobile.js
- Python backend SDK (single file, drop into your project): /sdk/python/truesecurix.py
<script src="https://truesecurix.com/sdk/truesecurix-capture.js"></script>
const cap = new TrueSecurixCapture();
await cap.start(document.querySelector("video")); // opens the camera
const selfie = await cap.captureFrame(); // Blob
const signals = await cap.collectSignals(); // device / injection signals
cap.stop();
// Send { selfie, device_signals: JSON.stringify(signals) } to YOUR backend, which
// posts them to /v1/verify with your X-API-Key.