Quickstart: tu primer clip
Del enlace del vídeo al MP4 renderizado, con peticiones reales
Siete peticiones separan un enlace de YouTube de un clip vertical renderizado. Esta guía recorre las siete, en orden, con la respuesta de cada una.
Antes de empezar, genera una clave de API y expórtala en tu terminal:
export CUTPRO_API_KEY="tu_clave"Todos los ejemplos usan la URL base https://api.cut.pro/api/v1 y envían la clave en la cabecera X-Api-Key. Si tu clave cubre varios workspaces, añade también X-Workspace-Id.
1. Analiza el vídeo
POST /clips/info lee los metadatos del enlace y calcula el coste. Analizar no consume créditos.
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" }'{
"id": "7412908365112823",
"title": "Entrevista completa: 2 horas sobre carrera",
"author": "Canal de ejemplo",
"platform": "youtube",
"duration": 7245,
"credits_cost": 121,
"current_balance": 480,
"credits_unlimited": false,
"force_watermark": false
}Guarda ese id: es el video_id de todas las llamadas siguientes.
¿Quieres recortar un archivo de tu ordenador en vez de una URL? Mira Enviando un vídeo para el flujo de subida.
2. Envíalo al recorte
POST /clips crea el envío. Los créditos se cobran aquí, por el importe que mostró el paso anterior.
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 }
}'{
"id": "7412908371004912",
"video_id": "7412908365112823",
"status": "queued",
"credits_charged": 30
}El timeframe es opcional: omítelo para procesar el vídeo entero, o redúcelo a un tramo (en segundos) para gastar menos. Arriba, la primera media hora costó 30 créditos en vez de 121.
strategy_id, template_id y source_language (auto, en, pt) también son opcionales. Lista tus plantillas con GET /templates para obtener los IDs.
3. Consulta hasta que termine
Haz polling del envío cada 10 o 15 segundos. El status pasa por queued, downloading, transcribing, video_analysis, analyzing y finalizing hasta llegar a completed (o failed).
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912 \
-H "X-Api-Key: $CUTPRO_API_KEY"{
"id": "7412908371004912",
"video_id": "7412908365112823",
"status": "analyzing",
"error_code": null,
"clips_count": 0,
"queue_position": 2,
"estimated_time": 340
}Mientras el vídeo espera en la cola, queue_position y estimated_time (en segundos) dicen cuánto falta. Cuando el status pasa a completed, clips_count trae cuántos clips generó la IA.
4. Recupera los clips generados
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips \
-H "X-Api-Key: $CUTPRO_API_KEY"{
"clips": [
{
"id": "7412908412887301",
"title": "El error que le costó su primera empresa",
"rating": 9.2,
"start_time": 412.5,
"end_time": 461.8,
"language": "es",
"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 }
}El rating es la nota de la IA de 0 a 10: cuanto más alta, más potencial tiene el corte. Ordena por ella para quedarte con los mejores primero.
5. Renderiza un clip
POST .../render genera el MP4 final. Para aplicar antes uno de tus estilos, llama a POST .../apply_template en el envío.
curl -X POST \
https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips/7412908412887301/render \
-H "X-Api-Key: $CUTPRO_API_KEY"{
"id": "7412908490112774",
"edit_id": "7412908490112775",
"status": "queued",
"output_resolution": "1080p",
"has_watermark": false,
"from_cache": false,
"download_url": null
}Cuando from_cache llega como true, la respuesta es un 200 con el download_url ya rellenado: ese clip ya se había renderizado con la misma configuración y puedes saltarte los dos pasos siguientes.
6. Consulta el render
curl https://api.cut.pro/api/v1/renders/7412908490112774 \
-H "X-Api-Key: $CUTPRO_API_KEY"{
"id": "7412908490112774",
"edit_id": "7412908490112775",
"status": "active",
"progress": 64,
"output_resolution": "1080p"
}El status pasa por queued, active y completed, y progress va de 0 a 100.
7. Descarga el MP4
curl https://api.cut.pro/api/v1/renders/7412908490112774/download \
-H "X-Api-Key: $CUTPRO_API_KEY"{
"url": "https://media.cut.pro/render/7412908490112774.mp4?signature=...",
"filename": "el-error-que-le-costo-su-primera-empresa.mp4"
}La url está firmada y vale una hora. Descarga el archivo dentro de ese plazo o pide otra.
El flujo entero en un archivo
Los siete pasos encadenados, con el polling ya resuelto. Cambia la URL del vídeo y ejecútalo.
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} créditos`);
const submission = await call("/clips", {
method: "POST",
body: JSON.stringify({ video_id: video.id }),
});
const base = `/clips/${video.id}/submissions/${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.id}`);
if (job.status !== "completed") {
if (job.status === "queued" || job.status === "active") continue;
throw new Error(job.status);
}
download = (await call(`/renders/${render.id}/download`)).url;
}
console.log(best.title, download);