Platform
Errors
A failed request returns an HTTP status and a JSON body with a stable error code. When the video itself is the problem, the request still works and the job fails instead.
Error format
Every error has this shape. This is the answer to a request that asked for too many clips:
{
"error": {
"code": "INVALID_REQUEST",
"message": "clips: Must be a whole number from 1 to 20",
"issues": [
{
"path": "clips",
"message": "Must be a whole number from 1 to 20"
}
]
}
}error.stringcode - Stable and machine-readable. Branch on this.
error.stringmessage - What went wrong, for people and logs. On
INVALID_REQUESTit joins the issues aspath: message, separated by semicolons. error.arrayissues - Only on
INVALID_REQUEST: one entry per problem. error.stringissues[]. path - The field, like
clipsormax_seconds. Empty when the whole body is wrong. error.stringissues[]. message - What's wrong with it.
Request errors
These come back as the response to your call. Each one lists the error.message you get, and when.
INVALID_REQUESTHTTP 400- A field is missing, has the wrong type or is out of range.
issueslists each one.- A field fails a check
clips: Must be a whole number from 1 to 20 - The body isn't a JSON object
body must be a JSON object waitis out of rangewait must be 0..300 seconds
issues, then send the request again. Fields we don't know are ignored, so a misspelled field is skipped without an error. - A field fails a check
INVALID_JSONHTTP 400- The body is empty or isn't valid JSON.
- Empty body
request body is empty, send a JSON object - Broken JSON
body is not valid JSON
- Empty body
INSUFFICIENT_CREDITHTTP 402- You're out of credit.Add credit in the dashboard, then retry.
HTTPS_REQUIREDHTTP 403- You called the API over plain
http://. API calls only work over https.plain http is refused so API keys never travel unencrypted, use https://api.clipsdk.com
https://api.clipsdk.com. NOT_FOUNDHTTP 404- The path doesn't exist, or the job doesn't.
- Unknown path
no route for POST /v1/clip, see /openapi.json - Unknown job, or one made with another key
unknown job
- Unknown path
METHOD_NOT_ALLOWEDHTTP 405- The path exists, but not with this method.
GET /v1/clipsuse POST
PAYLOAD_TOO_LARGEHTTP 413- The request body is too big. Video files never go in an API request body.
POST /v1/clipsover 2 MBbody over 2097152 bytesPOST /v1/uploadsover 16 KBbody over 16384 bytes
RATE_LIMITEDHTTP 429Safe to retry- You hit a limit.
Retry-Aftersays how many seconds to wait.- 3 jobs already running on this key
this key already has 3 jobs runningRetry-After: 10 - 200 jobs created today, UTC
this key reached its 200 jobs per dayRetry-After: seconds until 00:00 UTC - 20 GB uploaded today, UTC
this key reached its 20 GB of uploads per dayRetry-After: seconds until 00:00 UTC - 30 failed auths from your IP within a minute
too many failed auth attempts from your IP, retry in a minuteRetry-After: 60
Retry-Afterseconds, then send the request again. Nothing is queued for you. See Limits. - 3 jobs already running on this key
Server errors
INTERNALHTTP 500Safe to retry- Something broke on our side.Retry with backoff. If it keeps happening, email kevin@bitgate.com with the time of the request.
Job failures
When the video is the problem, the request still succeeds. The job ends with status failed and error says why. You get it with HTTP 200 from GET /v1/jobs/{id}, or in a job.failed webhook.
{
"job": {
"id": "job_f3k9m2p7x4c8v1b6n5z0",
"op": "clips",
"status": "failed",
"stage": null,
"created_at": "2026-10-26T09:14:02Z",
"finished_at": "2026-10-26T09:14:09Z",
"result": null,
"usage": {
"source_minutes": 0,
"clips": 0,
"output_seconds": 0
},
"error": {
"code": "INPUT_FETCH_FAILED",
"message": "Could not fetch video_url: HTTP 404"
},
"poll_url": "https://api.clipsdk.com/v1/jobs/job_f3k9m2p7x4c8v1b6n5z0"
}
}A failed job costs nothing: its usage is all zeros, and stage and result are null.
INPUT_FETCH_FAILED- We couldn't download
video_url.- The URL answered 404
Could not fetch video_url: HTTP 404
PUTbefore you create the job. - The URL answered 404
INPUT_UNSUPPORTED- The file isn't a video we can read, has no video stream, or has no moment that fits your clip length.
- No moment fits the clip length
no moment in video_url fits the requested clip length
min_secondsor send a longer video. - No moment fits the clip length
INPUT_TOO_LONG- The video runs longer than 3 hours.Trim it, or split it into parts under 3 hours.
INPUT_TOO_LARGE- The file is bigger than 5 GB.Re-encode it at a lower bitrate, or split it.
NO_SPEECH- The video has no audio track, or too little speech to rank.clipsdk picks moments from what people say, so send a video with talking in it.
INTERNALSafe to retry- Something broke on our side while the job ran.
something broke on our side, please retry
Handle errors
When the status isn't 2xx, read error.code and error.message. All three versions retry 429 and 500 when the wait is a minute or less:
# --fail-with-body exits non-zero on 4xx and 5xx but still prints the error JSON
# --retry 2 tries 429 and 500 again, waiting out Retry-After for up to a minute
curl https://api.clipsdk.com/v1/clips --fail-with-body --retry 2 --retry-max-time 60 \
-H "Authorization: Bearer $CLIPSDK_KEY" \
-H "Content-Type: application/json" \
-d '{"video_url": "https://cdn.example.com/off-script-112.mp4", "clips": 50}'When to retry
429: wait theRetry-Afterseconds, then retry. For the daily limits that's until 00:00 UTC.500and the job failureINTERNAL: safe to retry, with backoff.- Any other 4xx: fix the request first. Sent again unchanged, it fails the same way.
- Other job failures: fix the input, then create a new job.
INPUT_FETCH_FAILEDcan pass on a retry if the host was down.