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:

400 Bad Request
{
  "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.codestring
Stable and machine-readable. Branch on this.
error.messagestring
What went wrong, for people and logs. On INVALID_REQUEST it joins the issues as path: message, separated by semicolons.
error.issuesarray
Only on INVALID_REQUEST: one entry per problem.
error.issues[].pathstring
The field, like clips or max_seconds. Empty when the whole body is wrong.
error.issues[].messagestring
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. issues lists each one.
  • A field fails a checkclips: Must be a whole number from 1 to 20
  • The body isn't a JSON objectbody must be a JSON object
  • wait is out of rangewait must be 0..300 seconds
Fix each field in issues, then send the request again. Fields we don't know are ignored, so a misspelled field is skipped without an error.
INVALID_JSONHTTP 400
The body is empty or isn't valid JSON.
  • Empty bodyrequest body is empty, send a JSON object
  • Broken JSONbody is not valid JSON
Send a JSON object as the request body.
UNAUTHORIZEDHTTP 401
The API key is missing, wrong or revoked.
  • No Authorization headersend your API key as 'Authorization: Bearer csdk_live_...'
  • Unknown keyinvalid API key
  • Revoked keythis API key was revoked
Send Authorization: Bearer csdk_live_... with a key that is still active.
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
Call https://api.clipsdk.com.
NOT_FOUNDHTTP 404
The path doesn't exist, or the job doesn't.
  • Unknown pathno route for POST /v1/clip, see /openapi.json
  • Unknown job, or one made with another keyunknown job
Check the path against /openapi.json. A job is only visible to the API key that created it.
METHOD_NOT_ALLOWEDHTTP 405
The path exists, but not with this method.
  • GET /v1/clipsuse POST
Use the method the message names.
PAYLOAD_TOO_LARGEHTTP 413
The request body is too big. Video files never go in an API request body.
  • POST /v1/clips over 2 MBbody over 2097152 bytes
  • POST /v1/uploads over 16 KBbody over 16384 bytes
Pass the video as a URL, or upload it with POST /v1/uploads first.
RATE_LIMITEDHTTP 429Safe to retry
You hit a limit. Retry-After says how many seconds to wait.
  • 3 jobs already running on this keythis key already has 3 jobs runningRetry-After: 10
  • 200 jobs created today, UTCthis key reached its 200 jobs per dayRetry-After: seconds until 00:00 UTC
  • 20 GB uploaded today, UTCthis key reached its 20 GB of uploads per dayRetry-After: seconds until 00:00 UTC
  • 30 failed auths from your IP within a minutetoo many failed auth attempts from your IP, retry in a minuteRetry-After: 60
Wait the Retry-After seconds, then send the request again. Nothing is queued for you. See Limits.

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.

200 OK
{
  "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 404Could not fetch video_url: HTTP 404
Make sure the URL is public and still works. For an upload, finish the PUT before you create the job.
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 lengthno moment in video_url fits the requested clip length
Send MP4, MOV, WebM or MKV with a video stream. If no moment fits, lower min_seconds or send a longer video.
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
Create the job again. If it keeps failing, email kevin@bitgate.com with the job id.

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 the Retry-After seconds, then retry. For the daily limits that's until 00:00 UTC.
  • 500 and the job failure INTERNAL: 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_FAILED can pass on a retry if the host was down.