Videoslash API

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.

EndpointScope
GET /v1/ai-lab/tools, GET /v1/ai-lab/tools/{tool}read
POST /v1/ai-lab/{tool}/estimateread
POST /v1/ai-lab/{tool}/runscreative: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

  1. List tools with GET /v1/ai-lab/tools and read the tool's inputSchema, media and choices.
  2. Upload local files with POST /v1/creative-studio/media-uploads, then PUT the bytes.
  3. Optionally quote the price with POST /v1/ai-lab/{tool}/estimate.
  4. Start the run with POST /v1/ai-lab/{tool}/runs (returns 202 and the run).
  5. Poll GET /v1/ai-lab/runs/{id} every 10 to 20 seconds until status is no longer processing.
  6. Download each completed item's url (a CDN URL on cdn.videoslash.com).

Tools

Tool IDTitleOutputMain files
recastRecastvideovideo, versions[].references[].media
reshootReshootvideovideo, optional references[].media, audio
eraseErasevideovideo
extendExtendvideovideo, edgeFrame (for before), optional openingImage, references[].media
editEdit Videovideovideo, optional references[].media
recreateRecreatevideovideo, optional cast[].media, extras[].media
thumbnailThumbnailimageoptional photo, sketch.image, references[].image
upscaleUpscalevideovideo
lipsyncLipsyncvideovideo, audio
voiceChange Voicevideovideo
translateVideo Translatevideovideo
backgroundBackgroundimagephoto, optional background, sketch.image
soundAdd Soundvideovideo

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 its path in the input, accepted MIME types, size and length limits, and notes.
  • 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 when sound is custom) must be WAV, up to 15MB.
  • Upload size: the media upload endpoint caps video at 200MB, even where a tool's maxBytes is 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 its time in seconds) to get angles suited to the take; without them, a varied set of preset angles is used.
  • Extend before the start: side: "before" needs edgeFrame, an image upload of the clip's very first frame, plus openingImage when opening is image.
  • 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 id is the ID of its first output. The ID of any of its outputs also returns the whole run.
  • Run status is processing while any output is still running, then completed, failed, or partial (some outputs failed).
  • Each item has status, url (when completed), error (when failed) and credits.
  • Failed outputs are refunded; the run's credits counts 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.

StatusCodeWhen
400validation_errorInvalid input, a file in the wrong format, too short or too long, or an expired upload. The message lists up to four problems.
402subscription_requiredNo active plan. The message links to billing and summarizes the plans.
402insufficient_creditsNot enough credits. The message says how many are needed and which credit pack covers the shortfall, or when plan credits refill.
404not_foundUnknown tool, or a run that doesn't exist or isn't yours.
429rate_limitedToo 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.

On this page