The routes
The routes you need to build an integration. They all require the key, except those marked public.
Pricing — GET /api/pricing · public
Section titled “Pricing — GET /api/pricing · 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.
The estimate — POST /api/estimate
Section titled “The estimate — POST /api/estimate”// 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.
Start a generation — POST /api/process
Section titled “Start a generation — POST /api/process”{ "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_clipsis a ceiling from 1 to 20, not an order: the analysis keeps the best moments and may return fewer.0is rejected. When absent, the only ceiling is your plan’s.clip_secondsis 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.subtitlesforces 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 |
Several videos — POST /api/batch
Section titled “Several videos — POST /api/batch”Same body, with urls (1 to 20 links) instead of url. The settings apply to
each video in the batch.
Track — GET /api/status/{job_id}
Section titled “Track — GET /api/status/{job_id}”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) andvideo_url— the video;cover_url/cover_signed_url— a thumbnail. These keys can be absent: test for their presence rather than reading anull;viral_score— the clip’s score, from 1 to 100, ornullif it has none.nullis not0.
History — GET /api/history
Section titled “History — GET /api/history”Returns {"jobs": [...], "failed": [...]}.
jobs: the account’s generations that produced clips, with the same keys asstatus. The list is neither paginated nor sorted: sort on your side. A generation in progress does not appear yet.expired: trueon 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 samegroup.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, andreason, a technical message in English, not meant to be displayed as is. At most fifty entries, most recent first, within the retention period.
The balance — GET /api/credits
Section titled “The balance — GET /api/credits”{"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: trueis notbalance: 0. An unlimited account has no ceiling; only this field says so.reservedis always0. Nothing is held at launch: the debit happens at the end, pro rata to the duration actually processed.email_verifie: falseexplains anallocated: 0on 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.
Plans — GET /api/plans · public
Section titled “Plans — GET /api/plans · public”The plans, their credits, their features and their limits — the same as on the pricing page. Read amounts here rather than hard-coding them.
Other routes
Section titled “Other routes”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.
Answers come from these pages only. If they do not cover it, you will be told.