API reference

A REST API over JSON for everything ViddyFlow can do from a Twitch VOD.

Base URL and authentication

Base URL: https://api.viddyflow.com

Create a key in API Access and send it on every request. The key value is shown once, at creation.

X-API-Key: your_api_key_here

What the API can and cannot do

The API covers the whole pipeline for Twitch VODs. Three dashboard features are out of reach, because they need a browser session rather than an API key: uploading your own MP4 or MOV, background music, and branding intro/outro presets. Picture-in-picture shorts are also dashboard-only, since every overlay box is placed by hand on a frame of your stream and there is no sensible default to fall back on.

Facecam split framing does work over the API: its regions have real defaults, so you get a working facecam-over-gameplay short without sending a single coordinate. See Vertical shorts.

Quick start

The smallest job that does something useful: a 5 minute reel plus 3 shorts.

curl -X POST "https://api.viddyflow.com/jobs" \
  -H "X-API-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "vod_url": "https://twitch.tv/videos/123456789",
    "streamer_name": "SampleCreator",
    "final_video_length_minutes": 5,
    "num_shorts": 3,
    "webhook_url": "https://hooks.example.com/viddyflow"
  }'

Prefer a ready-made collection? Download the Postman collection and set the apiKey variable.

Endpoints

EndpointPurpose
POST /jobsCreate a job. Limited to 10 requests per minute.
GET /jobsList your jobs, newest first. Supports page, page_size, status, search.
GET /jobs/{id}Status of one job.
GET /jobs/{id}/resultsPer-clip download links once the job is completed.
POST /jobs/{id}/cancelCancel a pending or running job and refund on a tiered policy.
POST /jobs/{id}/feedbackRate a completed job. Returns 204.
GET /jobs/{id}/download-allStream every artifact as one ZIP, built on demand.
GET /videos/metadataProbe a Twitch VOD for title, duration and availability before spending credits.

Create a job

POST /jobs. Credits are reserved when the job is accepted and refunded automatically if it fails or is cancelled early.

Source and identity

FieldTypeDescription
vod_urlreqstringPublic Twitch VOD URL, for example https://twitch.tv/videos/123456789. The API accepts Twitch VODs only.
streamer_namestringDisplay name used in generated titles and descriptions.
game_namestringPrimary game or category, used as context when writing metadata.
streamer_twitch_urlstring (url)Channel link included in generated descriptions.
streamer_twitter_urlstring (url)Social link included in generated descriptions.
streamer_pronounsstringPronouns used when generating metadata. Defaults to "they".
webhook_urlstring (url)Receives job.running, job.completed and job.failed callbacks.
vod_length_hoursnumberOptional. Skips the automatic duration probe when you already know the length. Must be greater than 0.

What gets produced

FieldTypeDescription
final_video_length_minutesnumberTarget runtime of the highlight reel, 1 to 30. Send 0 only together with compilation_enabled: false.
compilation_enabledbooleanDefaults to true. Set false for a shorts-only job: no reel is rendered and no generation credits are charged for one. Requires num_shorts greater than 0, and only the first run profile is executed.
num_shortsintegerVertical shorts to generate, 0 to 10, charged at 10 credits each. Defaults to 0. Your plan caps this: 3 free or before any purchase, 5 on Starter, 10 on Pro and Studio. Above your cap it is silently reduced, not rejected, and you are billed the reduced count.
burn_captionsbooleanBurn in captions on the shorts. Defaults to true. A plain .srt sidecar is produced either way.
model_presetstringProcessing tier: rapid_sprint, stable_tempo, creator_focus, auto_balance, studio_polish, or director_finish. Sets both quality and the per-hour credit rate.
stream_languagestringISO 639-1 code for the stream's language, for example "de". Overrides auto-detection, which a multilingual stream can throw off.
metadata_languagestringISO 639-1 code for generated titles, descriptions and tags. Defaults to the stream language.
run_profilesstring[]Which analysis profiles to run: balanced, audience, streamer. Defaults to ["balanced"]. Each additional profile renders its own reel and costs its own generation credits.
run_overridesobjectPer-profile tuning, keyed by profile name. See the table below.
parametersobjectEverything in the pipeline options table below. Unknown keys are ignored rather than rejected.

Pipeline options, inside parameters

FieldTypeDescription
min_highlight_durationinteger (s)Shortest a single highlight may be. Clamped to 180s.
max_highlight_durationinteger (s)Longest a single highlight may be. Clamped to 180s, and raised to min_highlight_duration if you send a smaller value.
cold_open_enabledbooleanOpen the reel with a fast teaser montage of its best moments.
cold_open_max_clipsintegerClips in that teaser. Clamped to 2 to 6.
cold_open_snippet_durationnumber (s)Length of each teaser snippet. Clamped to 2 to 10.
reel_title_card_enabledbooleanShow a title card over each segment of the highlight reel.
shorts_title_card_enabledbooleanFlash the generated clip title at the start of each short.
shorts_crop_modestring"crop" fills the vertical frame and loses the sides, "fit" keeps the whole frame with padding, "split" stacks facecam over gameplay. Defaults to "crop".
shorts_split_rationumberSplit mode only. Share of the vertical frame given to the facecam. Clamped to 0.15 to 0.85, defaults to 0.5.
shorts_facecam_frame_enabledbooleanSplit mode only. Draw a coloured outline around the facecam panel.
shorts_facecam_frame_colorstringSplit mode only. One of white, black, violet. Anything else falls back to white.

Per-profile tuning, inside run_overrides

FieldTypeDescription
target_duration_minutesintegerReel length for this profile, 1 to 30.
target_duration_secondsintegerThe same in seconds, 30 to 1800. Takes precedence over the minutes form.
audience_weightnumber0 to 1. How much Twitch chat reaction drives moment selection.
streamer_weightnumber0 to 1. How much the streamer's own presence drives selection.
similarity_thresholdnumber0 to 1. Higher values allow more similar moments through.
highlight_min_scorenumber0 to 1. Score a moment must beat to be considered.
bucket_size_secondsinteger1 to 3600. Granularity of the scoring pass.

Full example

{
  "vod_url": "https://twitch.tv/videos/123456789",
  "streamer_name": "SampleCreator",
  "game_name": "Any Game",
  "streamer_twitch_url": "https://twitch.tv/samplecreator",
  "webhook_url": "https://hooks.example.com/viddyflow",
  "stream_language": "en",
  "metadata_language": "en",
  "model_preset": "auto_balance",
  "run_profiles": ["balanced"],
  "run_overrides": {
    "balanced": {
      "audience_weight": 0.5,
      "streamer_weight": 0.5,
      "similarity_threshold": 0.7,
      "target_duration_minutes": 8
    }
  },
  "final_video_length_minutes": 8,
  "num_shorts": 5,
  "burn_captions": true,
  "parameters": {
    "min_highlight_duration": 30,
    "max_highlight_duration": 90,
    "cold_open_enabled": true,
    "cold_open_max_clips": 4,
    "cold_open_snippet_duration": 5,
    "reel_title_card_enabled": true,
    "shorts_title_card_enabled": true,
    "shorts_crop_mode": "crop"
  }
}

Shorts-only job

Skip the highlight reel entirely and pay no generation credits for one. A run profile is still required, because it decides which moments the shorts are cut from, and only the first one runs.

{
  "vod_url": "https://twitch.tv/videos/123456789",
  "streamer_name": "SampleCreator",
  "compilation_enabled": false,
  "final_video_length_minutes": 0,
  "run_profiles": ["balanced"],
  "num_shorts": 6,
  "parameters": {
    "shorts_crop_mode": "crop",
    "shorts_title_card_enabled": true
  }
}

Response

Returns immediately with an acknowledgement. Processing happens in the background.

{
  "id": "abc123-def456-ghi789",
  "status": "pending",
  "credit_cost": 138,
  "webhook_url": "https://hooks.example.com/viddyflow",
  "status_endpoint": "/jobs/abc123-def456-ghi789",
  "results_endpoint": "/jobs/abc123-def456-ghi789/results",
  "message": "Job accepted. Poll /jobs/{id} or await your webhook callback for results."
}

Track a job

Poll GET /jobs/{id}, or set a webhook_url and skip polling entirely. Status is one of pending, running, completed, or failed. There is no separate cancelled state: a cancelled job is reported as failed with a "cancelled by user" message.

curl "https://api.viddyflow.com/jobs/abc123-def456-ghi789" \
  -H "X-API-Key: your_api_key_here"

Results

Once completed, GET /jobs/{id}/results returns a flat deliverables list: one entry per downloadable file, already joined to its title, duration and tags. Links are presigned and expire, so re-request this endpoint rather than storing them.

Files are not kept forever. Around 30 days after a job last changed, its videos, thumbnails, metadata and caption files are permanently deleted from storage, and the job keeps only its record. The deadline for a given job comes back as artifacts_expires_at. See Your results.

{
  "job_id": "abc123-def456-ghi789",
  "status": "completed",
  "deliverables": [
    {
      "type": "reel",
      "title": "Balanced highlight reel",
      "duration_seconds": 123.03,
      "run_name": "balanced",
      "size_bytes": 45234567,
      "url": "https://artifacts.viddyflow.com/...&X-Amz-Signature=..."
    },
    {
      "type": "short",
      "index": 1,
      "title": "Epic Clutch Play",
      "duration_seconds": 38.4,
      "tags": ["clutch", "gaming"],
      "url": "https://artifacts.viddyflow.com/...&X-Amz-Signature=..."
    }
  ],
  "zip_url": "https://api.viddyflow.com/jobs/abc123-def456-ghi789/download-all?token=...",
  "links_expire_at": "2026-08-24T15:25:44Z"
}

Cancel

POST /jobs/{id}/cancel stops a pending or running job and refunds on a tiered policy: the further it got, the less comes back. Anything already completed or failed returns 400.

{ "id": "abc123-def456-ghi789", "status": "failed", "refund_credits": 96 }

Feedback

POST /jobs/{id}/feedback on a completed job feeds highlight-detection tuning. Returns 204 with no body; re-submitting overwrites the previous vote. reason applies to negative votes and must be one of wrong_moments, timing_off, needs_editing, or other. Choosing other requires notes.

{ "positive": false, "reason": "wrong_moments" }

Check a VOD first

GET /videos/metadata?vod_url=... returns the title and duration, and tells you why a VOD is unusable (private, subscriber-only, deleted, or still live) before you spend anything.

curl "https://api.viddyflow.com/videos/metadata?vod_url=https://twitch.tv/videos/123456789" \
  -H "X-API-Key: your_api_key_here"

Errors and limits

StatusMeaning
401Missing or invalid API key.
402Not enough credits for the job as specified.
404Job does not exist, or belongs to another account.
422Payload rejected. The detail field says which field and why: an unreachable VOD, a still-live broadcast, or an impossible combination such as a 0 minute reel without compilation_enabled: false.
429Rate limited. Back off and retry.

Rate limit: job creation is capped at 10 requests per minute, counted per client IP. The read endpoints are not explicitly limited, though polling every few seconds is plenty. Contact support if you need more headroom.