Skip to content

API

Read jobs and clips through the API

Follow a job through its statuses with the Snipri API, read its clips with their scores and download links, and page through every job on the account.

On this page

A job moves through the same steps the Studio shows while it runs. Read it to see where it is, and once it has completed, to get its clips and the links to download them.

A job's status

#
StatusWhat it means
awaiting_uploadMade for a file that has not been started yet: upload the file, then start the job.
queuedWaiting for its turn to be processed, behind any jobs queued before it. A job whose run failed for a reason that may clear, such as a host that did not answer, comes back here before it runs again.
transcribingThe speech is being written out, word by word, with the time each word is said.
selectingThe moments are being chosen and scored.
renderingThe clips are being framed, captioned and made.
completedDone. Its clips are ready; none at all means nothing was worth clipping, and nothing was counted.
failedStopped before it gave clips. Its error says why, and nothing was counted.

A job takes minutes rather than seconds, so reading it about every half minute is plenty, and a webhook saves the reads altogether. How long a job takes says what decides the wait.

Read one job

#
Request
curl https://www.snipri.com/api/v1/jobs/cmhj2b9xk0003l708s4f1z9qa \
  -H "Authorization: Bearer $SNIPRI_API_KEY"
Answer
{
  "job": {
    "id": "cmhj2b9xk0003l708s4f1z9qa",
    "status": "completed",
    "name": "episode-12",
    "origin": "api",
    "source": {
      "type": "url",
      "url": "https://example.com/episode-12.mp4"
    },
    "durationSec": 3542.5,
    "videos": 1,
    "error": null,
    "createdAt": "2026-11-02T18:00:00.000Z",
    "completedAt": "2026-11-02T18:24:10.000Z",
    "clips": [
      {
        "id": "cmhj2kq4e0007l708u2m3c8vd",
        "index": 0,
        "part": 0,
        "title": "Launch week, honestly",
        "hook": "Nobody tells you this about launch week",
        "reason": "A clear question and a complete answer, and the last line lands without anything said before it.",
        "scores": {
          "hook": 8,
          "payoff": 8,
          "standalone": 9,
          "arc": 7,
          "quotability": 7
        },
        "startSec": 312.4,
        "endSec": 349.9,
        "durationSec": 37.5,
        "videoUrl": "https://...",
        "thumbnailUrl": "https://...",
        "urlsExpireAt": "2026-11-02T19:25:10.000Z"
      }
    ]
  }
}
FieldWhat it holds
idThe job's id, which every other request about it names.
statusWhere the job is, from the list above.
nameIts name in My clips, or null.
originapi for a job made with a key, studio for one started in the Studio.
sourcetype url, with the link, or type upload.
durationSecThe video's length in seconds once it is known, or null.
videosWhat the job holds against your plan while it runs, what it counted once it completed with clips, and 0 for a job that failed, found nothing or was never started.
errornull, or on a failed job its kind, title and message: the title and sentence the Studio shows.
createdAt, completedAtWhen it was made, and when it completed or null.
clipsOn one job and in a webhook: its clips, in order.
clipCountIn the list of jobs, in place of clips: how many it gave.

Its clips

#
FieldWhat it holds
idThe clip's id.
indexIts place among the job's clips, from 0.
part0 for the clip as Snipri made it, and 1 and up for the pieces a split in the editor adds.
titleIts title in My clips.
hookThe line it opens on, or null on clips made before Snipri wrote one.
reasonWhy the moment was kept, or null on older clips.
scoresThe 5 scores it was kept on, from 1 to 10 each: hook, payoff, standalone, arc and quotability. null on older clips.
startSec, endSec, durationSecWhere it starts and ends in the video, and how long it runs, in seconds.
videoUrlThe finished MP4, with its captions burned in and any edit made since in the editor.
thumbnailUrlIts cover picture.
urlsExpireAtWhen the two links stop working, an hour after the answer.

videoUrl and thumbnailUrl stay valid for an hour, and urlsExpireAt says until when. Read the job again for fresh ones whenever you need them.

Clips come in the order My clips shows them. A clip split in the editor is listed as its pieces, which share an index and differ in part. See why a clip was chosen explains the scores and the reason.

A job that found nothing

#

A job can complete with no clips when no moment in the video was strong enough, and then it counts nothing. Its near-misses, the moments that came closest, wait in My clips, where one can be made into a clip. That clip is in the job's clips the next time you read it, and When a video comes back with no clips says what making one counts.

Every job on the account

#

The list holds 20 jobs a page, or as many as limit asks for, from 1 to 100. Each job carries clipCount in place of its clips, and jobs started in the Studio are listed too, with origin studio.

Request
curl "https://www.snipri.com/api/v1/jobs?limit=50" \
  -H "Authorization: Bearer $SNIPRI_API_KEY"
Answer
{
  "jobs": [
    {
      "id": "cmhj2b9xk0003l708s4f1z9qa",
      "status": "completed",
      "name": "episode-12",
      "origin": "api",
      "source": {
        "type": "url",
        "url": "https://example.com/episode-12.mp4"
      },
      "durationSec": 3542.5,
      "videos": 1,
      "error": null,
      "createdAt": "2026-11-02T18:00:00.000Z",
      "completedAt": "2026-11-02T18:24:10.000Z",
      "clipCount": 1
    }
  ],
  "nextCursor": "cmhj2b9xk0003l708s4f1z9qa"
}

When there are more jobs, nextCursor is the id to send as cursor for the next page, as in https://www.snipri.com/api/v1/jobs?limit=50&cursor=cmhj2b9xk0003l708s4f1z9qa. On the last page it is null.

A job deleted in My clips is gone from the API too: the list leaves it out, and reading it answers NOT_FOUND.

A job that stops moving

#

Reading a job is also what fails one that has stopped moving, by the same allowances the Studio uses:

A job whose progress has not moved for 30 minutes is marked as failed. While it waits its turn in the queue it has 3 hours, and while it renders 90 minutes. A failed job is not counted.

When the job was made through the API, failing it this way sends job.failed to your webhook, as any other failure does.