> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deeptrack.io/llms.txt
> Use this file to discover all available pages before exploring further.

# REST API

> Getting started with the deeptrack REST API for deepfake detection.

> [!NOTE]
>
> The deeptrack team recommends using the SDK for most integrations. The SDK handles authentication, file uploads, job polling, and error handling automatically. Consider checking if your preferred language is supported before using the raw API directly.
>
> [View SDK Documentation →](https://docs.deeptrack.io/deepfake/sdk.md)

***

## Authentication

The deeptrack API authenticates via the `X-API-Key` header. Every request must include your API key.

```
X-API-Key: dt_your_key_here
```

To generate an API key, log into the [deeptrack Dashboard](https://deeptrack.io) and navigate to **Settings → API Keys**.

> [!WARNING]
>
> Keep your API key secure. Do not commit it to version control or expose it in client-side code.

***

## Base URL

```
https://api.deeptrack.io
```

***

## Size Limits

| Media Type | Maximum Size |
| - | - |
| Image | 15 MB |
| Video | 500 MB |
| Audio | 50 MB |

***

## Supported File Types

| Type | Extensions |
| - | - |
| Image | `.jpg`, `.jpeg`, `.png`, `.webp`, `.gif` |
| Video | `.mp4`, `.mov`, `.avi`, `.mkv` |
| Audio | `.mp3`, `.wav`, `.m4a`, `.aac`, `.ogg`, `.flac` |

***

## Analyze an Image

Upload an image file and receive an authenticity verdict instantly.

**Endpoint**

```
POST /v1/image/predict
```

| Header | Value |
| - | - |
| `X-API-Key` | Your API key |
| `Content-Type` | `multipart/form-data` |

| Field | Type | Required | Description |
| - | - | - | - |
| `file` | file | Yes | Image file to analyze |

```python Python theme={null}
import requests

BASE_URL = "https://api.deeptrack.io"
HEADERS  = {"X-API-Key": "dt_your_key_here"}

with open("photo.jpg", "rb") as f:
    resp = requests.post(
        f"{BASE_URL}/v1/image/predict",
        headers=HEADERS,
        files={"file": ("photo.jpg", f, "image/jpeg")},
    )

print(resp.json())
```

```javascript JavaScript theme={null}
import fs from "fs";
import FormData from "form-data";

const BASE_URL = "https://api.deeptrack.io";
const HEADERS  = { "X-API-Key": "dt_your_key_here" };

const form = new FormData();
form.append("file", fs.createReadStream("photo.jpg"));

const resp = await fetch(`${BASE_URL}/v1/image/predict`, {
  method:  "POST",
  headers: { ...HEADERS, ...form.getHeaders() },
  body:    form,
});

console.log(await resp.json());
```

```typescript TypeScript theme={null}
import fs from "fs";
import FormData from "form-data";

const BASE_URL = "https://api.deeptrack.io";
const HEADERS  = { "X-API-Key": "dt_your_key_here" };

interface ImageResult {
  filename:              string;
  prediction:            "Real" | "Fake" | "UNCERTAIN";
  confidence_percentage: number;
  raw_scores:            { Real: number; Fake: number };
}

const form = new FormData();
form.append("file", fs.createReadStream("photo.jpg"));

const resp = await fetch(`${BASE_URL}/v1/image/predict`, {
  method:  "POST",
  headers: { ...HEADERS, ...form.getHeaders() },
  body:    form as any,
});

const result = await resp.json() as ImageResult;
console.log(result);
```

```bash cURL theme={null}
curl -X POST https://api.deeptrack.io/v1/image/predict \
  -H "X-API-Key: dt_your_key_here" \
  -F "file=@photo.jpg"
```

### Response

```json theme={null}
{
  "filename":               "photo.jpg",
  "prediction":             "FAKE",
  "confidence_percentage":  87.3,
  "raw_scores": {
    "Real": 12.7,
    "Fake": 87.3
  }
}
```

| Field | Type | Description |
| - | - | - |
| `filename` | string | Name of the uploaded file |
| `prediction` | string | `Real`, `Fake`, or `UNCERTAIN` |
| `confidence_percentage` | float | Confidence of the verdict (0–100) |
| `raw_scores.Real` | float | Raw probability score for Real |
| `raw_scores.Fake` | float | Raw probability score for Fake |

***

## Analyze a Video

Video analysis is asynchronous. Upload the file, receive a `job_id`, then poll for the result.

### Step 1 — Upload the video

**Endpoint**

```
POST /v1/video/predict/video
```

| Header | Value |
| - | - |
| `X-API-Key` | Your API key |
| `Content-Type` | `multipart/form-data` |

| Field | Type | Required | Description |
| - | - | - | - |
| `file` | file | Yes | Video file to analyze |

```python Python theme={null}
import requests
import time

BASE_URL = "https://api.deeptrack.io"
HEADERS  = {"X-API-Key": "dt_your_key_here"}

# step 1 — upload
with open("clip.mp4", "rb") as f:
    resp = requests.post(
        f"{BASE_URL}/v1/video/predict/video",
        headers=HEADERS,
        files={"file": ("clip.mp4", f, "video/mp4")},
    )

job_id = resp.json()["job_id"]
print(f"Job queued: {job_id}")

# step 2 — poll until done
while True:
    resp   = requests.get(f"{BASE_URL}/v1/video/jobs/{job_id}", headers=HEADERS)
    status = resp.json()["status"]
    print(f"Status: {status}")

    if status == "done":
        print(resp.json()["result"])
        break
    elif status == "error":
        print("Error:", resp.json()["error"])
        break

    time.sleep(3)
```

```javascript JavaScript theme={null}
import fs from "fs";
import FormData from "form-data";

const BASE_URL = "https://api.deeptrack.io";
const HEADERS  = { "X-API-Key": "dt_your_key_here" };

// step 1 — upload
const form = new FormData();
form.append("file", fs.createReadStream("clip.mp4"));

const uploadResp = await fetch(`${BASE_URL}/v1/video/predict/video`, {
  method:  "POST",
  headers: { ...HEADERS, ...form.getHeaders() },
  body:    form,
});

const { job_id } = await uploadResp.json();
console.log("Job queued:", job_id);

// step 2 — poll until done
while (true) {
  await new Promise(r => setTimeout(r, 3000));

  const pollResp = await fetch(`${BASE_URL}/v1/video/jobs/${job_id}`, {
    headers: HEADERS,
  });
  const job = await pollResp.json();
  console.log("Status:", job.status);

  if (job.status === "done")  { console.log(job.result); break; }
  if (job.status === "error") { console.error(job.error); break; }
}
```

```typescript TypeScript theme={null}
import fs from "fs";
import FormData from "form-data";

const BASE_URL = "https://api.deeptrack.io";
const HEADERS  = { "X-API-Key": "dt_your_key_here" };

interface VideoResult {
  label:        "REAL" | "FAKE" | "UNCERTAIN";
  confidence:   number;
  fake_prob:    number;
  face_pct:     number;
  total_frames: number;
  n_segments:   number;
  segments:     Array<{
    segment:    number;
    start_sec:  number;
    end_sec:    number;
    label:      string;
    confidence: number;
    fake_prob:  number;
  }>;
}

// step 1 — upload
const form = new FormData();
form.append("file", fs.createReadStream("clip.mp4"));

const uploadResp = await fetch(`${BASE_URL}/v1/video/predict/video`, {
  method:  "POST",
  headers: { ...HEADERS, ...form.getHeaders() },
  body:    form as any,
});

const { job_id } = await uploadResp.json() as { job_id: string };
console.log("Job queued:", job_id);

// step 2 — poll until done
while (true) {
  await new Promise(r => setTimeout(r, 3000));

  const pollResp = await fetch(`${BASE_URL}/v1/video/jobs/${job_id}`, {
    headers: HEADERS,
  });
  const job = await pollResp.json() as {
    status: string;
    result: VideoResult;
    error:  string;
  };
  console.log("Status:", job.status);

  if (job.status === "done")  { console.log(job.result); break; }
  if (job.status === "error") { throw new Error(job.error); }
}
```

```bash cURL theme={null}
# step 1 — upload
curl -X POST https://api.deeptrack.io/v1/video/predict/video \
  -H "X-API-Key: dt_your_key_here" \
  -F "file=@clip.mp4"

# step 2 — poll (replace JOB_ID with the returned job_id)
curl https://api.deeptrack.io/v1/video/jobs/JOB_ID \
  -H "X-API-Key: dt_your_key_here"
```

### Upload Response

```json theme={null}
{
  "job_id":   "3f8a2c1d-...",
  "status":   "queued",
  "filename": "clip.mp4",
  "size_mb":  12.4,
  "poll_url": "/v1/video/jobs/3f8a2c1d-..."
}
```

### Step 2 — Poll for Result

**Endpoint**

```
GET /v1/video/jobs/{job_id}
```

Poll this endpoint every 2–3 seconds until `status` is `done` or `error`. Larger files may take longer to analyze.

### Poll Response

```json theme={null}
{
  "job_id":   "3f8a2c1d-...",
  "status":   "done",
  "filename": "clip.mp4",
  "result": {
    "label":        "FAKE",
    "confidence":   91.2,
    "fake_prob":    0.912,
    "face_pct":     98.0,
    "total_frames": 240,
    "n_segments":   4,
    "segments": [
      {
        "segment":    1,
        "start_sec":  0.0,
        "end_sec":    4.3,
        "label":      "FAKE",
        "confidence": 91.2,
        "fake_prob":  0.912
      }
    ]
  }
}
```

| Field | Type | Description |
| - | - | - |
| `job_id` | string | Unique job identifier |
| `status` | string | `queued`, `processing`, `done`, or `error` |
| `result.label` | string | `REAL`, `FAKE`, or `UNCERTAIN` |
| `result.confidence` | float | Confidence percentage (0–100) |
| `result.fake_prob` | float | Raw fake probability (0.0–1.0) |
| `result.face_pct` | float | % of frames with a detected face |
| `result.total_frames` | int | Total frames processed |
| `result.n_segments` | int | Number of rPPG segments |
| `result.segments` | array | Per-segment breakdown |

## Check Usage

Returns your monthly usage stats for the authenticated API key.

**Endpoint**

```
GET /v1/client/usage/me
```

```python Python theme={null}
resp = requests.get(f"{BASE_URL}/v1/client/usage/me", headers=HEADERS)
print(resp.json())
```

```javascript JavaScript theme={null}
const resp = await fetch(`${BASE_URL}/v1/client/usage/me`, { headers: HEADERS });
console.log(await resp.json());
```

```typescript TypeScript theme={null}
const resp = await fetch(`${BASE_URL}/v1/client/usage/me`, { headers: HEADERS });
console.log(await resp.json());
```

```bash cURL theme={null}
curl https://api.deeptrack.io/v1/client/usage/me \
  -H "X-API-Key: dt_your_key_here"
```

### Response

```json theme={null}
{
  "owner":           "Gotham Media",
  "track":           "api",
  "plan":            "starter",
  "rate_per_scan":   0.39,
  "monthly_limit":   5000,
  "used_this_month": 23,
  "remaining":       4977,
  "resets_at":       "2026-03-31"
}
```

## Error Reference

All errors return a JSON body with a `detail` field.

| Status | Meaning | Example detail |
| - | - | - |
| `401` | Missing or invalid API key | `"Missing X-API-Key header."` |
| `400` | Bad request | `"Unsupported format '.wmv'."` |
| `413` | File too large | `"File too large (520MB). Max is 500MB."` |
| `422` | Missing required field | `"field required: file"` |
| `429` | Monthly limit exceeded | `"Monthly limit of 5000 scans exceeded."` |
| `503` | Model not loaded | `"Video model not loaded."` |

```json theme={null}
{
  "detail": "Monthly limit of 5000 scans exceeded. Upgrade your plan at deeptrack.io/pricing"
}
```

## Support

For questions or issues, email **[tech@deeptrack.io](mailto:tech@deeptrack.io)** or reach out to your account manager.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.