AI Lab API
Run AI Lab video and image tools (Upscale, Lipsync, Video Translate, Reshoot and more) through the public API.
AI Lab API
The AI Lab tools from the dashboard are available over the public API: Recast, Reshoot, Erase, Extend, Edit Video, Recreate, Thumbnail, Upscale, Lipsync, Change Voice, Video Translate, Background and Add Sound. Each tool takes the same options as in the dashboard, charges the same credits, and runs asynchronously: start a run, then poll it until its outputs are ready.
The same tools are available to AI agents over MCP. See AI Lab tools (MCP).
Authentication and plan
All endpoints take an API key (Authorization: Bearer vsl_...). See Authentication.
| Endpoint | Scope |
|---|---|
GET /v1/ai-lab/tools, GET /v1/ai-lab/tools/{tool} | read |
POST /v1/ai-lab/{tool}/estimate | read |
POST /v1/ai-lab/{tool}/runs | creative:generate |
GET /v1/ai-lab/runs, GET /v1/ai-lab/runs/{id} | read |
POST /v1/creative-studio/media-uploads (files) | creative:generate |
Starting a run needs an active plan, the same rule as the dashboard. Pay-per-use credits alone don't unlock generation; they stay on the account and can be spent once you subscribe. Without a plan, starting a run returns 402 subscription_required. Check subscribed on GET /v1/credits before you start.
Workflow
- List tools with
GET /v1/ai-lab/toolsand read the tool'sinputSchema,mediaandchoices. - Upload local files with
POST /v1/creative-studio/media-uploads, then PUT the bytes. - Optionally quote the price with
POST /v1/ai-lab/{tool}/estimate. - Start the run with
POST /v1/ai-lab/{tool}/runs(returns202and the run). - Poll
GET /v1/ai-lab/runs/{id}every 10 to 20 seconds untilstatusis no longerprocessing. - Download each completed item's
url(a CDN URL oncdn.videoslash.com).
Tools
| Tool ID | Title | Output | Main files |
|---|---|---|---|
recast | Recast | video | video, versions[].references[].media |
reshoot | Reshoot | video | video, optional references[].media, audio |
erase | Erase | video | video |
extend | Extend | video | video, edgeFrame (for before), optional openingImage, references[].media |
edit | Edit Video | video | video, optional references[].media |
recreate | Recreate | video | video, optional cast[].media, extras[].media |
thumbnail | Thumbnail | image | optional photo, sketch.image, references[].image |
upscale | Upscale | video | video |
lipsync | Lipsync | video | video, audio |
voice | Change Voice | video | video |
translate | Video Translate | video | video |
background | Background | image | photo, optional background, sketch.image |
sound | Add Sound | video | video |
GET /v1/ai-lab/tools/{tool} is the source of truth. It returns:
inputSchema: the JSON Schema of the run's request body, including every option, its allowed values and defaults.media: one entry per file input with itspathin the input, accepted MIME types, size and length limits, andnotes.choices: option lists that aren't in the schema, such as the voices for Change Voice (choices.voices[].id).
Files
File fields take a string: either an upload ID or the URL of one of your earlier outputs (any url from a completed AI Lab run or Creative Studio generation). This makes it easy to chain tools, for example Recast a clip and then Upscale the result.
To upload a local file, request a presigned URL and PUT the bytes. Leave out modelId: it applies to Creative Studio models only.
curl -s -X POST "$API_BASE_URL/v1/creative-studio/media-uploads" \
-H "Authorization: Bearer vsl_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "fileName": "clip.mp4", "contentType": "video/mp4", "fileSizeBytes": 18874368 }'Uploads are temporary until a run references them. If an upload expires, the run returns 400 validation_error; upload the file again.
Format rules
Send files in a format the tool accepts (see each slot's accept); the API doesn't convert files.
- Lipsync: video must be MP4 and audio must be WAV. Convert MOV, MP3 or M4A first.
- Video Translate: video must be MP4.
- Reshoot: a custom soundtrack (
audio, used whensoundiscustom) must be WAV, up to 15MB. - Upload size: the media upload endpoint caps video at 200MB, even where a tool's
maxBytesis higher. - Reshoot without frames: the dashboard picks camera angles from frames of the take. Over the API you can send a few
frames(JPEG data URLs, about 512px on the long side, each with itstimein seconds) to get angles suited to the take; without them, a varied set of preset angles is used. - Extend before the start:
side: "before"needsedgeFrame, an image upload of the clip's very first frame, plusopeningImagewhenopeningisimage. - Length limits: most tools use the first part of a clip that is longer than their maximum (see each slot's
notes). Recast refuses source clips longer than its maximum.
Estimate
POST /v1/ai-lab/{tool}/estimate quotes a run without charging anything. Files aren't needed: send the options in input. Pass seconds, the length of the main video or audio, for an exact price; without it, the price for the tool's maximum length is quoted (basis: "maximum_length").
{ "input": { "resolution": "1080p", "fps": 30 }, "seconds": 42 }{ "tool": "upscale", "credits": 5.3, "basis": "given_length" }The actual charge is based on the file's measured length when the run starts.
Runs
A run is everything one start created. Tools with several outputs (Recast versions, Reshoot angles, Thumbnail and Background variants, Change Voice voices, Video Translate languages, Add Sound takes) return one run with one item per output, each with its own label (for example Version 2, Angle 1 or Spanish).
- The run
idis the ID of its first output. The ID of any of its outputs also returns the whole run. - Run
statusisprocessingwhile any output is still running, thencompleted,failed, orpartial(some outputs failed). - Each item has
status,url(when completed),error(when failed) andcredits. - Failed outputs are refunded; the run's
creditscounts only outputs that didn't fail.
List recent runs with GET /v1/ai-lab/runs. Filter with tool, limit with limit (1 to 50, default 20), and page with before set to the createdAt of the last run you received. The list includes runs started from the dashboard and MCP.
Errors
Errors use the standard envelope { "error": { "code", "message" } }. Messages are safe to show to users.
| Status | Code | When |
|---|---|---|
| 400 | validation_error | Invalid input, a file in the wrong format, too short or too long, or an expired upload. The message lists up to four problems. |
| 402 | subscription_required | No active plan. The message links to billing and summarizes the plans. |
| 402 | insufficient_credits | Not enough credits. The message says how many are needed and which credit pack covers the shortfall, or when plan credits refill. |
| 404 | not_found | Unknown tool, or a run that doesn't exist or isn't yours. |
| 429 | rate_limited | Too many runs started. Wait a minute and try again. |
End-to-end example: Upscale
Upscale a local 42-second clip to 1080p at 30 fps.
API_BASE_URL=https://www.videoslash.com/api
KEY=vsl_YOUR_KEY
FILE=clip.mp4
SIZE=$(wc -c < "$FILE" | tr -d ' ')
# 1. Check the tool's options
curl -s "$API_BASE_URL/v1/ai-lab/tools/upscale" \
-H "Authorization: Bearer $KEY"
# 2. Request an upload URL
UPLOAD=$(curl -s -X POST "$API_BASE_URL/v1/creative-studio/media-uploads" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "{\"fileName\":\"$FILE\",\"contentType\":\"video/mp4\",\"fileSizeBytes\":$SIZE}")
UPLOAD_ID=$(echo "$UPLOAD" | jq -r .uploadId)
UPLOAD_URL=$(echo "$UPLOAD" | jq -r .uploadUrl)
# 3. PUT the bytes (send the headers from requiredHeaders)
curl -s -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary @"$FILE"
# 4. Quote the price (optional)
curl -s -X POST "$API_BASE_URL/v1/ai-lab/upscale/estimate" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"resolution":"1080p","fps":30},"seconds":42}'
# 5. Start the run
RUN_ID=$(curl -s -X POST "$API_BASE_URL/v1/ai-lab/upscale/runs" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "{\"video\":\"$UPLOAD_ID\",\"resolution\":\"1080p\",\"fps\":30}" \
| jq -r .id)
# 6. Poll until it is done
while :; do
RUN=$(curl -s "$API_BASE_URL/v1/ai-lab/runs/$RUN_ID" \
-H "Authorization: Bearer $KEY")
STATUS=$(echo "$RUN" | jq -r .status)
[ "$STATUS" != "processing" ] && break
sleep 15
done
echo "$RUN" | jq '.items[] | {status, url, error}'To upscale an earlier output instead of a local file, skip steps 2 and 3 and pass its URL: "video": "https://cdn.videoslash.com/...".
API reference
Request and response schemas for every endpoint are in the API reference under AI Lab.