Cut.ProDocs
Guías

Errores y límites

La forma única de error, qué hacer en cada estado y cómo tratar el 429

Todo error de la API, en cualquier ruta y en cualquier estado, tiene el mismo cuerpo. Si aprendes a leer uno, los has leído todos.

Respuesta 402
{
  "code": "INSUFFICIENT_CREDITS",
  "extra": { "credits_needed": 121, "current_balance": 40 }
}
  • code es un identificador estable, en mayúsculas, de un conjunto cerrado. Es sobre él que decide tu switch.
  • extra solo aparece cuando hay algo que hacer: qué faltó, qué campo no pasó, qué ids se rechazaron.
  • No hay mensaje listo. El servidor no sabe el idioma de quien usa tu producto, y el texto corrido no se puede tratar en código. La frase la escribes tú.

El estado va en minúsculas, el error en mayúsculas. status dice dónde está algo (queued, processing, completed, failed); code y error_code dicen qué salió mal (VIDEO_TOO_LONG, DOWNLOAD_NO_AUDIO).

Qué hacer en cada estado

EstadoQué significaQué hacer
400El cuerpo de la petición está malCorrige el payload. Repetirlo igual no sirve
401Clave ausente, revocada o caducadaRevisa la cabecera X-Api-Key
402Créditos insuficientesRecarga, o lee extra.credits_needed
403El vídeo o la cuenta no está accesibleNo hay nada que repetir
404No existe en este workspaceRevisa el id y el workspace
409Existe, pero su estado no acepta la operaciónEspera y vuelve a intentar
410Existió y caducóVuelve a enviar o a renderizar
422Enlace válido, vídeo que no sirvePrueba otra fuente
429Límite de peticiones alcanzadoEspera el Retry-After
5xxError nuestroReintenta con backoff

La lista completa de code de cada ruta está en la referencia, respuesta por respuesta.

Tratando errores en tu código

El patrón que lo cubre todo: lee el code y deja que el estado decida si vale la pena reintentar.

const RETRIABLE = new Set([429, 500, 502, 503, 504]);

async function call(path, init = {}, attempt = 1) {
	const response = await fetch(`https://api.cut.pro/api/v1${path}`, {
		...init,
		headers: { "X-Api-Key": process.env.CUTPRO_API_KEY, "Content-Type": "application/json" },
	});

	if (response.ok) return response.json();

	const body = await response.json();

	if (RETRIABLE.has(response.status) && attempt <= 5) {
		// El servidor dice cuánto esperar en el 429. En los 5xx, backoff exponencial.
		const retryAfter = Number(response.headers.get("retry-after"));
		const wait = retryAfter > 0 ? retryAfter : 2 ** attempt;
		await new Promise((resolve) => setTimeout(resolve, wait * 1000));
		return call(path, init, attempt + 1);
	}

	throw Object.assign(new Error(body.code), { code: body.code, extra: body.extra, status: response.status });
}

Y entonces tu producto traduce el code al idioma de quien está mirando:

switch (error.code) {
	case "INSUFFICIENT_CREDITS":
		show(`Te faltan ${error.extra.credits_needed - error.extra.current_balance} créditos.`);
		break;
	case "VIDEO_TOO_LONG":
		show(`Ese vídeo dura ${error.extra.duration}s y tu plan acepta hasta ${error.extra.max_duration}s.`);
		break;
	case "LIVE_STREAM":
		show("La transmisión sigue en directo. Inténtalo cuando pase a ser vídeo.");
		break;
	default:
		show("No hemos podido procesarlo ahora. Inténtalo de nuevo en un momento.");
}

Límites de peticiones

600 peticiones por minuto, por clave de API, en una ventana fija de 60 segundos. Cada respuesta dice dónde estás:

CabeceraQué trae
X-RateLimit-LimitEl techo (600)
X-RateLimit-RemainingCuántas llamadas quedan en esta ventana
X-RateLimit-ResetUnix, en segundos, de cuándo se reinicia la ventana

Al pasar del techo, la respuesta es 429 con { "code": "RATE_LIMIT_EXCEEDED" } y la cabecera Retry-After en segundos. Respétala: reintentar al instante solo quema la ventana siguiente.

POST /clips/info tiene su propio límite, más estrecho, de 10 por minuto, porque cada llamada va hasta la plataforma de origen a buscar los metadatos. Analiza una vez y guarda el id.

El límite es por clave, no por IP: varios procesos tuyos con la misma clave comparten la misma cuota, y dos claves detrás de la misma IP no se estorban.

¿Cabe el polling?

De sobra. Seguir una tarea cada 10 segundos gasta 6 peticiones por minuto, así que puedes tener decenas de trabajos en marcha. Lo que revienta el límite es un bucle sin espera.

En esta página