Cut.ProDocs
Guias

Erros e limites

A forma única de erro, o que fazer em cada status e como tratar o 429

Todo erro da API, em qualquer rota e em qualquer status, tem o mesmo corpo. Aprendeu a ler um, leu todos.

Resposta 402
{
  "code": "INSUFFICIENT_CREDITS",
  "extra": { "credits_needed": 121, "current_balance": 40 }
}
  • code é um identificador estável, em maiúsculas, de um conjunto fechado. É nele que o seu switch decide.
  • extra só aparece quando existe algo para agir: o que faltou, qual campo reprovou, quais ids foram recusados.
  • Não existe mensagem pronta. O servidor não sabe o idioma de quem usa o seu produto, e texto corrido não dá para tratar em código. Quem escreve a frase é você.

Estado é minúsculo, erro é maiúsculo. status descreve onde algo está (queued, processing, completed, failed); code e error_code descrevem o que deu errado (VIDEO_TOO_LONG, DOWNLOAD_NO_AUDIO).

O que fazer em cada status

StatusO que significaO que fazer
400O corpo da requisição está erradoCorrija o payload. Repetir igual não adianta
401Chave ausente, revogada ou expiradaConfira o header X-Api-Key
402Créditos insuficientesRecarregue, ou leia extra.credits_needed
403O vídeo ou a conta não está acessívelNão há o que repetir
404Não existe nesse workspaceConfira o id e o workspace
409Existe, mas o estado não aceita a operaçãoEspere e tente de novo
410Existiu e expirouSubmeta ou renderize de novo
422Link válido, vídeo que não serveTente outra fonte
429Limite de requisições atingidoEspere o Retry-After
5xxErro nossoTente de novo com backoff

A lista completa de code de cada rota está na referência, resposta por resposta.

Tratando erros no seu código

O padrão que cobre tudo: leia o code, decida pelo status se vale repetir.

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) {
		// O servidor diz quanto esperar no 429. Nos 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 });
}

E aí o seu produto traduz o code para a língua de quem está olhando:

switch (error.code) {
	case "INSUFFICIENT_CREDITS":
		show(`Faltam ${error.extra.credits_needed - error.extra.current_balance} créditos.`);
		break;
	case "VIDEO_TOO_LONG":
		show(`Esse vídeo tem ${error.extra.duration}s e o seu plano aceita até ${error.extra.max_duration}s.`);
		break;
	case "LIVE_STREAM":
		show("A transmissão ainda está no ar. Tente quando ela virar vídeo.");
		break;
	default:
		show("Não conseguimos processar agora. Tente de novo em instantes.");
}

Limites de requisição

600 requisições por minuto, por chave de API, numa janela fixa de 60 segundos. Toda resposta diz onde você está:

HeaderO que traz
X-RateLimit-LimitO teto (600)
X-RateLimit-RemainingQuantas chamadas ainda cabem nesta janela
X-RateLimit-ResetUnix, em segundos, de quando a janela zera

Passou do teto, a resposta é 429 com { "code": "RATE_LIMIT_EXCEEDED" } e o header Retry-After em segundos. Respeite-o: tentar na hora só queima a janela seguinte.

POST /clips/info tem um limite próprio e mais apertado, de 10 por minuto, porque cada chamada vai até a plataforma de origem buscar os metadados. Analise uma vez e guarde o id.

O limite é por chave, não por IP: vários processos seus com a mesma chave dividem a mesma cota, e duas chaves atrás do mesmo IP não atrapalham uma à outra.

Isso cabe no polling?

Cabe, com folga. Acompanhar uma submissão a cada 10 segundos gasta 6 requisições por minuto: dá para ter dezenas de jobs em voo ao mesmo tempo. O que estoura o limite é loop apertado sem espera.

Nesta página