Skip to content

Quickstart: your first clip

Seven requests stand between a YouTube link and a rendered vertical clip. This guide walks through all seven, in order, with the response of each one.

Before you start, create an API key and export it in your terminal:

Terminal window
export CUTPRO_API_KEY="your_key"

POST /clips/info reads the link metadata and works out the cost. Analyzing does not spend credits.

Terminal window
curl -X POST https://api.cut.pro/api/v1/clips/info \
-H "X-Api-Key: $CUTPRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }'
Response
{
"video_id": "7412908365112823",
"title": "Full interview: 2 hours on building a career",
"author": "Example Channel",
"platform": "youtube",
"duration": 7245,
"credits_cost": 121,
"current_balance": 480,
"credits_unlimited": false,
"force_watermark": false
}

Keep the video_id: it identifies the video in every call that follows.

POST /clips creates the submission. Credits are charged here, at the amount the previous step showed.

Terminal window
curl -X POST https://api.cut.pro/api/v1/clips \
-H "X-Api-Key: $CUTPRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_id": "7412908365112823",
"timeframe": { "start": 0, "end": 1800 }
}'
Response 201
{
"submission_id": "7412908371004912",
"video_id": "7412908365112823",
"status": "queued",
"credits_charged": 30
}

The timeframe is optional: omit it to process the whole video, or narrow it to a stretch (in seconds) to spend less. Above, the first half hour cost 30 credits instead of 121.

Poll the submission every 10 or 15 seconds. The status moves through queued, downloading, transcribing, video_analysis, analyzing and finalizing until it reaches completed (or failed).

Terminal window
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912 \
-H "X-Api-Key: $CUTPRO_API_KEY"
Response
{
"submission_id": "7412908371004912",
"video_id": "7412908365112823",
"status": "analyzing",
"error_code": null,
"clips_count": 0,
"queue_position": 2,
"estimated_time": 340
}

While the video waits in line, queue_position and estimated_time (in seconds) tell you how much is left. Once status turns completed, clips_count carries how many clips the AI produced.

Terminal window
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips \
-H "X-Api-Key: $CUTPRO_API_KEY"
Response
{
"clips": [
{
"id": "7412908412887301",
"title": "The mistake that cost him his first company",
"rating": 9.2,
"start_time": 412.5,
"end_time": 461.8,
"language": "en",
"play_url": "https://media.cut.pro/preview/...",
"download_url": "https://media.cut.pro/clip/...",
"has_template_applied": false
}
],
"pagination": { "current_page": 1, "total_pages": 1, "total_count": 12, "has_next_page": false }
}

The rating is the AI score from 0 to 10: the higher it is, the more potential the clip has. Sort by it to take the best ones first.

POST .../render produces the final MP4. To apply one of your looks first, call POST .../apply_template on the submission.

Terminal window
curl -X POST \
https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips/7412908412887301/render \
-H "X-Api-Key: $CUTPRO_API_KEY"
Response 202
{
"render_id": "7412908490112774",
"edit_setting_id": "7412908490112775",
"status": "queued",
"output_resolution": "1080p",
"has_watermark": false,
"from_cache": false,
"download_url": null
}

When from_cache comes back true, the response is a 200 with download_url already filled in: that clip had been rendered with the same settings before, and you can skip the next two steps.

Terminal window
curl https://api.cut.pro/api/v1/renders/7412908490112774 \
-H "X-Api-Key: $CUTPRO_API_KEY"
Response
{
"render_id": "7412908490112774",
"edit_setting_id": "7412908490112775",
"status": "active",
"progress": 64,
"output_resolution": "1080p"
}

The status moves through queued, active and completed, and progress runs from 0 to 100.

Terminal window
curl https://api.cut.pro/api/v1/renders/7412908490112774/download \
-H "X-Api-Key: $CUTPRO_API_KEY"
Response
{
"url": "https://media.cut.pro/render/7412908490112774.mp4?signature=...",
"filename": "the-mistake-that-cost-him-his-first-company.mp4"
}

The url is signed and valid for one hour. Download the file within that window or ask for another one.

The seven steps chained together, polling included. Swap the video URL and run it.

const API = "https://api.cut.pro/api/v1";
const headers = {
"X-Api-Key": process.env.CUTPRO_API_KEY,
"Content-Type": "application/json",
};
async function call(path, init) {
const response = await fetch(`${API}${path}`, { ...init, headers });
const body = await response.json();
if (!response.ok) throw new Error(`${response.status} ${body.code}`);
return body;
}
const wait = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));
const video = await call("/clips/info", {
method: "POST",
body: JSON.stringify({ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }),
});
console.log(`${video.title}: ${video.credits_cost} credits`);
const submission = await call("/clips", {
method: "POST",
body: JSON.stringify({ video_id: video.video_id }),
});
const base = `/clips/${video.video_id}/submissions/${submission.submission_id}`;
let state = submission;
while (state.status !== "completed") {
if (state.status === "failed") throw new Error(state.error_code);
await wait(15);
state = await call(base);
}
const { clips } = await call(`${base}/clips`);
const best = [...clips].sort((a, b) => b.rating - a.rating)[0];
const render = await call(`${base}/clips/${best.id}/render`, { method: "POST" });
let download = render.from_cache ? render.download_url : null;
while (!download) {
await wait(10);
const job = await call(`/renders/${render.render_id}`);
if (job.status !== "completed") {
if (job.status === "queued" || job.status === "active") continue;
throw new Error(job.status);
}
download = (await call(`/renders/${render.render_id}/download`)).url;
}
console.log(best.title, download);