API
Send a video through the API
Make a job from a link or from a file with the Snipri API: the request, the upload links, files sent in parts, starting the job and retrying safely.
On this page
A job starts from a link to a video or from a file you upload. A link takes one request, and the job is queued at once. A file takes a request that makes the job, an upload to the link its answer gives, and a request that starts it. Its bytes go straight to storage and never pass through the API.
From a link
#Send the link as source.url. The links the Studio takes work here too, and Import a video from a link lists them.
curl -X POST https://www.snipri.com/api/v1/jobs \
-H "Authorization: Bearer $SNIPRI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: episode-12" \
-d '{
"source": {
"url": "https://example.com/episode-12.mp4"
},
"clip": {
"genre": "podcast",
"length": "medium"
}
}'A link is queued at once. The answer, with status 201, is the job:
{
"job": {
"id": "cmhj2b9xk0003l708s4f1z9qa",
"status": "queued",
"name": "episode-12",
"origin": "api",
"source": {
"type": "url",
"url": "https://example.com/episode-12.mp4"
},
"durationSec": null,
"videos": 1,
"error": null,
"createdAt": "2026-11-02T18:00:00.000Z",
"completedAt": null,
"clipCount": 0
}
}A video from a link can run up to 1 hour on every plan; a longer one fails, and its error says to send the file instead. While it runs, a job from a link holds one video, because its length is unknown until Snipri has it.
A YouTube link works like any other, as long as it points at one public video or Short: not a playlist or a channel, and not a private, members-only or live video.
From a file
#Make the job
#Send the file's size in bytes as source.upload.sizeBytes, and its name as source.upload.fileName to name the job after it.
curl -X POST https://www.snipri.com/api/v1/jobs \
-H "Authorization: Bearer $SNIPRI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": {
"upload": {
"sizeBytes": 734003200,
"fileName": "episode-12.mp4"
}
}
}'The answer, with status 201, is the job, waiting for its file, and where to put the file. A file up to 4 GB goes up in one PUT:
{
"job": {
"id": "cmhj2b9xk0003l708s4f1z9qa",
"status": "awaiting_upload",
"name": "episode-12",
"origin": "api",
"source": {
"type": "upload"
},
"durationSec": null,
"videos": 0,
"error": null,
"createdAt": "2026-11-02T18:00:00.000Z",
"completedAt": null,
"clipCount": 0
},
"upload": {
"method": "PUT",
"multipart": false,
"url": "https://...",
"headers": {
"Content-Type": "video/mp4"
},
"expiresAt": "2026-11-03T00:00:00.000Z"
}
}Upload the file
#Put the job's id from that answer in JOB_ID and its upload.url in UPLOAD_URL, then send the file:
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--upload-file episode-12.mp4Send the Content-Type the answer names with it. The type is part of the link's signature, and an upload without it is refused.
Start the job
#Once the upload has finished, start the job. It is queued from that moment, and the videos it may count are held for it.
curl -X POST https://www.snipri.com/api/v1/jobs/$JOB_ID/start \
-H "Authorization: Bearer $SNIPRI_API_KEY"The answer is the job, queued. Starting a job that is already queued answers with the job as it is and changes nothing, so a start whose answer never came can be sent again.
The upload links stay valid for 6 hours, and expiresAt says until when. A job still waiting for its file 6 hours after it was made is failed, and counts nothing.
The largest file a job takes is 3 GB on Starter and 10 GB on Pro and Scale. A larger one is refused before any of it is sent, with FILE_TOO_LARGE.
Large files
#A file over 4 GB goes up in parts of 128 MB, the last part holding whatever is left. The answer's upload has a link for every part, numbered from 1; these are the first two:
{
"upload": {
"method": "PUT",
"multipart": true,
"uploadId": "...",
"partSize": 134217728,
"parts": [
{
"partNumber": 1,
"url": "https://..."
},
{
"partNumber": 2,
"url": "https://..."
}
],
"expiresAt": "2026-11-03T00:00:00.000Z"
}
}PUT each part to its link and keep the ETag header each of those answers carries. Then start the job with the upload's id and every part's ETag:
curl -X POST https://www.snipri.com/api/v1/jobs/$JOB_ID/start \
-H "Authorization: Bearer $SNIPRI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"uploadId": "...",
"parts": [
{
"partNumber": 1,
"etag": "\"9b2cf535f27731c974343645a3985328\""
},
{
"partNumber": 2,
"etag": "\"6f1ed002ab5595859014ebf0951522d9\""
}
]
}'A part that fails can be sent again on its own, to the same link, while the links are valid. Upload a video has more on the files Snipri reads.
Retry without making a second job
#A create whose answer never arrived may still have made the job, and sending it again would make another. An Idempotency-Key header makes the retry safe.
- Send an Idempotency-Key header with a create: up to 255 printable ASCII characters, with no spaces.
- The same key with the same body answers with the job the first request made, with status 200, and with fresh upload links while its file has not arrived. The order of the fields in the body does not matter.
- The same key with a different body is refused with IDEMPOTENCY_KEY_REUSED.
- Keys belong to one account, so two accounts can use the same one.
A key that names the video, such as the episode's own id, also keeps a video sent twice from becoming a second job.