Video API

v1 OpenAPI spec

Overview

The Video API turns your video files into streaming-ready, downloadable MP4s. Upload a file, optionally trim it, hide sensitive regions, or combine clips, then download the result. It accepts MP4, MOV, MKV, WebM and most other formats, up to 20 GiB and 8 hours per file.

Base URLhttps://api.videopiper.dev/v1
FormatJSON requests and responses (Content-Type: application/json)
AuthAuthorization: Bearer <your API key>
Specopenapi.yaml (OpenAPI 3.0). Import it into Postman, Insomnia or a code generator.
Create video→Upload parts to storage→Complete→Poll status→Download

Video bytes never pass through the API. You upload them directly to storage with short-lived pre-signed URLs, which keeps large uploads fast and reliable.

Authentication

Every request carries your API key as a bearer token:

Authorization: Bearer vpk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  • Your key is issued to you by the service owner. Treat it like a password: anyone who has it can upload videos as you.
  • Each key belongs to one user. You only ever see your own videos; any other video ID answers 404 NOT_FOUND.
  • A missing, unknown or revoked key gets 401 UNAUTHORIZED. Revoked keys stop working within a minute.

Accounts and API keys

Sign up in the web app with your email (a 6-digit code is sent to you). Once signed in, create API keys on the Account page. Each key is shown once; you cannot retrieve it again. API keys can also be created programmatically with POST /account/keys when signed in with a session token. Your account shows your plan, usage this month and API keys.

Keep the key on your server. Don't put it in a web page, a mobile app or a public repository, where anyone can extract it. Call the API from your backend, and hand your users' browsers only the pre-signed upload URLs and download links, which are safe to share and expire on their own. See Uploads from a browser.

Quickstart

Upload a video, wait for it to process, and download the MP4. Set two environment variables first:

export VIDEO_API="https://api.videopiper.dev/v1"
export VIDEO_API_KEY="vpk_..."   # your key
# Uses jq to read JSON. Files up to 64 MiB are a single part (see Python/JavaScript for any size).
AUTH="Authorization: Bearer $VIDEO_API_KEY"; JSON="Content-Type: application/json"

# 1. Create the video
SIZE=$(wc -c < lesson.mp4 | tr -d ' ')
VIDEO_ID=$(curl -s -X POST "$VIDEO_API/videos" -H "$AUTH" -H "$JSON" \
  -d "{\"fileName\":\"lesson.mp4\",\"sizeBytes\":$SIZE}" | jq -r .videoId)

# 2. Get an upload URL for part 1, and PUT the bytes to it (no Authorization header)
PART_URL=$(curl -s -X POST "$VIDEO_API/videos/$VIDEO_ID/parts" -H "$AUTH" -H "$JSON" \
  -d '{"partNumbers":[1]}' | jq -r '.parts[0].url')
curl -s -T lesson.mp4 "$PART_URL"

# 3. Start processing
curl -s -X POST "$VIDEO_API/videos/$VIDEO_ID/complete" -H "$AUTH" -H "$JSON" -d '{}'

# 4. Wait for SUCCEEDED, then download
until [ "$(curl -s "$VIDEO_API/videos/$VIDEO_ID" -H "$AUTH" | jq -r .status)" != "RUNNING" ]; do sleep 10; done
curl -s "$VIDEO_API/videos/$VIDEO_ID" -H "$AUTH" | jq -r .status          # expect SUCCEEDED
curl -s -o lesson-processed.mp4 "$(curl -s "$VIDEO_API/videos/$VIDEO_ID" -H "$AUTH" | jq -r .downloadUrl)"

Short videos are usually ready within a minute or two of complete; long videos are processed in parallel chunks.

Concepts

Video lifecycle

UPLOADING→ complete →RUNNING→SUCCEEDEDorFAILED/TIMED_OUT/ABORTED
StatusMeaning
UPLOADINGCreated; waiting for parts and complete.
READY_TO_STARTUpload finished but processing didn't start; call complete again.
RUNNINGProcessing. progress shows the stages.
SUCCEEDEDDone. downloadUrl is present.
FAILED / TIMED_OUTProcessing failed. Check the file plays elsewhere, then upload again or reprocess.
ABORTEDCancelled.

Priority processing

Paid plans get priority. Videos from paid plans are scheduled ahead of free-tier videos when capacity is contended, so paid customers never wait behind a free-tier backlog. Plan changes take effect within ~60 seconds.

Conventions

  • IDs: videoId is 32 lowercase hex characters.
  • Times are seconds (decimals allowed). An end of null means "to the end".
  • Positions on screen (x, y, w, h) are fractions of the frame from 0 to 1, so they work at every quality level.
  • Strict input: unknown fields are refused with 400 INVALID_REQUEST, so a typo can't be silently ignored.
  • Results: each finished video has an MP4 (H.264/AAC, with fast start for streaming playback).

Uploading videos

  1. Create the video with its file name and exact size: POST /videos. You get a videoId, a partSize (64 MiB) and a partCount.
  2. Get part URLs: POST /videos/{videoId}/parts with up to 100 partNumbers per call. Each URL is valid for 15 minutes, so request them shortly before use.
  3. Upload each part with PUT <url>. Part n is the byte range starting at (n − 1) × partSize, exactly sizeBytes long. Send no Authorization header. Parts can upload in parallel (4–8 at a time works well) and in any order.
  4. Complete: POST /videos/{videoId}/complete, optionally with processing options. Processing starts.
POST /videos
{ "fileName": "lesson.mp4", "sizeBytes": 734003200, "maxHeight": 1080 }

201 Created
{ "videoId": "3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f", "partSize": 67108864, "partCount": 11,
  "status": "UPLOADING", "statusPath": "/videos/3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f" }

POST /videos/3f1c…/parts
{ "partNumbers": [1, 2, 3] }

200 OK
{ "parts": [ { "partNumber": 1, "sizeBytes": 67108864, "url": "https://…" }, … ], "expiresInSeconds": 900 }
  • Retries: if a part fails or its URL expires, request a new URL for that part number and upload it again. complete is safe to call more than once: it never starts a second job.
  • Abandoned uploads (never completed) are deleted automatically after 2 days. To discard one sooner, call POST /videos/{videoId}/abort.
  • Incomplete uploads: complete answers 409 UPLOAD_INCOMPLETE if a part is missing or the wrong size.

Import from a URL

Instead of uploading a file, send a public HTTPS URL and the API downloads it. The file is checked once it arrives and processed immediately, just like an upload. Processing options (trim, redactions, deleteOriginal) go in the request.

The URL must be HTTPS and resolve only to public internet addresses. The file size limit is the same as uploads (20 GiB by default). The server must answer 200 with the file (at most 3 redirects, each re-checked); Dropbox share links need ?dl=1, and presigned S3 links work fine.

POST /videos
{ "sourceUrl": "https://example.com/videos/tutorial.mp4", "fileName": "tutorial.mp4", "maxHeight": 1080 }

201 Created
{ "videoId": "3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f", "status": "SUBMITTED",
  "fileName": "tutorial.mp4", "statusPath": "/videos/3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f" }

Unlike an upload, there is no parts step or complete call. Dry runs (?dryRun=true) validate the URL without downloading. While the download is in progress the video record has no sourceVersionId; it fills in from the receipt once the file arrives. The download is retried once on network errors; 4xx and size-limit errors are permanent.

AUTH="Authorization: Bearer $VIDEO_API_KEY"; JSON="Content-Type: application/json"

# Create the video from a URL
VIDEO_ID=$(curl -s -X POST "$VIDEO_API/videos" -H "$AUTH" -H "$JSON" \
  -d '{"sourceUrl":"https://example.com/videos/tutorial.mp4","fileName":"tutorial.mp4","maxHeight":1080}' | jq -r .videoId)

# Poll status until ready
until [ "$(curl -s "$VIDEO_API/videos/$VIDEO_ID" -H "$AUTH" | jq -r .status)" != "RUNNING" ]; do sleep 10; done

# Download
curl -s -o tutorial-processed.mp4 "$(curl -s "$VIDEO_API/videos/$VIDEO_ID" -H "$AUTH" | jq -r .downloadUrl)"

Limits and errors

  • URL format: must be HTTPS, 1–2,048 characters, with no username or password embedded.
  • Redirects: at most 3; each destination is checked the same way (HTTPS, public internet).
  • Content-Length: checked up front; if the declared size exceeds the limit, the import fails immediately.
  • Network errors: retried once (e.g. timeout, connection reset). Other errors are permanent: 404, size limit hit, empty file, DNS failure, private address.
  • No camera / streaming: imports work only with single files. Use regular uploads for screen + camera or upload-while-recording.
  • Idempotency: `Idempotency-Key` works the same way as for uploads and edits.

Uploads from a browser

To let your users upload from your web app without exposing your key, split the work between your backend and the browser:

  1. The browser tells your backend the file name and size.
  2. Your backend calls POST /videos and POST /videos/{id}/parts, and returns only the videoId, the partSize and the part URLs.
  3. The browser PUTs each slice (file.slice(start, start + sizeBytes)) straight to its URL. Storage accepts cross-origin PUTs, and exposes the ETag header.
  4. The browser tells your backend it's done; your backend calls complete.
// Browser: upload the slices your backend signed
for (const part of parts) {
  const start = (part.partNumber - 1) * partSize;
  const response = await fetch(part.url, { method: "PUT", body: file.slice(start, start + part.sizeBytes) });
  if (!response.ok) throw new Error(`Part ${part.partNumber} failed`);
}

For playback or download in the browser, pass the downloadUrl from a status response to the page. It's valid for 15 minutes.

Warm-up for faster processing

Request parts progressively as you upload (e.g., every few parts) rather than requesting all parts at once from the beginning. When you request the last few parts (within 192 MiB from the end of the file), the API automatically starts the processing container early so it boots while those final parts upload. This can cut total processing time nearly in half.

This happens automatically—no extra API calls needed. Asking for all parts at once, starting from part 1, skips warm-up (unless the whole file is ≤192 MiB). The web UI and example code already request parts progressively, so you get this benefit by default.

Screen + camera

Upload a screen recording and a camera recording together. The result shows the camera in the bottom-right corner of the screen, with both audio tracks mixed. Record both in the same session so they line up.

POST /videos
{ "fileName": "screen.webm", "sizeBytes": 209715200,
  "layout": "pip", "camera": { "fileName": "camera.webm", "sizeBytes": 52428800 } }

The response adds camera.partSize and camera.partCount. Request the camera's part URLs with "file": "camera", upload both files, then call complete once.

Processing options

Send these in the body of complete (and of reprocess). maxHeight is set on create.

OptionTypeDescription
maxHeight720 | 1080 | 1440 | 2160Highest quality produced; default 1080. Every lower level is made too. Never upscales; higher takes longer.
trim{start, end}Keep only this part, in seconds into the upload. Frame-accurate; costs no extra processing time.
redactionsarray (≤ 20)Regions to blur or black out, each during a time window. See below.
deleteOriginalbooleanDelete your uploaded original once the result is published. Use it with redactions when the unredacted file must not be kept. The video can't be reprocessed afterwards.
POST /videos/3f1c…/complete
{
  "trim": { "start": 4.5, "end": 312 },
  "redactions": [
    { "type": "box",  "x": 0.05, "y": 0.04, "w": 0.30, "h": 0.06, "start": 0, "end": null },
    { "type": "blur", "shape": "ellipse", "x": 0.62, "y": 0.55, "w": 0.20, "h": 0.30, "start": 12.5, "end": 20 }
  ]
}

Redaction fields

FieldDescription
type"box" (solid black bar: irreversible, the safest choice for text) or "blur".
shape"rect" (default) or "ellipse" (fills the box).
x, y, w, hTop-left corner and size, as fractions of the final frame (0–1). For screen + camera videos that's the combined picture.
start, endSeconds on the output timeline (after any trim). end: null = until the end.

Following moving content

For something that moves, like a face walking across the frame, give the region a track of keyframes instead of x, y, w, h. It glides smoothly between them, resizing as it goes:

{ "type": "blur", "shape": "ellipse", "start": 4, "end": 12,
  "track": [ { "time": 4,  "x": 0.10, "y": 0.30, "w": 0.15, "h": 0.25 },
             { "time": 8,  "x": 0.45, "y": 0.28, "w": 0.18, "h": 0.30 },
             { "time": 12, "x": 0.80, "y": 0.30, "w": 0.15, "h": 0.25 } ] }

Add a keyframe wherever the motion changes direction or speed. Up to 50 keyframes per region.

Trim, stitch & splice

An edit makes a new video from clips of your finished videos (status SUCCEEDED). Send POST /videos with an edit instead of a file. There's nothing to upload; poll the new video's status as usual.

Clip fieldDescription
videoIdOne of your finished videos. The same video may appear several times.
start, endSeconds into that video (default: all of it).
transitionHow the clip starts from the previous one: omitted = hard cut; {"type": "fade" | "fadeblack", "seconds": 0.1–3}.

Also accepted: fileName, maxHeight, and redactions (on the edit's own timeline). Up to 50 clips. The first clip sets the frame size; differently shaped clips are letterboxed.

Recipes

// Cut 1:00–1:30 out of a video
{ "edit": { "clips": [ { "videoId": "AAAA…", "end": 60 }, { "videoId": "AAAA…", "start": 90 } ] } }

// Stitch an intro, a lesson and an outro, with soft joins
{ "fileName": "Lesson 1", "edit": { "clips": [
  { "videoId": "INTRO…" },
  { "videoId": "LESSON…", "transition": { "type": "fade", "seconds": 0.75 } },
  { "videoId": "OUTRO…",  "transition": { "type": "fadeblack", "seconds": 1 } } ] } }

// Splice a clip into another at 2:00
{ "edit": { "clips": [
  { "videoId": "MAIN…", "end": 120 },
  { "videoId": "INSERT…", "transition": { "type": "fadeblack", "seconds": 0.5 } },
  { "videoId": "MAIN…", "start": 120, "transition": { "type": "fadeblack", "seconds": 0.5 } } ] } }
201 Created
{ "videoId": "9a8b…", "status": "SUBMITTED", "clips": 3, "statusPath": "/videos/9a8b…" }

A clip from someone else's video gets 404 NOT_FOUND; a video still processing gets 409 EDIT_SOURCE_NOT_READY. To trim a new upload, use the trim option on complete instead: it's faster.

Status & download

GET /videos/3f1c…
{
  "videoId": "3f1c…",
  "status": "SUCCEEDED",
  "startedAt": 1790903142.5,
  "readyAt": 1790903205.0,
  "progress": { "planned": true, "chunksTotal": 4, "chunksDone": 4, "audioDone": true,
                "videoSeconds": 312.4, "topRendition": "1080p" },
  "downloadUrl": "https://…/download.mp4?…",
  "downloadExpiresInSeconds": 900
}
  • Poll every 5–15 seconds while the status is SUBMITTED or RUNNING. Don't poll faster than once a second per video.
  • downloadUrl is valid for 15 minutes. Fetch the status again for a fresh link, and don't store the link.
  • posterUrl is a still frame (JPEG) for thumbnails, also valid for 15 minutes.
  • progress shows chunks encoded out of the total, plus audio; videoSeconds is the result's length.
  • Processing time is readyAt − startedAt (Unix seconds).
  • edit / trim (when used) echo exactly how the video was cut, so you can check what was requested.

Streaming (Pro and Scale)

On Pro and Scale, finished videos also have adaptive streaming copies (HLS), and the status includes a link any standard player can play. The player picks the quality that suits each viewer's connection.

"streamUrl": "https://…/stream/3f1c…/1790925000/9b2e…/master.m3u8",
"streamExpiresAt": 1790925000
  • The link is valid for 6 hours (streamExpiresAt, Unix seconds). Fetch the status again for a fresh one when you load a player; don't store it.
  • It works in Safari and iOS natively, and anywhere else with hls.js, video.js, Shaka or ExoPlayer, including on your own website.
  • Streaming copies count toward your plan's storage. On other plans, videos get the download only.
<!-- hls.js where the browser can't play HLS itself -->
<video id="player" controls playsinline></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
<script>
  const video = document.getElementById("player"), url = STREAM_URL;  // from GET /videos/{id}
  if (video.canPlayType("application/vnd.apple.mpegurl")) video.src = url;
  else { const hls = new Hls(); hls.loadSource(url); hls.attachMedia(video); }
</script>

Listing your videos

GET /videos?limit=25
{ "videos": [ { "videoId": "9a8b…", "fileName": "Lesson 1", "createdAt": 1790903100, "state": "SUBMITTED", "clips": 3 }, … ],
  "nextToken": "eyJ2…" }

The newest videos come first. Pass nextToken back to get the next page. state only tells uploading from submitted; call GET /videos/{id} for the live status.

Uploading while recording (advanced)

For live recordings, upload while the recording is still being made, so the result is ready moments after it stops:

  1. Create with "streaming": true (no sizeBytes). Add "prestart": true to have processing ready and waiting.
  2. Request each part's URL with its exact size: {"parts": [{"partNumber": 4, "sizeBytes": 8388608}]}. Every part except the last must be at least 5 MiB.
  3. With prestart, send POST /videos/{id}/heartbeat every ~10 seconds while recording. If heartbeats stop for 2 minutes, the waiting job gives up.
  4. When recording ends, call complete with the totals: {"source": {"sizeBytes": …, "partCount": …}}. To cancel instead, call abort.

Usage and billing

Each user's usage is metered by month for billing. Call GET /usage?month=YYYY-MM to fetch processing and storage totals:

GET /usage?month=2026-10
{
  "month": "2026-10",
  "complete": true,
  "processing": {
    "videos": 5,
    "outputMinutes": 126.45,
    "billableMinutes": 158.60
  },
  "storage": {
    "gbMonths": 4.237,
    "storedGb": 1.506,
    "note": "download MP4s, posters and originals; streaming (HLS) copies are not billed"
  },
  "delivery": {
    "gb": null,
    "note": "not metered yet"
  }
}

Billing rules

  • Processing: billable minutes per video = max(60 seconds, ceil(output seconds)) / 60 × quality multiplier. Quality multiplier: ≤1080p ×1, 1440p ×2, 4K ×4. Counted when the video finishes. Each upload, reprocess and edit that completes counts as one.
  • Storage: GB-months = bytes kept × days kept / (1e9 × days in month). Includes download MP4s, posters and original uploads. HLS streaming copies are metered but not billed. Videos deleted in the past still contribute to the month's total up to their deletion date.
  • Pricing: free plans have no overage. Paid plans charge $0.09/minute and $0.15/GB-month for anything over the plan's included limits.
  • Delivery: download bandwidth is not metered yet.

Deleting videos

Call DELETE /videos/{id} to remove a video permanently. It cancels any running processing, removes all outputs and work files, and stops billing the video's storage immediately. Usage records stay forever as billing history. The response includes how many bytes were freed.

DELETE /videos/3f1c…
200 OK
{ "videoId": "3f1c…", "deleted": true, "originalDeleted": true, "freedBytes": 1234567890 }

Irreversible: deleted videos can't be reprocessed. If you reprocessed from the same original, it's still kept for other videos that need it.

Account and API keys

Sign up by sending your email to POST /auth/start, which emails a 6-digit code (5 attempts, 10 minute expiry). Verify it with POST /auth/verify, accepting the terms on your first sign-in, to get a sessionToken. Sessions last 30 days and are stored just like API keys but marked as temporary; use the token as a bearer token the same way.

When signed in (session token) or with your API key, you can:

  • GET /account for your email, plan name, limits, and this month's usage (minutes, storage).
  • GET /account/keys to list your API keys (never the keys themselves; they're shown once at creation).
  • POST /account/keys {label} to create a new key. Must be signed in with a session token.
  • DELETE /account/keys/{keyId} to revoke a key. Must be signed in with a session token.
  • POST /auth/signout to end the session (session tokens only).

Plan limits your maximum quality output, processing minutes and storage per month. Free-plan limits reset on the 1st of the month (UTC). Once your free-plan limit is hit, POST /videos returns 403 PLAN_LIMIT_REACHED. Paid plans continue and the overage is billed at your plan's rate. Usage details are available at GET /account.

Webhooks

Get notified when videos finish or fail, and when you're approaching your plan's limits. Set up a webhook endpoint (URL) in the web app on your Account → Webhooks page, or with the API:

  • GET /webhook — your current configuration.
  • PUT /webhook {url, events?, enabled?} — save or update an endpoint.
  • DELETE /webhook — remove the endpoint.
  • POST /webhook/rotate — generate a new signing secret (keep the URL).
  • POST /webhook/test — send a test event and report the result immediately.
  • GET /webhook/deliveries — the last 30 days of delivery attempts.

Events

Each account has one endpoint that receives events for all types it's subscribed to. The possible events are:

EventSent whenData
video.readyProcessing succeeded.videoId, fileName, statusPath, metadata (if set), durationSeconds, downloadUrl (valid 1 hour), downloadExpiresInSeconds, posterUrl, and if streaming: streamUrl.
video.failedProcessing failed or timed out.videoId, fileName, statusPath, metadata, status: FAILED or TIMED_OUT.
video.canceledProcessing was aborted.videoId, fileName, statusPath, metadata.
video.deletedA video was deleted.videoId, fileName, statusPath, metadata.
usage.threshold80% or 100% of your plan's monthly limits is reached (once each per month).measure (minutes or storage), percent (80 or 100), used, included (plan's allowance), month (YYYY-MM), plan (your plan name), overage (whether you'll be billed for excess).

Webhook envelope

Every event arrives as JSON with metadata about the event:

{
  "id": "evt_a1b2c3d4e5f6g7h8",
  "type": "video.ready",
  "createdAt": "2025-01-15T14:30:45Z",
  "data": { event-specific data }
}

Signature verification (Standard Webhooks)

Each delivery includes headers webhook-id, webhook-timestamp and webhook-signature that implement the Standard Webhooks specification, so libraries for any language can verify them:

// npm install standardwebhooks
import { Webhook } from "standardwebhooks";

const wh = new Webhook(webhookSecret);  // your secret from the account page
try {
  const payload = wh.verify(body, {
    "webhook-id": req.headers["webhook-id"],
    "webhook-timestamp": req.headers["webhook-timestamp"],
    "webhook-signature": req.headers["webhook-signature"],
  });
  // payload is the parsed event; proceed
} catch (err) {
  res.status(401).send("Unauthorized");
}

Reliability and delivery

  • Respond 2xx within 10 seconds. Your endpoint must be HTTPS and reachable from the public internet. Redirects (3xx) are not followed.
  • Retry policy: if you don't answer 2xx or timeout, delivery is retried after 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, 6 hours and 12 hours (8 attempts over ~22 hours).
  • At-least-once delivery: events may arrive more than once. Deduplicate using the webhook-id header (unique per event). Events may arrive out of order; use timestamps if order matters.
  • Delivery log: check GET /webhook/deliveries to see recent attempts, their status codes, response bodies and errors (kept for 30 days).

URL safety

Webhook URLs must be HTTPS and resolve only to public internet addresses. Private addresses (like 10.0.0.1, 192.168.1.x, 127.0.0.1, localhost or cloud-internal networks) are rejected when you save the URL or on every delivery attempt. This protects you from SSRF attacks. Redirects are never followed; the URL you set is the URL we connect to.

Validation & dry runs

Requests are checked before anything is created or started, against the real lengths of your videos where they're known. That includes trims past the end, clips that don't fit their video, transitions longer than their clips, redaction boxes outside the frame, and times after a video ends. Unknown fields (typos) are refused, never ignored.

Every problem is reported at once in details, each with its field path:

400
{
  "message": "edit.clips[0].end: 80s is past the end of video 3f1c…, which is 60.0s (1:00); use null for \"to the end\" (and 1 more problem)",
  "error": "INVALID_REQUEST",
  "requestId": "…",
  "details": [
    { "field": "edit.clips[0].end", "message": "80s is past the end of video 3f1c…, which is 60.0s (1:00); use null for \"to the end\"" },
    { "field": "redactions[0].w",   "message": "must be a fraction of the frame from 0 to 1; got 1.2 (pixels? divide by the frame size)" }
  ]
}

Dry run

Add ?dryRun=true to POST /videos (an upload or an edit), POST /videos/{id}/complete or POST /videos/{id}/reprocess to check a request without creating or starting anything. It doesn't count toward your daily video limit. A valid request answers 200 with "valid": true; an edit also tells you its resulting length:

POST /videos?dryRun=true
{ "edit": { "clips": [ { "videoId": "3f1c…", "end": 30 },
                       { "videoId": "9a8b…", "transition": { "type": "fade", "seconds": 1 } } ] } }

200 OK
{ "valid": true, "dryRun": true, "fileName": "Edit of 2 clips", "durationSeconds": 49.0, "duration": "49.0s (0:49)", "clips": [ … ] }

Use dry runs to validate user input in your app (for example, an edit timeline a user built) before submitting it.

Idempotency

Send an Idempotency-Key header with requests that create or start something (POST /videos, POST /videos/{id}/complete, POST /videos/{id}/reprocess

How it works

  • Format: 1–255 printable ASCII characters (no spaces). Choose any unique value per request.
  • Replay: same key, same request = the first response, with header Idempotent-Replayed: true. Store the videoId immediately on the first request (don't wait to see if it's a replay).
  • Reuse error: same key, different request (body, path or method) = 409 IDEMPOTENCY_KEY_REUSED. Use a new key.
  • In-progress error: same key while the first request is still processing = 409 IDEMPOTENCY_IN_PROGRESS. Retry in a moment.
  • Only 2xx stored: after an error the key is free, so a corrected retry works.
  • Expires: stored for 24 hours.
  • Dry runs skip keys: ?dryRun=true doesn't use or check the key.

Example

First request
POST /videos HTTP/1.1
Idempotency-Key: my-lesson-upload-20250101-abc123
Content-Type: application/json

{ "fileName": "lesson.mp4", "sizeBytes": 1048576 }

200 OK
{ "videoId": "3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f", "partSize": 67108864, … }

Retry with same key (e.g., connection dropped)
POST /videos HTTP/1.1
Idempotency-Key: my-lesson-upload-20250101-abc123

200 OK (same response as first time)
Idempotent-Replayed: true
{ "videoId": "3f1c0a9e5b7d4c2a8e6f1b0d9c7a5e3f", "partSize": 67108864, … }

Metadata

Store your own key-value pairs on a video: lesson IDs, course names, student IDs, project codes, anything. Metadata appears in status, list responses and webhooks, and you can filter listings by it.

Rules

  • Up to 20 keys per video.
  • Keys: 1–40 characters; letters, digits, _, ., -.
  • Values: strings, up to 500 characters each.
  • Total: 4 KB maximum for all metadata on one video.

Set on create

Add a metadata object when creating a video (upload or edit):

POST /videos
{
  "fileName": "lesson-1.mp4",
  "sizeBytes": 1048576,
  "metadata": { "lessonId": "123", "courseId": "algebra-1" }
}

Update with PATCH

Change metadata on a finished or in-progress video without re-uploading. Keys set to null are removed; other keys are set:

PATCH /videos/3f1c…
{ "metadata": { "lessonId": "456", "archived": null } }

200 OK
{ "videoId": "3f1c…", "metadata": { "lessonId": "456", "courseId": "algebra-1" } }

Filter listings

Find videos by metadata: GET /videos?metadata.lessonId=123. Each query can include up to 5 filters. Filters are AND'd together. The OpenAPI spec uses metadata.<key> as a placeholder for dynamic filter names.

Inheritance

When you reprocess a video, the new one gets the original's metadata unless you provide new metadata in the reprocess request.

Endpoints

All paths are relative to the base URL. Every field and response is in the API reference below, and in the spec: openapi.yaml · openapi.json.

EndpointDescriptionSuccess
GET/videosList your videos, newest first (limit 1–100, nextToken).200
POST/videosCreate a video: an upload (fileName, sizeBytes, maxHeight, camera, streaming, prestart) or an edit (edit).201
POST/videos/{id}/partsPre-signed upload URLs: partNumbers (or parts with sizes, for streaming), file: source | camera.200
POST/videos/{id}/completeFinish the upload and start processing, with options.202
GET/videos/{id}Status, progress, timing and download link.200
POST/videos/{id}/reprocessProcess again as a new video with new options (maxHeight, trim, redactions, deleteOriginal). Nothing is re-uploaded, and options aren't inherited. Returns the new videoId.201
POST/videos/{id}/cancelStop processing. The upload is kept, so you can reprocess later.200
DELETE/videos/{id}Remove a video permanently (irreversible). Cancels processing, removes outputs and work files. Stops billing storage. Returns {videoId, deleted: true, originalDeleted, freedBytes}.200
PATCH/videos/{id}Update metadata: {metadata: {key: value, …}}. Set keys or null to remove them.200
POST/videos/{id}/abortDiscard an unfinished upload and its parts.200
POST/videos/{id}/heartbeatKeep a pre-started recording job waiting (while recording).200
GET/usageUsage for a calendar month: processing time and storage, for billing. Query param month=YYYY-MM (defaults to current month). Returns aggregated minutes, storage, and current storage in GB.200
POST/auth/startPublic (no auth). Email a sign-in code: {email}. Returns {sent: true, expiresInSeconds: 600}.200
POST/auth/verifyPublic (no auth). Verify a code: {email, code, acceptTerms}. Returns {sessionToken, expiresAt, account, created}.200
POST/auth/signoutEnd a session (session token only).200
GET/accountYour account: email, plan, limits and this month's usage.200
GET/account/keysYour API keys (never the keys themselves; shown once at creation).200
POST/account/keysCreate an API key: {label}. Signed-in sessions only. Returns {key, keyId, label, note}.201
DELETE/account/keys/{keyId}Revoke an API key. Signed-in sessions only.200
GET/webhookYour webhook configuration: endpoint URL, events, enabled status, secret and timestamps.200
PUT/webhookSet or update your webhook endpoint: {url, events?, enabled?}. Returns the full config.200
DELETE/webhookRemove your webhook endpoint.200
POST/webhook/rotateGenerate a new signing secret (keep the URL). Returns the full config.200
POST/webhook/testSend a test event now and report the result: {ok, status, ms, error, response, eventId}.200
GET/webhook/deliveriesRecent delivery attempts (last 30 days, newest first). Returns {deliveries} array of {eventId, type, attempt, ok, status, ms, error, at, final}.200

API reference

Every operation, grouped like the spec. Open one to see its parameters, request body and responses, each with an example and the full schema. Load openapi.json or openapi.yaml into Postman, Insomnia or a code generator.

Videos

Create, list, check and delete videos (uploads and edits).

GET/videosList my videos (newest first)

Filter by metadata: include up to 5 parameters like metadata.lessonId=123. Filters are AND'd together.

Parameters
NameInTypeDescription
limitqueryinteger
nextTokenquerystring

From the previous page

metadata.<key>querystring

Filter by metadata value (up to 5 filters; dynamic parameter name)

Responses
200A page of videos
application/json object
{
  "videos": [
    {
      "videoId": "string",
      "fileName": "string",
      "cameraFileName": "string",
      "createdAt": 0,
      "sizeBytes": 0,
      "state": "UPLOADING",
      "redactions": 0,
      "originalDeleted": false,
      "clips": 0,
      "reprocessOf": "string",
      "trim": {
        "start": 0,
        "end": 0
      },
      "metadata": {}
    }
  ],
  "nextToken": "string"
}
Schema
  • videosarray of VideoSummary
    • videoIdstring
    • fileNamestring
    • cameraFileNamestring
    • createdAtinteger

      Unix time

    • sizeBytesinteger
    • statestring

      Call GET /videos/{id} for live status

      one of "UPLOADING", "READY_TO_START", "SUBMITTED"
    • redactionsinteger
    • originalDeletedboolean
    • clipsinteger

      Present for edits

    • reprocessOfstring
    • trimTrim

      Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

      • startnumber
        min 0 · default 0
      • endnumber

        null = to the end

    • metadataMetadata

      Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

  • nextTokenstring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId listVideos

POST/videosCreate a video (an upload, or an edit of finished videos)

Send an upload request, or an edit (no upload) to cut, join and splice your finished videos.

Parameters
NameInTypeDescription
dryRunqueryboolean

Validate only: nothing is created or started (answers 200 with valid: true)

Idempotency-Keyheaderstring

Unique key for idempotent requests: POST /videos, POST /videos/{id}/complete, POST /videos/{id}/reprocess. Same key with same request = replay of first response. Stored 24 hours.

Request body required
{
  "fileName": "lesson1.mp4",
  "sizeBytes": 104857600,
  "maxHeight": 1080,
  "camera": {
    "fileName": "string",
    "sizeBytes": 0
  },
  "layout": "pip",
  "streaming": false,
  "prestart": false,
  "metadata": {}
}
Schema
One of:
UploadRequest
  • fileNamestringrequired
  • sizeBytesinteger

    Required unless streaming

  • maxHeightinteger

    Highest output quality; never upscales

    one of 720, 1080, 1440, 2160 · default 1080
  • cameraobject

    Optional second file shown picture-in-picture over the first (screen + camera)

    • fileNamestring
    • sizeBytesinteger
  • layoutstring

    Optional with camera

    one of "pip"
  • streamingboolean

    Size unknown yet (e.g. still recording); parts are signed per size

  • prestartboolean

    With streaming

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

ImportRequest
  • sourceUrlstring (uri)required

    HTTPS URL (public internet addresses only; no username/password) with the video file. At most 3 redirects, each checked. The server must answer 200; file size is checked against the upload limit.

    max length 2048
  • fileNamestring

    Display name (default: last URL path segment). 1–200 characters.

  • maxHeightinteger

    Highest output quality; never upscales

    one of 720, 1080, 1440, 2160 · default 1080
  • trimTrim

    Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

    • startnumber
      min 0 · default 0
    • endnumber

      null = to the end

  • redactionsarray of Redaction

    Regions to blur or black out

    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • deleteOriginalboolean

    Delete the imported file once the output is published

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

EditRequest
  • editobjectrequired
    • clipsarray of Cliprequired
      max items 50
      • videoIdstringrequired

        One of your finished (SUCCEEDED) videos; may repeat

        pattern "^[a-f0-9]{32}$"
      • startnumber

        Seconds into that video

        min 0 · default 0
      • endnumber

        Seconds into that video; null = to its end

      • transitionobject

        How this clip starts from the previous one (hard cut if omitted; not on the first clip)

        • typestring
          one of "fade", "fadeblack" · default "fade"
        • secondsnumber
          min 0.1 · max 3 · default 0.5
  • fileNamestring

    Display name (default: Edit of N clips)

  • maxHeightinteger
    one of 720, 1080, 1440, 2160 · default 1080
  • redactionsarray of Redaction

    On the edit's own timeline

    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

Responses
201Created
application/json object
{
  "videoId": "string",
  "partSize": 0,
  "partCount": 0,
  "camera": {
    "partSize": 0,
    "partCount": 0
  },
  "clips": 0,
  "status": "UPLOADING"
}
Schema
  • videoIdstring
  • partSizeinteger

    Uploads only. Bytes per part (last part may be smaller)

  • partCountinteger

    Uploads only

  • cameraobject
    • partSizeinteger
    • partCountinteger
  • clipsinteger

    Edits only

  • statusstring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
403Plan does not allow this feature (e.g. streaming, 4K, screen recording) or plan limit reached (free tier only)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404Edit: a clip's videoId is not yours
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
409Edit: a clip's video has not finished processing
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429Rate limit or daily video limit
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId createVideo

GET/videos/{videoId}Status, timing and (when finished) a 15-minute download link
Parameters
NameInTypeDescription
videoIdrequiredpathstring
Responses
200Current state
application/json object
{
  "videoId": "string",
  "status": "UPLOADING",
  "readyAt": 0,
  "downloadUrl": "string",
  "posterUrl": "string",
  "streamUrl": "string",
  "streamExpiresAt": 0,
  "startedAt": 0,
  "stoppedAt": 0,
  "progress": {
    "planned": false,
    "chunksTotal": 0,
    "chunksDone": 0,
    "audioDone": false,
    "videoSeconds": 0,
    "topRendition": "1080p"
  },
  "downloadExpiresInSeconds": 0,
  "result": {
    "jobId": "string",
    "downloadAvailable": false,
    "streamAvailable": false
  }
}
Schema
  • videoIdstring
  • statusstring
    one of "UPLOADING", "READY_TO_START", "RUNNING", "SUCCEEDED", "FAILED", "TIMED_OUT", "ABORTED", "PENDING_REDRIVE", "HISTORY_UNAVAILABLE"
  • readyAtnumber

    Unix time the output was published

  • downloadUrlstring

    Pre-signed MP4 link (SUCCEEDED only)

  • posterUrlstring

    Pre-signed JPEG still frame for thumbnails (SUCCEEDED only)

  • streamUrlstring

    HLS master playlist link (Pro and Scale plans only; valid 6 hours)

  • streamExpiresAtnumber

    Unix time the streaming link expires

  • startedAtnumber

    Unix time processing started

  • stoppedAtnumber
  • progressobject
    • plannedboolean
    • chunksTotalinteger
    • chunksDoneinteger
    • audioDoneboolean
    • videoSecondsnumber
    • topRenditionstring
  • downloadExpiresInSecondsinteger
  • resultobject

    SUCCEEDED only - publication status

    • jobIdstring
    • downloadAvailableboolean
    • streamAvailableboolean

      Whether a playable streaming link exists

404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId getVideo

PATCH/videos/{videoId}Update video metadata (keys to null to remove them)
Parameters
NameInTypeDescription
videoIdrequiredpathstring
Request body required
application/json object
{
  "metadata": {
    "courseId": "algebra-2",
    "archived": null
  }
}
Schema
  • metadataobjectrequired
Responses
200Updated
application/json object
{
  "videoId": "string",
  "metadata": {}
}
Schema
  • videoIdstring
  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
409IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_IN_PROGRESS, or other conflict
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId updateVideo

DELETE/videos/{videoId}Remove a video (irreversible; stops billing its storage)

Cancels any running processing, removes outputs and work files. The original upload is removed unless another video was reprocessed from it and still exists. Usage records are kept for billing history.

Parameters
NameInTypeDescription
videoIdrequiredpathstring
Responses
200Deleted
application/json object
{
  "videoId": "string",
  "deleted": true,
  "originalDeleted": false,
  "freedBytes": 0
}
Schema
  • videoIdstring
  • deletedboolean
  • originalDeletedboolean

    Whether the original upload was also removed

  • freedBytesinteger

    Total bytes removed from storage

400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId deleteVideo

Uploads

Send a file's bytes in parts with pre-signed URLs, then complete or abort the upload.

POST/videos/{videoId}/partsGet pre-signed upload URLs for parts
Parameters
NameInTypeDescription
videoIdrequiredpathstring
Request body required
application/json object
{
  "partNumbers": [
    1,
    2
  ],
  "file": "source",
  "parts": [
    {
      "partNumber": 0,
      "sizeBytes": 0
    }
  ]
}
Schema
  • partNumbersarray of integer

    For normal uploads (1-100 per call)

  • filestring
    one of "source", "camera" · default "source"
  • partsarray of object

    For streaming uploads, each part with its exact size (>= 5 MiB except the last)

    • partNumberinteger
    • sizeBytesinteger
Responses
200URLs valid for 15 minutes; PUT the bytes with exactly sizeBytes as Content-Length
application/json object
{
  "parts": [
    {
      "partNumber": 0,
      "sizeBytes": 0,
      "url": "string"
    }
  ],
  "expiresInSeconds": 0
}
Schema
  • partsarray of object
    • partNumberinteger
    • sizeBytesinteger
    • urlstring
  • expiresInSecondsinteger
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId getPartUrls

POST/videos/{videoId}/completeFinish the upload and start processing (optionally with redactions)
Parameters
NameInTypeDescription
dryRunqueryboolean

Validate only: nothing is created or started (answers 200 with valid: true)

videoIdrequiredpathstring
Idempotency-Keyheaderstring

Unique key for idempotent requests: POST /videos, POST /videos/{id}/complete, POST /videos/{id}/reprocess. Same key with same request = replay of first response. Stored 24 hours.

Request body
application/json object
{
  "redactions": [
    {
      "type": "blur",
      "shape": "rect",
      "x": 0,
      "y": 0,
      "w": 0,
      "h": 0,
      "start": 0,
      "end": 0,
      "track": [
        {
          "time": 0,
          "x": 0,
          "y": 0,
          "w": 0,
          "h": 0
        }
      ]
    }
  ],
  "deleteOriginal": false,
  "trim": {
    "start": 0,
    "end": 0
  },
  "source": {
    "sizeBytes": 0,
    "partCount": 0
  },
  "camera": {
    "sizeBytes": 0,
    "partCount": 0
  }
}
Schema
  • redactionsarray of Redaction
    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • deleteOriginalboolean

    Delete the unredacted upload after the output is published

  • trimTrim

    Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

    • startnumber
      min 0 · default 0
    • endnumber

      null = to the end

  • sourceobject

    Streaming uploads only

    • sizeBytesinteger
    • partCountinteger
  • cameraobject

    Streaming uploads only

    • sizeBytesinteger
    • partCountinteger
Responses
202Accepted; poll GET /videos/{videoId}
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
403Plan does not allow this feature (e.g. redaction) or plan limit reached (free tier only)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
409Upload incomplete or sizes don't match
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId completeUpload

POST/videos/{videoId}/abortCancel an unfinished upload (deletes uploaded parts and the record)
Parameters
NameInTypeDescription
videoIdrequiredpathstring
Responses
200Cancelled
409Upload already completed
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId abortUpload

POST/videos/{videoId}/heartbeatKeep a pre-started recording job waiting (send every ~10 s while recording)

If heartbeats stop for 2 minutes the waiting job gives up. To cancel on purpose, call abort.

Parameters
NameInTypeDescription
videoIdrequiredpathstring
Responses
200OK
409Not an unfinished streaming upload with prestart
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId sendHeartbeat

Processing

Stop processing, or process a finished video again with new options.

POST/videos/{videoId}/cancelStop processing (the workflow and any of its queued or running jobs)
Parameters
NameInTypeDescription
videoIdrequiredpathstring
Responses
200Stopped; includes terminatedJobs
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId cancelProcessing

POST/videos/{videoId}/reprocessProcess a video again as a new video (new quality, trim and/or redactions)

Reuses the original upload (nothing is re-sent); for an edit, renders the same clips again. Options are not inherited. Not available after deleteOriginal.

Parameters
NameInTypeDescription
dryRunqueryboolean

Validate only: nothing is created or started (answers 200 with valid: true)

videoIdrequiredpathstring
Idempotency-Keyheaderstring

Unique key for idempotent requests: POST /videos, POST /videos/{id}/complete, POST /videos/{id}/reprocess. Same key with same request = replay of first response. Stored 24 hours.

Request body
application/json object
{
  "maxHeight": 720,
  "redactions": [
    {
      "type": "blur",
      "shape": "rect",
      "x": 0,
      "y": 0,
      "w": 0,
      "h": 0,
      "start": 0,
      "end": 0,
      "track": [
        {
          "time": 0,
          "x": 0,
          "y": 0,
          "w": 0,
          "h": 0
        }
      ]
    }
  ],
  "deleteOriginal": false,
  "trim": {
    "start": 0,
    "end": 0
  },
  "metadata": {}
}
Schema
  • maxHeightinteger
    one of 720, 1080, 1440, 2160
  • redactionsarray of Redaction
    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • deleteOriginalboolean

    Uploads only

  • trimTrim

    Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

    • startnumber
      min 0 · default 0
    • endnumber

      null = to the end

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

Responses
201New video created; poll its status
application/json object
{
  "videoId": "string",
  "reprocessOf": "string"
}
Schema
  • videoIdstring
  • reprocessOfstring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
403Plan does not allow the requested quality or feature, or plan limit reached (free tier only); reprocessing at a lower quality if the plan allows
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
409Original never completed or was deleted
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId reprocessVideo

Usage

Processing minutes and storage for billing.

GET/usageUsage for a calendar month (for billing)

Returns processing time and storage for a month, against the plan. Month defaults to the current UTC month.

Parameters
NameInTypeDescription
monthquerystring

YYYY-MM (default: current month)

Responses
200Usage summary
application/json object
{
  "month": "2026-10",
  "complete": false,
  "processing": {
    "videos": 0,
    "outputMinutes": 0,
    "billableMinutes": 0
  },
  "storage": {
    "gbMonths": 0,
    "storedGb": 0,
    "note": "string"
  },
  "delivery": {
    "gb": null,
    "note": "string"
  }
}
Schema
  • monthstring
  • completeboolean

    Whether the month is complete (now >= month end)

  • processingobject
    • videosinteger

      Count of videos that finished processing

    • outputMinutesnumber

      Sum of output duration (after trim/edit)

    • billableMinutesnumber

      max(60

  • storageobject
    • gbMonthsnumber

      Byte-time (bytes × time) for bytes kept

    • storedGbnumber

      What is stored right now

    • notestring
  • deliveryobject
    • gbnull

      Not metered yet

    • notestring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId getUsage

Authentication

Sign up and sign in with email, create sessions and API keys, manage your account.

POST/auth/startEmail a sign-in code (public; no auth required)

Sends a 6-digit code to the email address. 5 attempts per code, 10 minute expiry. Rate limited 5 per email per hour, 30 per IP per hour.

Request body required
application/json object
{
  "email": "user@example.com"
}
Schema
  • emailstringrequired
Responses
200Code sent
application/json object
{
  "sent": false,
  "expiresInSeconds": 0
}
Schema
  • sentboolean
  • expiresInSecondsinteger
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429Rate limited
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId startSignIn

POST/auth/verifyVerify a sign-in code (public; no auth required)

On first sign-in (new account), acceptTerms must be true. Returns a session token valid for 30 days.

Request body required
application/json object
{
  "email": "user@example.com",
  "code": "123456",
  "acceptTerms": false
}
Schema
  • emailstringrequired
  • codestringrequired
    pattern "^\\d{6}$"
  • acceptTermsboolean

    Required to create an account

Responses
200Verified
application/json object
{
  "sessionToken": "vps_...",
  "expiresAt": 0,
  "created": false,
  "account": {
    "email": "string",
    "plan": "string",
    "user": "string"
  }
}
Schema
  • sessionTokenstring
  • expiresAtinteger

    Unix time

  • createdboolean

    True if a new account was created

  • accountobject
    • emailstring
    • planstring
    • userstring
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429Rate limited
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId verifySignIn

POST/auth/signoutEnd a session (session token only)
Responses
200Signed out
application/json object
{
  "signedOut": false
}
Schema
  • signedOutboolean
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId signOut

GET/accountYour account info, plan and this month's usage
Responses
200Account details
application/json object
{
  "email": "string",
  "user": "string",
  "plan": "string",
  "planName": "string",
  "createdAt": "string",
  "limits": {
    "minutes": 0,
    "storageGb": 0,
    "maxHeight": 720,
    "features": [
      "string"
    ],
    "videosPerDay": 0,
    "apiKeys": 0,
    "overage": false
  },
  "usage": {
    "month": "2026-10",
    "billableMinutes": 0,
    "videos": 0,
    "storedGb": 0,
    "gbMonths": 0
  },
  "session": false,
  "billing": {
    "customer": false
  }
}
Schema
  • emailstring
  • userstring
  • planstring
  • planNamestring
  • createdAtstring (date-time)
  • limitsobject
    • minutesinteger

      Monthly processing minutes (billable)

    • storageGbinteger

      Monthly storage in GB

    • maxHeightinteger
      one of 720, 1080, 1440, 2160
    • featuresarray of string
    • videosPerDayinteger
    • apiKeysinteger

      Max simultaneous API keys

    • overageboolean

      Whether overage is billed

  • usageobject
    • monthstring
    • billableMinutesnumber
    • videosinteger
    • storedGbnumber
    • gbMonthsnumber
  • sessionboolean

    True if authenticated with a session token

  • billingobject
    • customerboolean

      Has a Stripe customer ID

401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId getAccount

GET/account/keysList your API keys (never the keys themselves)
Responses
200API keys
application/json object
{
  "keys": [
    {
      "keyId": "string",
      "label": "string",
      "createdAt": "string",
      "revoked": false,
      "prefix": "string"
    }
  ]
}
Schema
  • keysarray of object
    • keyIdstring
    • labelstring
    • createdAtstring (date-time)
    • revokedboolean
    • prefixstring

      First 8 chars of the key

401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId listApiKeys

POST/account/keysCreate an API key (session token only)
Request body required
application/json object
{
  "label": "string"
}
Schema
  • labelstring

    Optional label for the key

    max length 60
Responses
201Key created
application/json object
{
  "key": "string",
  "keyId": "string",
  "label": "string",
  "note": "string"
}
Schema
  • keystring

    The full key (shown only once)

  • keyIdstring
  • labelstring
  • notestring

    Copy it now: it can't be shown again

401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
403Session required or plan limit reached
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId createApiKey

DELETE/account/keys/{keyId}Revoke an API key (session token only)
Parameters
NameInTypeDescription
keyIdrequiredpathstring
Responses
200Revoked
application/json object
{
  "keyId": "string",
  "revoked": false
}
Schema
  • keyIdstring
  • revokedboolean
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
403Session required
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404NOT_FOUND: no such video for this user (wrong ID or someone else's)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId revokeApiKey

Webhooks

Set up an endpoint to receive events when videos finish, fail, or you reach usage thresholds. Each account has one webhook. Events are signed with Standard Webhooks. Events: video.ready (processing succeeded), video.failed, video.canceled, video.deleted, usage.threshold (80% and 100% of plan limits). Each event envelope contains id, type, createdAt and data. Signature verification uses HMAC-SHA256 of "id.timestamp.body" with the base64-decoded secret after "whsec_".

GET/webhookGet your webhook configuration
Responses
200Webhook config
application/json object
{
  "configured": false,
  "url": "string",
  "events": [
    "video.ready"
  ],
  "enabled": false,
  "secret": "string",
  "createdAt": "string",
  "updatedAt": "string"
}
Schema
  • configuredboolean
  • urlstring
  • eventsarray of string
  • enabledboolean
  • secretstring

    whsec_-prefixed signing secret

  • createdAtstring (date-time)
  • updatedAtstring (date-time)
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId getWebhookConfig

PUT/webhookSet or update your webhook endpoint
Request body required
application/json object
{
  "url": "string",
  "events": [
    "video.ready"
  ],
  "enabled": false
}
Schema
  • urlstring (uri)required

    HTTPS only, public addresses only

  • eventsarray of string

    Defaults to all events if omitted

  • enabledboolean

    Defaults to true

Responses
200Saved
application/json object
{
  "configured": false,
  "url": "string",
  "events": [
    "string"
  ],
  "enabled": false,
  "secret": "string",
  "createdAt": "string",
  "updatedAt": "string"
}
Schema
  • configuredboolean
  • urlstring
  • eventsarray of string
  • enabledboolean
  • secretstring
  • createdAtstring (date-time)
  • updatedAtstring (date-time)
400INVALID_REQUEST: invalid body or parameter (the message names the field)
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId setWebhookConfig

DELETE/webhookRemove your webhook endpoint
Responses
200Deleted
application/json object
{
  "configured": false
}
Schema
  • configuredboolean
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId deleteWebhookConfig

POST/webhook/rotateGenerate a new signing secret (keep the URL)
Responses
200New secret
application/json object
{
  "configured": false,
  "url": "string",
  "events": [
    "string"
  ],
  "enabled": false,
  "secret": "string",
  "createdAt": "string",
  "updatedAt": "string"
}
Schema
  • configuredboolean
  • urlstring
  • eventsarray of string
  • enabledboolean
  • secretstring

    New whsec_-prefixed secret; old one stops working immediately

  • createdAtstring (date-time)
  • updatedAtstring (date-time)
401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404No webhook is set up yet
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId rotateWebhookSecret

POST/webhook/testSend a test event and report the result immediately
Responses
200Test sent and one attempt reported
application/json object
{
  "ok": false,
  "status": 0,
  "ms": 0,
  "error": "string",
  "response": "string",
  "eventId": "string"
}
Schema
  • okboolean
  • statusinteger

    HTTP status code from the endpoint

  • msinteger

    Milliseconds to respond (or error)

  • errorstring

    Error message if not ok

  • responsestring

    First 500 bytes of the response body

  • eventIdstring

    The test event ID

401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
404No webhook is set up yet
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId testWebhook

GET/webhook/deliveriesRecent webhook delivery attempts (kept for 30 days)
Parameters
NameInTypeDescription
limitqueryinteger
Responses
200Delivery log
application/json object
{
  "deliveries": [
    {
      "eventId": "string",
      "type": "string",
      "attempt": 0,
      "ok": false,
      "status": 0,
      "ms": 0,
      "error": "string",
      "response": "string",
      "at": 0,
      "final": false
    }
  ]
}
Schema
  • deliveriesarray of object
    • eventIdstring
    • typestring
    • attemptinteger
    • okboolean
    • statusinteger
    • msinteger

      Milliseconds taken

    • errorstring
    • responsestring

      First 500 bytes of response

    • atinteger

      Unix time

    • finalboolean

      Whether retries will stop

401UNAUTHORIZED: missing, unknown or revoked API key
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
429RATE_LIMITED (retry with backoff), QUOTA_EXCEEDED, DAILY_LIMIT or VIDEOS_PAUSED
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
503UNAVAILABLE: temporary failure; retry with backoff
application/json Error
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Schema
  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring

operationId listWebhookDeliveries

Schemas

Errorobject

Every error response (from the API and from API Gateway). Program against error; show message.

  • messagestringrequired

    Human-readable; wording may change

  • errorstringrequired

    Stable machine-readable code (new codes may be added; fall back to the HTTP status)

    one of "INVALID_REQUEST", "UNAUTHORIZED", "MISSING_AUTHENTICATION", "FORBIDDEN", "REQUEST_REJECTED", "NOT_FOUND", "ROUTE_NOT_FOUND", "METHOD_NOT_ALLOWED", "UPLOAD_INCOMPLETE", "ALREADY_COMPLETED", "ORIGINAL_UNAVAILABLE", "EDIT_SOURCE_NOT_READY", "NOT_AN_UPLOAD", "IDEMPOTENCY_KEY_REUSED", "IDEMPOTENCY_IN_PROGRESS", "INVALID_STATE", "TOO_LARGE", "RATE_LIMITED", "QUOTA_EXCEEDED", "DAILY_LIMIT", "VIDEOS_PAUSED", "PLAN_UPGRADE_REQUIRED", "PLAN_LIMIT_REACHED", "INVALID_CODE", "TERMS_REQUIRED", "SESSION_REQUIRED", "ACCOUNT_DISABLED", "EMAIL_NOT_CONFIGURED", "EMAIL_FAILED", "UPSTREAM_ERROR", "UNAVAILABLE"
  • requestIdstringrequired

    Quote this when reporting a problem

  • detailsarray of object

    Validation errors only (400 INVALID_REQUEST) - every problem found, with its field path

    • fieldstring
    • messagestring
{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "string",
  "details": [
    {
      "field": "edit.clips[0].end",
      "message": "80s is past the end of video …, which is 60.0s (1:00); use null for \"to the end\""
    }
  ]
}
Metadataobject

Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

{}
UploadRequestobject
  • fileNamestringrequired
  • sizeBytesinteger

    Required unless streaming

  • maxHeightinteger

    Highest output quality; never upscales

    one of 720, 1080, 1440, 2160 · default 1080
  • cameraobject

    Optional second file shown picture-in-picture over the first (screen + camera)

    • fileNamestring
    • sizeBytesinteger
  • layoutstring

    Optional with camera

    one of "pip"
  • streamingboolean

    Size unknown yet (e.g. still recording); parts are signed per size

  • prestartboolean

    With streaming

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

{
  "fileName": "lesson1.mp4",
  "sizeBytes": 104857600,
  "maxHeight": 1080,
  "camera": {
    "fileName": "string",
    "sizeBytes": 0
  },
  "layout": "pip",
  "streaming": false,
  "prestart": false,
  "metadata": {}
}
ImportRequestobject

Import a video from a public HTTPS URL instead of uploading. The URL is downloaded by the API.

  • sourceUrlstring (uri)required

    HTTPS URL (public internet addresses only; no username/password) with the video file. At most 3 redirects, each checked. The server must answer 200; file size is checked against the upload limit.

    max length 2048
  • fileNamestring

    Display name (default: last URL path segment). 1–200 characters.

  • maxHeightinteger

    Highest output quality; never upscales

    one of 720, 1080, 1440, 2160 · default 1080
  • trimTrim

    Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

    • startnumber
      min 0 · default 0
    • endnumber

      null = to the end

  • redactionsarray of Redaction

    Regions to blur or black out

    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • deleteOriginalboolean

    Delete the imported file once the output is published

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

{
  "sourceUrl": "string",
  "fileName": "string",
  "maxHeight": 1080,
  "trim": {
    "start": 0,
    "end": 0
  },
  "redactions": [
    {
      "type": "blur",
      "shape": "rect",
      "x": 0,
      "y": 0,
      "w": 0,
      "h": 0,
      "start": 0,
      "end": 0,
      "track": [
        {
          "time": 0,
          "x": 0,
          "y": 0,
          "w": 0,
          "h": 0
        }
      ]
    }
  ],
  "deleteOriginal": false,
  "metadata": {}
}
EditRequestobject

A new video from clips of your finished videos, played in order (trim, stitch, splice).

  • editobjectrequired
    • clipsarray of Cliprequired
      max items 50
      • videoIdstringrequired

        One of your finished (SUCCEEDED) videos; may repeat

        pattern "^[a-f0-9]{32}$"
      • startnumber

        Seconds into that video

        min 0 · default 0
      • endnumber

        Seconds into that video; null = to its end

      • transitionobject

        How this clip starts from the previous one (hard cut if omitted; not on the first clip)

        • typestring
          one of "fade", "fadeblack" · default "fade"
        • secondsnumber
          min 0.1 · max 3 · default 0.5
  • fileNamestring

    Display name (default: Edit of N clips)

  • maxHeightinteger
    one of 720, 1080, 1440, 2160 · default 1080
  • redactionsarray of Redaction

    On the edit's own timeline

    max items 20
    • typestringrequired

      box = solid black bar

      one of "blur", "box"
    • shapestring
      one of "rect", "ellipse" · default "rect"
    • xnumber

      Fraction of the final frame width

      min 0 · max 1
    • ynumber
      min 0 · max 1
    • wnumber
      min 0 · max 1
    • hnumber
      min 0 · max 1
    • startnumber

      Seconds

      default 0
    • endnumber

      Seconds; null = until the end

    • trackarray of object

      Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

      max items 50
      • timenumberrequired

        Seconds on the output timeline

        min 0
      • xnumberrequired
        min 0 · max 1
      • ynumberrequired
        min 0 · max 1
      • wnumberrequired
        min 0 · max 1
      • hnumberrequired
        min 0 · max 1
  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

{
  "edit": {
    "clips": [
      {
        "videoId": "string",
        "start": 0,
        "end": 0,
        "transition": {
          "type": "fade",
          "seconds": 0.5
        }
      }
    ]
  },
  "fileName": "string",
  "maxHeight": 1080,
  "redactions": [
    {
      "type": "blur",
      "shape": "rect",
      "x": 0,
      "y": 0,
      "w": 0,
      "h": 0,
      "start": 0,
      "end": 0,
      "track": [
        {
          "time": 0,
          "x": 0,
          "y": 0,
          "w": 0,
          "h": 0
        }
      ]
    }
  ],
  "metadata": {}
}
Clipobject
  • videoIdstringrequired

    One of your finished (SUCCEEDED) videos; may repeat

    pattern "^[a-f0-9]{32}$"
  • startnumber

    Seconds into that video

    min 0 · default 0
  • endnumber

    Seconds into that video; null = to its end

  • transitionobject

    How this clip starts from the previous one (hard cut if omitted; not on the first clip)

    • typestring
      one of "fade", "fadeblack" · default "fade"
    • secondsnumber
      min 0.1 · max 3 · default 0.5
{
  "videoId": "string",
  "start": 0,
  "end": 0,
  "transition": {
    "type": "fade",
    "seconds": 0.5
  }
}
Trimobject

Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

  • startnumber
    min 0 · default 0
  • endnumber

    null = to the end

{
  "start": 0,
  "end": 0
}
VideoSummaryobject
  • videoIdstring
  • fileNamestring
  • cameraFileNamestring
  • createdAtinteger

    Unix time

  • sizeBytesinteger
  • statestring

    Call GET /videos/{id} for live status

    one of "UPLOADING", "READY_TO_START", "SUBMITTED"
  • redactionsinteger
  • originalDeletedboolean
  • clipsinteger

    Present for edits

  • reprocessOfstring
  • trimTrim

    Keep only part of the upload (frame-accurate, no extra encode). Redaction times are on the trimmed timeline.

    • startnumber
      min 0 · default 0
    • endnumber

      null = to the end

  • metadataMetadata

    Customer key-value pairs (up to 20 keys, 4 KB total). Keys are 1-40 [A-Za-z0-9_.-]; values are strings up to 500 chars.

{
  "videoId": "string",
  "fileName": "string",
  "cameraFileName": "string",
  "createdAt": 0,
  "sizeBytes": 0,
  "state": "UPLOADING",
  "redactions": 0,
  "originalDeleted": false,
  "clips": 0,
  "reprocessOf": "string",
  "trim": {
    "start": 0,
    "end": 0
  },
  "metadata": {}
}
Redactionobject

A fixed box (x, y, w, h) or a moving one (track). Not both.

  • typestringrequired

    box = solid black bar

    one of "blur", "box"
  • shapestring
    one of "rect", "ellipse" · default "rect"
  • xnumber

    Fraction of the final frame width

    min 0 · max 1
  • ynumber
    min 0 · max 1
  • wnumber
    min 0 · max 1
  • hnumber
    min 0 · max 1
  • startnumber

    Seconds

    default 0
  • endnumber

    Seconds; null = until the end

  • trackarray of object

    Keyframes for moving content, in time order; the region glides between them (instead of x, y, w, h)

    max items 50
    • timenumberrequired

      Seconds on the output timeline

      min 0
    • xnumberrequired
      min 0 · max 1
    • ynumberrequired
      min 0 · max 1
    • wnumberrequired
      min 0 · max 1
    • hnumberrequired
      min 0 · max 1
{
  "type": "blur",
  "shape": "rect",
  "x": 0,
  "y": 0,
  "w": 0,
  "h": 0,
  "start": 0,
  "end": 0,
  "track": [
    {
      "time": 0,
      "x": 0,
      "y": 0,
      "w": 0,
      "h": 0
    }
  ]
}

Errors

Every error has the same JSON body:

{
  "message": "Daily limit reached (50 videos per 24 hours); try again later",
  "error": "DAILY_LIMIT",
  "requestId": "c0a8f1e2-5b7d-4c2a-8e6f-1b0d9c7a5e3f"
}
  • error: a stable code. Write your code against this. New codes may be added; handle unknown ones by HTTP status.
  • message: human-readable and safe to show to users. Its wording may change.
  • requestId: include it when you report a problem.
  • details (validation errors only): every problem found, as {field, message}. See Validation.
HTTPerrorMeaningWhat to do
400INVALID_REQUESTInvalid body or parameter; the message names the field.Fix the request.
401UNAUTHORIZEDMissing, unknown or revoked API key.Check the Authorization header.
403MISSING_AUTHENTICATIONThe request didn't reach the API with a key, usually because the base URL is missing its /v1 path.Check the base URL.
403FORBIDDENCredentials not allowed.Check your key.
403REQUEST_REJECTEDRejected before reaching the API, almost always a base URL missing /v1.Check the base URL.
404NOT_FOUNDNo such video for you.Check the ID.
404ROUTE_NOT_FOUNDNo such path.Check the URL.
405METHOD_NOT_ALLOWEDWrong HTTP method; the message lists the right one.Use the listed method.
409UPLOAD_INCOMPLETEParts missing or the wrong size.Upload the missing parts, then complete again.
409ALREADY_COMPLETEDThe upload already completed.Use cancel to stop processing.
409ORIGINAL_UNAVAILABLEReprocess: the original is missing or was deleted.Upload again.
409EDIT_SOURCE_NOT_READYAn edit clip's video hasn't finished.Wait for SUCCEEDED.
409NOT_AN_UPLOADAn upload action on an edit.Use cancel or reprocess.
409IDEMPOTENCY_KEY_REUSEDSame Idempotency-Key, different request.Use a new key.
409IDEMPOTENCY_IN_PROGRESSA request with this Idempotency-Key is still processing.Retry in a moment.
409INVALID_STATENot possible in the video's current state.Read the message.
413TOO_LARGEThe JSON body is too large.Send less.
429RATE_LIMITEDMore than 5 requests per second.Retry with backoff.
429QUOTA_EXCEEDEDDaily request quota used up.Try again tomorrow.
429DAILY_LIMITDaily new-video limit reached.Wait; it's a rolling 24 hours.
403PLAN_UPGRADE_REQUIREDThe request uses something your plan doesn't include: a higher quality than its maximum (Free 720p, Starter 1080p), redaction, screen recording (camera, streaming uploads). details names the field.Remove it, lower maxHeight, or upgrade.
403PLAN_LIMIT_REACHEDFree plan only: this month's processing minutes or the storage allowance is used up. Nothing is deleted.Delete videos you don't need, wait for the 1st (UTC), or upgrade.
429VIDEOS_PAUSEDNew videos are paused for your account.Contact the service owner.
502UPSTREAM_ERRORAn internal inconsistency.Report it with the requestId.
503UNAVAILABLEA temporary failure.Retry with backoff.
Retry RATE_LIMITED, UNAVAILABLE and network errors with exponential backoff (e.g. 1 s, 2 s, 4 s… with jitter). Don't retry other 4xx errors unchanged.

Limits

LimitDefault
Requests5 per second per key (bursts of 10)
Daily requests5,000 per key
New videos50 per rolling 24 hours (uploads, edits and reprocesses each count)
File size20 GiB per file
Duration8 hours per video
Upload URL lifetime15 minutes
Download URL lifetime15 minutes
Streaming link lifetime6 hours (Pro and Scale)
Top quality by planFree 720p · Starter 1080p · Pro and Scale 4K
Monthly processing and storageYour plan's allowance (see pricing). Free stops there; paid plans continue and the extra is billed.
Redactions20 per video
Edit clips50 per edit; transitions 0.1–3 s

Your account may have different limits; ask the service owner.

Best practices

  • Keep the key server-side, and pass only pre-signed URLs to browsers and apps.
  • Store the videoId as soon as you create a video: it's how you resume, check status, or abort.
  • Retry safely. Send an Idempotency-Key header with POST /videos, POST /videos/{id}/complete, and POST /videos/{id}/reprocess. Part uploads can be retried with fresh URLs. See Idempotency.
  • Poll politely: every 5–15 seconds, and stop at a final status (SUCCEEDED, FAILED, TIMED_OUT, ABORTED).
  • Fetch download links when needed. They expire after 15 minutes, so don't cache them.
  • Handle errors by the error code, not by the message text.

Changelog

VersionChanges
v1Uploads (including screen + camera and while recording), processing options (quality, trim, redactions), edits (stitch, splice, cut), reprocess, cancel, structured errors, up-front validation with details, and dry runs.

Changes within v1 only add things (new fields, new error codes) and never remove or rename existing ones.