API Reference
Everything you need to detect AI-generated content via the TruthLens API.
Overview
The TruthLens API is a REST API. All requests use JSON bodies and return JSON responses. The base URL for all endpoints is:
https://truthlens-api.fly.dev
All endpoints require authentication via a Bearer token in the Authorization header.
Authentication
Generate an API key from your dashboard. Pass it as a Bearer token:
shell
Authorization: Bearer tl_live_xxxxxxxxxxxxxxxxxxxx
API keys are shown only once at creation. Store them securely. You can create multiple keys and revoke them individually.
Detect text
/v1/detectRun the full text detection pipeline. The multi-stage pipeline runs heuristics (always), RoBERTa (CPU), and Binoculars/Falcon-7B (GPU via Modal) concurrently. Results include per-stage scores and a human-readable explanation.
Request body
modalityMust be "text" for text detection.
input_typeMust be "raw_text". URL text extraction coming soon.
contentThe text to analyse. Minimum 20 words recommended for reliable detection.
Example
shell
curl -X POST https://truthlens-api.fly.dev/v1/detect \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modality": "text",
"input_type": "raw_text",
"content": "The proliferation of AI has engendered a paradigm shift..."
}'Response
json
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"modality": "text",
"status": "completed",
"verdict": "ai_generated",
"confidence": 0.87,
"attribution": null,
"explanation": "Content shows strong AI-generated writing patterns (heuristic + ML analysis). AI probability: 87%.",
"details": {
"heuristic_score": 0.82,
"binoculars_score": 0.91,
"roberta_score": 0.79,
"ensemble_method": "weighted_blend",
"stages": {
"heuristics": true,
"binoculars": true,
"roberta": true
},
"features": {
"word_count": 89,
"unique_word_ratio": 0.93,
"avg_sentence_length": 89.0,
"sentence_length_variance": 0.0,
"char_entropy": 4.54,
"stopword_ratio": 0.11
}
},
"latency_ms": 547
}Verdict values
humanContent is likely written by a human.ai_generatedContent is likely AI-generated.mixedMixed signals — possibly AI-assisted.Detect image
/v1/detectDetect AI-generated images. Three-stage pipeline: EXIF/metadata analysis, 2D FFT frequency analysis, and a ViT-L neural classifier (GPU). Supports JPEG, PNG, WEBP, GIF, and BMP up to 20 MB.
Upload (base64)
modality"image"
input_type"upload"
contentBase64-encoded image bytes (without the data URL prefix).
shell
# Encode image to base64 (macOS / Linux)
B64=$(base64 -i photo.jpg)
curl -X POST https://truthlens-api.fly.dev/v1/detect \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"modality\": \"image\",
\"input_type\": \"upload\",
\"content\": \"$B64\"
}"URL
modality"image"
input_type"url"
urlPublicly accessible image URL.
shell
curl -X POST https://truthlens-api.fly.dev/v1/detect \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modality": "image",
"input_type": "url",
"url": "https://example.com/photo.jpg"
}'Image response
json
{
"id": "b2c3d4e5-...",
"modality": "image",
"verdict": "ai_generated",
"confidence": 0.93,
"explanation": "Image shows strong indicators of AI generation (metadata + frequency analysis + neural classifier). AI probability: 93%.",
"details": {
"metadata_score": 1.0,
"fft_score": 0.72,
"classifier_score": 0.97,
"stages": {
"metadata": true,
"frequency": true,
"classifier": true
},
"features": {
"width": 1024,
"height": 1024,
"format": "PNG",
"file_size_bytes": 2097152,
"has_exif": true,
"ai_tool_signature": "Stable Diffusion",
"c2pa_verdict": null,
"fft_smoothness": 0.81,
"fft_periodicity": 0.64
}
},
"latency_ms": 1823
}Batch detection
/v1/detect/batchProcess up to 100 items in a single request. Items are processed concurrently (10 workers). Results are returned in input order. A failed item does not abort the batch.
Quota note: each item counts as one scan. The endpoint checks quota before processing and rejects the batch if insufficient scans remain.
shell
curl -X POST https://truthlens-api.fly.dev/v1/detect/batch \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"modality": "text",
"input_type": "raw_text",
"content": "First piece of text to check..."
},
{
"modality": "text",
"input_type": "raw_text",
"content": "Second piece of text to check..."
}
]
}'json
{
"total": 2,
"succeeded": 2,
"failed": 0,
"results": [
{
"index": 0,
"success": true,
"result": { "verdict": "human", "confidence": 0.12, ... }
},
{
"index": 1,
"success": true,
"result": { "verdict": "ai_generated", "confidence": 0.91, ... }
}
]
}Scan history
List scans
/v1/scansReturns a paginated list of your scans (most recent first). Supports limit (max 100) and offset query params.
shell
curl https://truthlens-api.fly.dev/v1/scans?limit=20&offset=0 \ -H "Authorization: Bearer YOUR_API_KEY"
Get scan
/v1/scans/{scan_id}Returns full scan details including result_json with all stage scores and features.
shell
curl https://truthlens-api.fly.dev/v1/scans/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer YOUR_API_KEY"
Error codes
401invalid_tokenAPI key is missing, invalid, or revoked.402quota_exceededMonthly scan limit reached. Upgrade or wait for reset.422empty_contentcontent is empty or too short.422invalid_base64content is not valid base64 for image upload.422image_too_largeImage exceeds 20 MB limit.422modality_not_supportedRequested modality is not yet available.429rate_limitedToo many requests. Limit: 60/min for detect, 10/min for batch.500detection_errorInternal error during detection. Retry after a short delay.Code examples
Python
python
import requests
API_KEY = "tl_live_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://truthlens-api.fly.dev"
def detect_text(text: str) -> dict:
resp = requests.post(
f"{BASE_URL}/v1/detect",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"modality": "text",
"input_type": "raw_text",
"content": text,
},
timeout=120,
)
resp.raise_for_status()
return resp.json()
result = detect_text("The quick brown fox jumps over the lazy dog.")
print(f"Verdict: {result['verdict']} ({result['confidence']:.0%})")Python — image upload
python
import base64, requests
def detect_image_file(path: str, api_key: str) -> dict:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
resp = requests.post(
"https://truthlens-api.fly.dev/v1/detect",
headers={"Authorization": f"Bearer {api_key}"},
json={
"modality": "image",
"input_type": "upload",
"content": b64,
},
timeout=120,
)
resp.raise_for_status()
return resp.json()Node.js / TypeScript
typescript
const API_KEY = "tl_live_xxxxxxxxxxxxxxxxxxxx";
async function detectText(text: string) {
const res = await fetch("https://truthlens-api.fly.dev/v1/detect", {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
modality: "text",
input_type: "raw_text",
content: text,
}),
signal: AbortSignal.timeout(120_000),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.detail?.message ?? res.statusText);
}
return res.json();
}
const result = await detectText("Your content here…");
console.log(result.verdict, result.confidence);Batch — Python
python
def batch_detect(texts: list[str], api_key: str) -> list[dict]:
items = [
{"modality": "text", "input_type": "raw_text", "content": t}
for t in texts
]
resp = requests.post(
"https://truthlens-api.fly.dev/v1/detect/batch",
headers={"Authorization": f"Bearer {api_key}"},
json={"items": items},
timeout=300,
)
resp.raise_for_status()
data = resp.json()
return [
r["result"] if r["success"] else {"error": r["error"]}
for r in sorted(data["results"], key=lambda x: x["index"])
]Need help?
Open an issue at github.com/SaquibAnwar/truthlens.