# Quickstart

> Haz tu primera solicitud y sal con un clip vertical en MP4.

En esta guía verificas la clave con una llamada que no cobra nada, analizas un video, generas los clips y descargas el mejor ya renderizado.

**Vas a necesitar:** una cuenta en Cut.Pro, una clave de API y `curl`. Los ejemplos completos del final usan Node.js 18+ o Python 3.9+.

## 1. Crea la clave

Abre [Claves de API](https://cut.pro/studio/me/api-keys), haz clic en **Nueva clave** y copia el valor. Aparece una sola vez.

```bash
export CUTPRO_API_KEY="pega_tu_clave_aqui"
```

## 2. Verifica la clave

`GET /workspace` no cobra créditos y muestra en qué workspace opera la clave.

```bash
curl https://api.cut.pro/api/v1/workspace \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "id": "7401220118845503",
  "name": "Estudio Ana",
  "is_personal": true,
  "status": "active",
  "role": "admin",
  "plan_name": "Pro",
  "plan_is_free": false,
  "credits": 120,
  "credits_unlimited": false,
  "created_at": "2026-03-02T14:11:09.000Z"
}
```

¿Recibiste `401 UNAUTHORIZED`? La clave es incorrecta o fue revocada. ¿Recibiste `400 MISSING_WORKSPACE_ID`? La clave alcanza más de un workspace: ve [Autenticación](/es/authentication#clave-con-más-de-un-workspace).

## 3. Analiza el video

Analizar es gratis. La respuesta trae el costo del clipping y tu saldo.

```bash
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" }'
```

```json title="200 OK"
{
  "id": "7412908365112823",
  "title": "Rick Astley - Never Gonna Give You Up",
  "platform": "youtube",
  "duration": 213,
  "credits_cost": 4,
  "current_balance": 120
}
```

Guarda el `id`: es el `video_id` de los próximos pasos.

## 4. Genera los clips

> Este es el paso que cobra. El valor de `credits_cost` sale del saldo al instante, y vuelve si cancelas antes de que termine.

```bash
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" }'
```

```json title="201 Created"
{
  "id": "7412908371004912",
  "video_id": "7412908365112823",
  "status": "queued",
  "credits_charged": 4
}
```

## 5. Espera a que termine

Consulta el envío cada 5 a 10 segundos hasta que `status` pase a `completed` o `failed`.

```bash
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912 \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "id": "7412908371004912",
  "video_id": "7412908365112823",
  "status": "completed",
  "error_code": null,
  "clips_count": 9,
  "completed_at": "2026-10-29T18:04:51.000Z"
}
```

## 6. Obtén el mejor clip

Cada clip tiene una nota de 0 a 10. Ordena por ella y pide solo uno.

```bash
curl "https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips?sort=rating&order=desc&limit=1" \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "clips": [
    {
      "id": "7412908412887301",
      "title": "El estribillo que todo el mundo conoce",
      "rating": 9.2,
      "start_time": 42.5,
      "end_time": 71.0,
      "language": "en",
      "has_template_applied": false,
      "edit_id": null
    }
  ],
  "pagination": { "current_page": 1, "total_pages": 9, "total_count": 9, "has_next_page": true, "has_previous_page": false, "limit": 1 }
}
```

## 7. Renderiza y descarga

Pide el render del clip. Sin plantilla, sale con la configuración predeterminada.

```bash
curl -X POST https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips/7412908412887301/render \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="202 Accepted"
{
  "id": "7412908490112774",
  "edit_id": "7412908488820131",
  "status": "queued",
  "output_resolution": "1080p",
  "from_cache": false,
  "download_url": null
}
```

Consulta `GET /renders/7412908490112774` hasta que `status` pase a `completed` y pide el enlace:

```bash
curl https://api.cut.pro/api/v1/renders/7412908490112774/download \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "url": "https://...",
  "filename": "el-estribillo-que-todo-el-mundo-conoce.mp4"
}
```

El enlace vale 1 hora. Listo: ese es tu clip.

## Todo el flujo en un archivo

Los pasos 3 a 7 encadenados, con la espera resuelta. Cambia la URL y ejecuta.

**Node.js**

```js title="quickstart.mjs"
const API = "https://api.cut.pro/api/v1";
const headers = { "X-Api-Key": process.env.CUTPRO_API_KEY, "Content-Type": "application/json" };
const PENDING = ["queued", "active", "waiting_quality"];

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(10);
	state = await call(base);
}

const { clips: [best] } = await call(`${base}/clips?sort=rating&order=desc&limit=1`);
const render = await call(`${base}/clips/${best.id}/render`, { method: "POST" });

let url = render.download_url;
while (!url) {
	await wait(10);
	const job = await call(`/renders/${render.id}`);
	if (job.status === "completed") url = (await call(`/renders/${render.id}/download`)).url;
	else if (!PENDING.includes(job.status)) throw new Error(job.status);
}

console.log(best.title, url);
```

**Python**

```python title="quickstart.py"

API = "https://api.cut.pro/api/v1"
HEADERS = {"X-Api-Key": os.environ["CUTPRO_API_KEY"]}
PENDING = ("queued", "active", "waiting_quality")

def call(path, method="GET", **kwargs):
    response = requests.request(method, f"{API}{path}", headers=HEADERS, **kwargs)
    body = response.json()
    if not response.ok:
        raise RuntimeError(f"{response.status_code} {body.get('code')}")
    return body

video = call("/clips/info", "POST", json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"})
print(f"{video['title']}: {video['credits_cost']} créditos")

submission = call("/clips", "POST", json={"video_id": video["id"]})
base = f"/clips/{video['id']}/submissions/{submission['id']}"

state = submission
while state["status"] != "completed":
    if state["status"] == "failed":
        raise RuntimeError(state["error_code"])
    time.sleep(10)
    state = call(base)

best = call(f"{base}/clips", params={"sort": "rating", "order": "desc", "limit": 1})["clips"][0]
render = call(f"{base}/clips/{best['id']}/render", "POST")

url = render["download_url"]
while not url:
    time.sleep(10)
    job = call(f"/renders/{render['id']}")
    if job["status"] == "completed":
        url = call(f"/renders/{render['id']}/download")["url"]
    elif job["status"] not in PENDING:
        raise RuntimeError(job["status"])

print(best["title"], url)
```

## Ajusta el código

- **Corta solo un tramo:** envía `timeframe: { "start": 600, "end": 1800 }` en `POST /clips` para generar clips del minuto 10 al 30.
- **Aplica tu estilo:** pasa un `template_id` de `GET /templates` en `POST /clips` y todo clip sale con tus subtítulos y tu encuadre.
- **Traduce los subtítulos:** `translate_to: "es"` en `POST /clips` genera los subtítulos en español. Cuesta más que el clipping simple, y `credits_charged` muestra cuánto se cobró.
- **Usa un archivo tuyo:** cambia el paso 3 por la [subida](/es/uploads), que devuelve el mismo `video_id`.

## Próximos pasos

- [Publica el clip](https://cut.pro/docs/es/publishing): Usa el `edit_id` del render para publicar en TikTok, Instagram y YouTube.
- [Clips en detalle](https://cut.pro/docs/es/clipping): Estados del envío, fuente que aún no salió al aire, reintento y cancelación.
- [Errores](https://cut.pro/docs/es/errors): Qué significa cada `code` y qué hacer.
