DUCKDUCKGOOSE · VIDEO ANALYSIS API

One deepfake verdict per second of video.

Upload a video; we run every second through our selfie deepfake detector and return the timeline below as JSON. You decide what the timeline means for the video.

0:00one cell = one second0:27
accept inspect reject

1AUTHENTICATE

Every request carries your existing DuckDuckGoose API key — note the scheme is Token, not Bearer:

Authorization: Token <your_api_key>

Base URL: https://dsta-video.duckduckgoose.ai

2UPLOAD A VIDEO

# multipart/form-data, field name: file
curl -X POST https://dsta-video.duckduckgoose.ai/videos \
  -H "Authorization: Token <your_api_key>" \
  -F file=@video.mp4
# 202 Accepted
{"video_id": "b07f60c03a7347ee9b3187161ec44eaf", "status": "queued"}

mp4 · webm · avi · mov · mkv max 5 GB first 15 min analysed 1 frame analysed per second

3POLL FOR THE RESULT

Ask every few seconds until status is terminal. A one-minute video typically finishes in under a minute.

curl https://dsta-video.duckduckgoose.ai/videos/<video_id> \
  -H "Authorization: Token <your_api_key>"
queued → analyzing → completed · failed (see error) · interrupted (re-upload)
{
  "video_id": "b07f60c0…",
  "file_name": "video.mp4",
  "status": "completed",
  "total_frames": 60,
  "frames": [
    {"second": 0, "status": "completed", "output": "accept",
     "perc_fake": 11.53, "num_faces": 1, "error": null},
    {"second": 1, "status": "completed", "output": "accept",
     "perc_fake": 10.39, "num_faces": 1, "error": null}
  ],
  "error": null
}

4READ THE TIMELINE

FieldMeaning
secondTimestamp in the video this frame represents
outputaccept · inspect · reject — our verdict for this frame
perc_fake0–100, higher = more likely manipulated
num_facesFaces detected in the frame
status"failed" means no face was visible that second — no signal, not an error

PYTHON

The whole flow in one script (pip install requests):

# python analyze_video.py video.mp4
import sys, time, requests

BASE = "https://dsta-video.duckduckgoose.ai"
HEADERS = {"Authorization": "Token <your_api_key>"}

def analyze(path):
    with open(path, "rb") as f:
        r = requests.post(f"{BASE}/videos", headers=HEADERS, files={"file": f})
    r.raise_for_status()
    video_id = r.json()["video_id"]
    while True:
        r = requests.get(f"{BASE}/videos/{video_id}", headers=HEADERS)
        r.raise_for_status()
        job = r.json()
        if job["status"] in ("completed", "failed", "interrupted"):
            return job
        time.sleep(5)

job = analyze(sys.argv[1])
print(job["status"], job.get("error") or "")
for frame in job["frames"]:
    print(f'{frame["second"]:>4}s  {frame["output"] or "no face":8}  '
          f'perc_fake={frame["perc_fake"]}')

ERRORS

CodeMeaning
401Missing or invalid Authorization: Token <key> header
404Unknown video_id, or it belongs to another key
413Video larger than 5 GB
415Unsupported file extension
429Too many requests — retry later
507Server temporarily out of storage — retry later