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

POST
/v1/detect

Run 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

modality
string
required

Must be "text" for text detection.

input_type
string
required

Must be "raw_text". URL text extraction coming soon.

content
string
required

The 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

POST
/v1/detect

Detect 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
string
required

"image"

input_type
string
required

"upload"

content
string
required

Base64-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
string
required

"image"

input_type
string
required

"url"

url
string
required

Publicly 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

POST
/v1/detect/batch

Process 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

GET
/v1/scans

Returns 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

GET
/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.