# 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](/docs/es/api-reference/autenticacao) y expórtala en tu terminal:

```bash
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.**

```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="Respuesta"
{
  "video_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 el `video_id`: es lo que identifica el vídeo en todas las llamadas siguientes.

> ¿Quieres recortar un archivo de tu ordenador en vez de una URL? Mira [Enviando un vídeo](/docs/es/api-reference/enviando-video) 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.

```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",
    "timeframe": { "start": 0, "end": 1800 }
  }'
```

```json title="Respuesta 201"
{
  "submission_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`).

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

```json title="Respuesta"
{
  "submission_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

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

```json title="Respuesta"
{
  "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.

```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="Respuesta 202"
{
  "render_id": "7412908490112774",
  "edit_setting_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

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

```json title="Respuesta"
{
  "render_id": "7412908490112774",
  "edit_setting_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

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

```json title="Respuesta"
{
  "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.

**Node.js**

```js showLineNumbers
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.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);
```

**Python**

```python showLineNumbers

API = "https://api.cut.pro/api/v1"
HEADERS = {"X-Api-Key": os.environ["CUTPRO_API_KEY"]}

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["video_id"]})

base = f"/clips/{video['video_id']}/submissions/{submission['submission_id']}"
state = submission
while state["status"] != "completed":
    if state["status"] == "failed":
        raise RuntimeError(state["error_code"])
    time.sleep(15)
    state = call(base)

clips = call(f"{base}/clips")["clips"]
best = max(clips, key=lambda clip: clip["rating"])

render = call(f"{base}/clips/{best['id']}/render", "POST")
download = render["download_url"] if render["from_cache"] else None
while not download:
    time.sleep(10)
    job = call(f"/renders/{render['render_id']}")
    if job["status"] == "completed":
        download = call(f"/renders/{render['render_id']}/download")["url"]
    elif job["status"] not in ("queued", "active"):
        raise RuntimeError(job["status"])

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

## ¿Y ahora?

- [Publica en redes](https://cut.pro/docs/es/api-reference/postagem): Lleva los clips renderizados a TikTok, Instagram, YouTube y más
- [Workspace y créditos](https://cut.pro/docs/es/api-reference/saldo): Cómo se consumen los créditos y cómo consultar el saldo
