API, private preview
Run this from your own setup
Send a video URL, get back the same thing the site shows you: the score, the shots, who is in them, what is wrong and when, and what to change. Ask me for a key and I will turn it on.
Request access
This just opens your mail app. Or email sindri@johannsson.io
Submit a job
POST https://mhfxmaylqosurzzupfyy.supabase.co/functions/v1/api-score
Authorization: Bearer <api_key>
Content-Type: application/json{
"video_url": "https://example.com/shot.mp4",
"references": [
{
"name": "ada",
"image_urls": ["https://example.com/ada-1.png", "https://example.com/ada-2.png"]
}
],
"webhook_url": "https://your.app/hooks/consistency",
"client_ref": "scene-014"
}Response:
{
"job_id": "1f0b…c7",
"status_url": "https://mhfxmaylqosurzzupfyy.supabase.co/functions/v1/job-status?id=1f0b…c7"
}Full example:
curl -X POST https://mhfxmaylqosurzzupfyy.supabase.co/functions/v1/api-score \
-H "Authorization: Bearer $VC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://example.com/shot.mp4",
"references": [{ "name": "ada", "image_urls": ["https://example.com/ada-1.png"] }],
"webhook_url": "https://your.app/hooks/consistency",
"client_ref": "scene-014"
}'Read the result
The result is POSTed to webhook_url when the run finishes, and is always readable at:
GET https://mhfxmaylqosurzzupfyy.supabase.co/functions/v1/job-status?id=<job_id>
Authorization: Bearer <api_key>{
"id": "1f0b…c7",
"status": "done",
"result": {
"overall": 0.74,
"overall_spread": 0.03,
"verdict": "Four shots need repair.",
"shots": [{ "index": 3, "start": 8.4, "end": 12.9 }],
"entities": [
{ "id": "maya", "name": "Maya", "kind": "person",
"anchor": { "shot": 3, "t": 9.1 } }
],
"findings": [
{
"id": "f_04",
"category": "physical",
"type": "wardrobe",
"slot": "jacket",
"severity": "high",
"shot": 12,
"entity": "maya",
"t_start": 41.2,
"t_end": 46.0,
"description": "The jacket is brown and open; it was dark green and buttoned in shot 3.",
"confidence": 0.81,
"votes": { "runs": 3, "agree": 3 }
}
],
"fixes": [
{
"id": "x_02",
"resolves": ["f_04"],
"target": { "shot": 12, "start": 41.2, "end": 46.0 },
"entities": ["maya"],
"fix_text": "Shot 12, 0:41 to 0:46. …",
"status": "open"
}
],
"meta": {
"models": ["…"],
"mode_bible": "agentic",
"runs": 3,
"tokens_in": 412000,
"tokens_out": 18400,
"cost_usd_estimate": 0.42
}
},
"report_url": "https://…/report.html?token=…"
}Fields
- video_url
- Required. https URL to the video, up to 5 GB. The analysis downloads it.
- references
- Optional. Reference images per character, as { name, image_urls[] }. When present they become the anchor instead of the first appearance.
- webhook_url
- Optional. Receives the finished result payload by POST.
- client_ref
- Optional string echoed back in the webhook payload.
Webhook payload
When the run finishes we POST this JSON to webhook_url:
{
"job_id": "1f0b…c7",
"status": "done",
"client_ref": "scene-014",
"result": { "overall": 0.74, "overall_spread": 0.03, "findings": [ … ], "fixes": [ … ] }
}Rate limits and retention
- 5 active jobs
- Per account on create-job (browser uploads). Exceeding it returns HTTP 429.
- 30 jobs / hour
- Per API key on api-score. Exceeding it returns HTTP 429 with an error message.
- 5 GB max
- Per video, for both uploads and video_url submissions.
- 7 day retention
- Uploaded videos are deleted 7 days after the run.
- 90 day retention
- Reports are deleted 90 days after the run.
Your API keys (preview)
Sign in and you can make keys here.
Sign in