Checking a video, a stream, or a file
Always probe first
curl -sX POST $RTFC/media/probe -H "X-Auth-Token: $TOKEN" \
-H 'Content-Type: application/json' -d '{"url": "https://…"}'Anonymous, synchronous, creates nothing, costs nothing. YouTube, TikTok and Instagram are supported.
"Public" means an anonymous fetch succeeds. Every probe is made without cookies, deliberately - a video that only downloads because our servers happen to be signed in somewhere is not public, and treating it as such would leak private content between accounts.
reject_reason | Meaning |
|---|---|
unsupported_platform | Not a platform we can fetch |
not_a_single_video | A playlist, channel or profile |
unavailable | Deleted, or the id is wrong |
private | Not publicly viewable |
needs_auth | Requires a login |
geo_blocked | Not available from our region |
live_in_progress | Still streaming - try again when it ends |
Empty means it is usable.
Ingest
curl -sX POST $RTFC/debates/$DEBATE/upload-media \
-H "X-Auth-Token: $TOKEN" -H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url": "https://…", "language": "auto", "detector_mode": "batch"}'For YouTube, the video's own captions are used when available - no transcription cost, exact timestamps - falling back to audio + speech-to-text automatically when there are none in the language you asked for.
detector_mode:
realtime- flush eagerly, low latency. For live audio you are watching.batch- wait for paragraph boundaries, feed more context per call. Better
claim quality on recorded material. Use this for uploaded video.
Audio files and live audio
POST /v1/debates/{id}/upload-audio takes a file (multipart file, plus optional whisper_provider, language, no_diarize). no_diarize skips speaker separation - much faster, at the cost of not knowing who said what.
For live audio, POST /v1/session/start spawns a listener, then POST /v1/session/audio-ingest-token gives you a short-lived WebSocket URL to stream into.
That token call returns 409 while the listener is still starting. That is expected and retryable - poll it, do not treat it as an error.
Positions in the video
Each claim carries media_offset_ms: where in the media it was said, measured from the start of the media rather than wall-clock. That is what you need to sync verdicts to a player's current time.
It is null when the position could not be determined - never 0 as a stand-in, so a falsy check is safe.
Reuse
If a public analysis of the same video already exists, use it instead of paying to redo it - see the tutorial. The reused analysis is a normal debate you have been granted access to, so every ordinary endpoint works on it unchanged.