Envie um arquivo de vídeo
Suba o arquivo direto para o storage, em uma parte ou em várias, e receba o video_id para clipar.
Use o upload quando o vídeo está com você e não num link público. O arquivo vai direto do seu servidor para o storage, por URL assinada, e não passa pela API. No fim você tem um video_id igual ao de POST /clips/info.
Formatos aceitos: .mp4, .mov, .webm e .mkv. O tamanho máximo vem do plano.
Peça a URL de upload
curl -X POST https://api.cut.pro/api/v1/videos/upload \
-H "X-Api-Key: $CUTPRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "file_name": "podcast-ep-42.mp4", "file_size": 734003200, "content_type": "video/mp4" }'{
"mode": "single",
"video_id": "7412911002237764",
"upload_url": "https://...",
"expires_in": 3600
}mode diz como enviar: single (um PUT) ou multipart (várias partes). Arquivo grande demais responde 400 FILE_TOO_LARGE com o teto em extra.max_size.
Envie os bytes
Com mode: "single", um PUT com o mesmo Content-Type que você declarou:
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--upload-file podcast-ep-42.mp4Com mode: "multipart", veja Arquivos grandes.
Registre o vídeo
Depois que o PUT respondeu 200, informe duração, largura e altura:
curl -X POST https://api.cut.pro/api/v1/videos/upload/complete \
-H "X-Api-Key: $CUTPRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_id": "7412911002237764",
"file_name": "podcast-ep-42.mp4",
"duration": 3712,
"width": 1920,
"height": 1080
}'A resposta tem o mesmo formato de POST /clips/info, com credits_cost e current_balance. Mande o id em POST /clips e siga como em Clipe um vídeo.
Arquivos grandes
Quando o arquivo passa do limite de um PUT só, POST /videos/upload responde mode: "multipart":
{
"mode": "multipart",
"video_id": "7412911002237764",
"upload_id": "2~kB1x...",
"part_urls": ["https://...", "https://...", "https://..."],
"part_size": 104857600,
"expires_in": 3600
}- Corte o arquivo em pedaços de
part_sizebytes. Só o último pode ser menor. - Faça um PUT de cada pedaço na URL de mesma posição em
part_urls. A posição 0 é a parte 1. - Guarde o header
ETagde cada resposta. - Feche o upload com as partes em ordem:
curl -X POST https://api.cut.pro/api/v1/videos/upload/multipart/complete \
-H "X-Api-Key: $CUTPRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_id": "7412911002237764",
"upload_id": "2~kB1x...",
"parts": [
{ "part_number": 1, "etag": "\"a54357aff0632cce46d942af68356b38\"" },
{ "part_number": 2, "etag": "\"0c78aef83f66abc1fa1e8477f296d394\"" },
{ "part_number": 3, "etag": "\"acbd18db4cc2f85cedef654fccc4a4d8\"" }
]
}'- Registre com
POST /videos/upload/complete, como no passo 3 acima.
import { open } from "node:fs/promises";
const file = await open("podcast-ep-42.mp4");
const parts = [];
for (const [index, url] of upload.part_urls.entries()) {
const buffer = Buffer.alloc(upload.part_size);
const { bytesRead } = await file.read(buffer, 0, upload.part_size, index * upload.part_size);
const response = await fetch(url, { method: "PUT", body: buffer.subarray(0, bytesRead) });
parts.push({ part_number: index + 1, etag: response.headers.get("ETag") });
}
await file.close();Desistiu no meio? Chame POST /videos/upload/multipart/abort com video_id e upload_id. Sem isso, as partes já enviadas continuam ocupando o storage.
Erros
| Code | Quando |
|---|---|
INVALID_FILE_TYPE | Extensão fora da lista. extra.allowed_extensions traz as aceitas. |
FILE_TOO_LARGE | Passa do teto do plano, informado em extra.max_size. |
FILE_NOT_FOUND | O complete chegou antes do arquivo estar no storage. Confira o PUT. |
VIDEO_TOO_LONG, VIDEO_TOO_SHORT | Duração fora do permitido. extra.duration e extra.max_duration dizem quanto. |