REST API reference
Base URL: https://frugal-anteater-681.convex.site · All bodies are JSON · Authenticate every /v1 request with
Authorization: Bearer ss_live_...
Conventions
- Jobs are asynchronous. Endpoints that do work (
/v1/styles,/v1/edits,/v1/recordings,/v1/fetch) return202with a job immediately. PollGET /v1/jobs/{id}every few seconds. - Credits are charged when a job is accepted and refunded automatically if it fails. See Credits.
- Getting a key: request access. Keys work only after a person approves the account; an
unapproved key gets
403 key_pending_approval. - Errors have one shape:
{ "error": { "code": "insufficient_credits", "message": "this costs 5 credit(s); balance is 2. …" } }
| Status | Codes |
|---|---|
| 400 | missing_field, invalid_field, invalid_json, invalid_id, invalid_url, invalid_pack, unknown_account, platform_mismatch |
| 401 | unauthorized — missing, invalid or revoked key |
| 402 | insufficient_credits |
| 403 | key_pending_approval, forbidden (needs an admin key), fetch_disabled |
| 404 | not_found |
| 409 | conflict, not_pending |
| 429 | rate_limited, too_many_jobs |
| 502 / 503 | zernio_error, not_configured |
Account
GET /v1/me
{ "orgId": "js7…", "keyScope": "agent", "name": "Acme", "credits": 93, "autoPublish": false,
"allowHostedFetch": false, "maxConcurrentJobs": 4, "apiVersion": "2026-10-08" }
`apiVersion` changes whenever the endpoint or MCP tool surface changes; MCP clients that cache the tool
list should reconnect when it does.
Assets
An asset is any file in your account: an uploaded clip or song, a reference, a finished edit, a recording. Uploading takes three calls, so large files go straight to storage instead of through the API.
POST /v1/assets/upload-url
Returns a one-time URL: { "uploadUrl": "https://…" }. Send the raw bytes to it:
curl -X POST "$uploadUrl" -H "Content-Type: video/mp4" --data-binary @clip.mp4
# → { "storageId": "kg2…" }
POST /v1/assets
Register the upload: { "storageId": "kg2…", "filename": "clip.mp4" } → 201 with the asset:
{ "id": "j97…", "kind": "video", "role": "upload", "filename": "clip.mp4", "contentType": "video/mp4",
"size": 991017, "url": "https://…", "source": null, "jobId": null, "createdAt": 1791328110667 }
kind is video, audio, image, json or other, from the uploaded Content-Type.
GET /v1/assets · GET /v1/assets/{id} · DELETE /v1/assets/{id}
List the 100 most recent, read one (with a download url), or delete one and its file permanently.
Styles
POST /v1/styles — analyze a reference (2 credits)
{ "assetId": "j97…", "semantic": true }
semantic (default true) adds vision-model shot roles, descriptions and caption style on top of the
measured analysis. When the job succeeds, result.styleId is the new style and result summarizes it:
{ "styleId": "jn7…", "aspect": "9:16", "duration": 17.8, "shot_count": 7, "bpm": 99.4,
"cuts_on_beat_ratio": 0.71, "semantic": true, "summary": "Fast result-first hook, …",
"pacing": { "shot_count": 7, "mean_shot": 2.54, "median_shot": 0.73, "cuts_per_minute": 20.3, … } }
GET /v1/styles · GET /v1/styles/{id}
GET /v1/styles/{id} includes the full spec — see Styles and edits.
Edits
POST /v1/edits — cut your clips to a style (5 credits)
| Field | Type | |
|---|---|---|
styleId |
string | Required. |
clipAssetIds |
string[] | Required. 1–30 of your video assets. |
musicAssetId |
string | An audio asset. Cuts snap to its beat when the style is beat-driven. |
musicStart |
number | Seconds into the track to start (default 0). |
captions |
string[] | Caption lines in order (up to 40, 200 chars each). The first is the hook. |
brief |
string | What the video is about. Used to write captions when captions is omitted. |
aspect |
string | 9:16, 4:5, 1:1, 4:3 or 16:9. Defaults to the reference's. |
duration |
number | Target length, 3–180 s. Defaults to the reference's. |
keepClipAudio |
boolean | Mix your clips' own sound. Default: on without music, off (ducked) with music. |
semantic |
boolean | Use the vision model to pick the best moments (default true). |
The finished job's outputs contain the edit (mp4) and the plan (JSON: which clip and in-point
filled each shot). result.qa is the automatic quality report; result.notes explains decisions such
as beat snapping and layout.
Generation
See Generating images, characters and video for every option.
| Endpoint | |
|---|---|
POST /v1/characters |
{ name, description, referenceAssetIds?, aspect?, resolution? } → a stored character whose sheet is generated; poll until ready |
GET /v1/characters · GET /v1/characters/{id} · DELETE /v1/characters/{id} |
List, read (with sheetUrl), delete |
POST /v1/images |
{ kind, brief, characterIds?, references?, aspect?, resolution?, n?, estimate? } → job; outputs are images |
POST /v1/videos |
{ brief, characterIds?, duration?, resolution?, aspect?, imageAssetId?, referenceAssetIds?, referenceVideoAssetIds?, referenceAudioAssetIds?, estimate? } → job, or a price with estimate: true |
POST /v1/voice |
{ text, voice?, direction?, stability?, perform? } → job; output is audio |
POST /v1/lipsync |
{ videoAssetId, audioAssetId, pro? } → job |
Generation results include notes on choices made. The production craft behind them stays server-side.
Models, skills, swaps, edits
GET /v1/models |
The image, video and swap models you can pick, with what each supports. |
POST /v1/skills · GET /v1/skills · GET/POST/DELETE /v1/skills/{id} |
Your own versioned image recipes; skillIds on images, characters, edits and brand kits. |
POST /v1/images/edit |
Masked edit of a real photo: only the mask is painted, the rest is untouched. |
POST /v1/swaps |
object_swap / motion_transfer: keep the footage, change the subject. |
POST /v1/videos/{id}/finalize · draft: true |
Cheap 480p drafts, then the keeper at 720p/1080p. |
POST /v1/jobs/{id}/cancel |
Cancel with a full refund. |
POST /v1/upscales |
Lanczos resample to 2160p. |
POST /v1/dialogue · GET /v1/voices · POST /v1/voices/clone |
Multi-speaker tracks with per-line timings; your own ElevenLabs voices and clones when your key is connected. |
GET /v1/providers · POST/DELETE /v1/providers/{higgsfield\|elevenlabs} |
Connect your own provider keys (admin, where enabled). |
POST /v1/brands/analyze |
A suggested brand kit from your boards. |
See Generation.
Explainer videos
Brand kits, scripts and renders have their own page: Explainer videos.
POST /v1/brands · GET /v1/brands · GET /v1/brands/{id} · POST /v1/brands/{id} · DELETE /v1/brands/{id} |
Brand kits: name, description, tone, colors, font, logo, product images with descriptions, music. Free. |
POST /v1/scripts |
{ brandId, brief, duration?, aspect?, language? } → job; result.script is an editable scene list. 2 credits. |
POST /v1/explainers |
{ brandId, brief | script, aspect?, captions?, voiceover?, musicAssetId? } → job; the video plus the rendered script. 12 credits. |
Recordings
POST /v1/recordings — record a public web app (3 credits)
{ "url": "https://example.com", "viewport": "mobile",
"steps": [ { "type": "hold", "seconds": 2 }, { "type": "click", "selector": "text=Pricing" },
{ "type": "scroll", "pixels": 900 }, { "type": "hold", "seconds": 2 } ] }
See Recording for every step type. Output: a recording asset (mp4) and
result.marks, the timestamp of every step for cutting.
Fetching
POST /v1/fetch — a reference from a social URL (1 credit)
{ "url": "https://www.tiktok.com/@…/video/…", "start": 3, "end": 18 }. start/end (seconds,
optional) keep only that section — handy for a 4–30 s reference clip for POST /v1/videos.
Hosted fetching is a per-account setting: if it is off you get 403 fetch_disabled — ask us to enable
it (POST /v1/reports works) and confirm you have the rights to the clips, or fetch on your own machine
with the local MCP server and upload instead. Output: a fetched asset with source attribution (and
the trim applied).
Jobs
GET /v1/jobs/{id} · GET /v1/jobs
{ "id": "jd7…", "kind": "replicate", "status": "succeeded", "progress": "done", "error": null,
"result": { … }, "creditsCharged": 5, "refunded": false, "attempts": 1,
"outputs": [ { "assetId": "j95…", "role": "edit", "kind": "video", "filename": "edit.mp4", "url": "https://…" } ],
"createdAt": 1791469255706, "startedAt": 1791469256012, "finishedAt": 1791469281420 }
status: queued → running → succeeded | failed. A job with no word from the worker for three
hours is marked failed and refunded.
Social accounts and posts
See Posting for the approval model.
| Endpoint | |
|---|---|
GET /v1/social/accounts |
Connected accounts: { id, platform, username, displayName, status } |
POST /v1/social/connect |
{ "platform": "tiktok", "redirectUrl": "https://…" } → { "authUrl": "…" } |
POST /v1/posts |
Draft a post (1 credit). See below. |
GET /v1/posts |
Posts and their status |
POST /v1/posts/{id}/approve |
Admin key. Publish or schedule a pending post. |
POST /v1/posts/{id}/reject |
Admin key. Reject it; its credit is refunded. |
POST /v1/posts:
{ "assetId": "j95…", "caption": "Dinner in one search #recipes",
"targets": [ { "platform": "tiktok", "accountId": "6a62…" } ],
"scheduledFor": "2026-10-12T18:00:00-04:00" }
Give scheduledFor (ISO 8601 with an offset, or with timezone) or "publishNow": true. Post
statuses: pending_approval → approved → scheduled | published | failed, or rejected.
Team
Members, roles, keys, per-person credit caps and the shared library have their own page: Team.
GET /v1/members · POST /v1/members · GET/POST/DELETE /v1/members/{id} · POST /v1/members/{id}/keys |
People on the account, each with their own key and role. |
GET /v1/keys · DELETE /v1/keys/{id} |
Every live key and whose it is. |
GET /v1/library |
Brand kits, characters, styles, finished videos and uploads the team can reuse, with createdBy. |
Reporting problems
Found a bug, want a feature, or have a question? File it through the API — agents can do this on their own when something goes wrong. Reports are free.
POST /v1/reports
| Field | Type | |
|---|---|---|
title |
string | Required. Up to 200 characters. |
description |
string | Required. What happened, what you expected, steps to reproduce. Up to 10,000 characters. |
kind |
string | bug (default), feature or question. |
severity |
string | low, normal (default), high or blocking. |
jobId |
string | The job involved. Its status, error, inputs and QA report are attached automatically. |
{ "kind": "bug", "severity": "high", "jobId": "jd7…",
"title": "Captions cut off on 4:5 edits",
"description": "The second caption line is clipped at the top. Expected it inside the frame." }
Returns 201 with the report. GET /v1/reports and GET /v1/reports/{id} show each report's
status — open, acknowledged, fixed, wont_fix or closed — and the team's response.
Credits
| Endpoint | |
|---|---|
GET /v1/billing |
{ credits, costs, packs } |
GET /v1/billing/ledger |
Every charge, refund and purchase, newest first |
Agents: this page is also available as Markdown; the whole reference is in llms-full.txt.