Skip to content

The routes

The routes you need to build an integration. They all require the key, except those marked public.

{"unit": "source_minute", "minutes_per_credit": 1.0,
"price_per_minute_usd": 0.12, "currency": "USD",
"rounding": "second", "minimum_minutes": 0.0,
"retention_days": 7, "storage_mb_per_minute": 4.4,
"live_monitor_max_hours": 12}

price_per_minute_usd can be null: in that case, show the unit without announcing an amount.

The rounding (rounding) and the billed minimum (minimum_minutes) are read here. Do not hard-code them: read them each time.

// request
{ "url": "https://youtube.com/watch?v=…",
"start": 600, "end": 1500, "with_heatmap": true }
Returned field Meaning
duration_seconds total duration of the source, or null if it could not be read
billable_minutes billed minutes — those of the portion if a range is given
estimated_cost_usd the amount, or null
range the range retained, or null
heatmap {start, end, intensity} markers, in absolute seconds

range can differ from what you asked for: an end past the video is brought back to the end of the video. Display the retained range.

The curve (heatmap) is given in absolute seconds, over the whole video, never shifted to the range. with_heatmap adds a few seconds to the response: only ask for it if you display the curve.

A link to a live stream in progress returns 400, with a detail starting with source_is_live:: a live stream is followed with the Live Monitor, not with a generation.

{ "url": "…", "start": 600, "end": 1500,
"instructions": "keep the parts where he explains a concept",
"reframe_mode": "auto", // auto | subject | disabled
"aspect": "9:16", // 9:16 | 1:1 | 16:9
"language": "en",
"max_clips": 5,
"clip_seconds": 45,
"subtitles": true,
"brand_template": "account" }

Also accepts multipart/form-data with a file. start/end only apply to a URL.

  • max_clips is a ceiling from 1 to 20, not an order: the analysis keeps the best moments and may return fewer. 0 is rejected. When absent, the only ceiling is your plan’s.
  • clip_seconds is the target average duration, from 14 to 180 seconds. When absent, one minute. Clips can differ from it by about 40% either way, so a moment is not cut before its end.
  • subtitles forces subtitles on (true) or off (false) for this generation. When absent, the brand template decides. Only send the field to override the template.

brand_template takes three forms:

Value What applies
"account" the account’s default brand template
"<id>" that saved template
{ … } that template, spelled out, for this generation only
absent no branding

Same body, with urls (1 to 20 links) instead of url. The settings apply to each video in the batch.

The stage, the progress and, once the generation is finished, the clips. Poll every few seconds: clips arrive together, at the end.

Each clip carries:

  • signed_url (preferred) and video_url — the video;
  • cover_url / cover_signed_url — a thumbnail. These keys can be absent: test for their presence rather than reading a null;
  • viral_score — the clip’s score, from 1 to 100, or null if it has none. null is not 0.

Returns {"jobs": [...], "failed": [...]}.

  • jobs: the account’s generations that produced clips, with the same keys as status. The list is neither paginated nor sorted: sort on your side. A generation in progress does not appear yet.
  • expired: true on a generation: its retention period has passed, its clips no longer exist. Offer neither playback nor download.
  • group: the segments of the same live monitoring share the same group.id, which lets you group them. Treat it as opaque.
  • failed: generations that failed without producing anything — their id, their date, their source link when there is one, and reason, a technical message in English, not meant to be displayed as is. At most fifty entries, most recent first, within the retention period.
{"balance": 1960, "reserved": 0, "unlimited": false,
"allocated": 2000, "used": 40, "carried_over": 0, "plan": "studio",
"email_verifie": true,
"period_start": "…", "period_end": "…",
"ledger": [{"at": "…", "delta": -40, "reason": "generation", "job_id": "…"}]}

balance = allocated − used + carried_over. carried_over is the debt carried over from the previous period: negative or 0, never positive — see Credits.

Three things to know:

  • unlimited: true is not balance: 0. An unlimited account has no ceiling; only this field says so.
  • reserved is always 0. Nothing is held at launch: the debit happens at the end, pro rata to the duration actually processed.
  • email_verifie: false explains an allocated: 0 on the free plan: the address is not confirmed yet.

A download link — POST /api/media/{job_id}/{index}/link

Section titled “A download link — POST /api/media/{job_id}/{index}/link”

Returns {"url": "…", "expires_at": 1787707500}: a signed address, readable without an account, valid for one hour. index is the clip’s position in the list returned by status.

If you pass this link on, tell the recipient when it expires: after one hour, it stops working.

The plans, their credits, their features and their limits — the same as on the pricing page. Read amounts here rather than hard-coding them.

Settings, the Live Monitor, publishing and brand templates also have routes, used by the app. Their bodies may still change: they are not documented here. The routes on this page do not change without notice.