Autenticação

Toda chamada leva a sua chave no header x-api-key. Crie e revogue chaves na página Chaves de API.

curl "{BASE}/api/videos" \
  -H "x-api-key: SUA_CHAVE"

O limite padrão é de 60 chamadas por minuto por chave. As respostas trazem X-RateLimit-Remaining; ao estourar, vem 429 com Retry-After.

Enviar um vídeo

O arquivo vai do seu servidor (ou do navegador do seu usuário) direto para o storage, usando URLs assinadas que a API emite. Ele não passa pela nossa aplicação, o que permite enviar arquivos de vários GB sem prender uma conexão.

1. Criar o vídeo e abrir o envio

POST {BASE}/api/videos
{
  "title": "Aula 01 - Introdução",
  "privacy": "signed",
  "filename": "aula01.mp4",
  "size_bytes": 734003200,
  "content_type": "video/mp4"
}

// resposta
{
  "status": true,
  "video": { "id": 12, "playback_id": "kR7pQm2xVt9bLnCsWd4Hga", ... },
  "upload": {
    "mode": "multipart",
    "part_size": 16777216,
    "total_parts": 44,
    "parts": [ { "part": 1, "url": "https://...", "size": 16777216 }, ... ]
  }
}

2. Enviar cada parte

// as partes podem subir em paralelo; uma que falhe se reenvia sozinha
for (const p of upload.parts) {
  const inicio = (p.part - 1) * upload.part_size;
  const pedaco = arquivo.subarray(inicio, inicio + p.size);
  await fetch(p.url, { method: 'PUT', body: pedaco });
}

3. Fechar o envio

POST {BASE}/api/videos/12/upload/complete
{}

Não precisa informar as partes: nós perguntamos ao storage o que chegou. Se você já tem os ETag de cada PUT em mãos, pode enviá-los em parts e poupar uma consulta.

Envio simples: para arquivos pequenos ou integrações rápidas, existe POST /api/videos/upload com multipart/form-data. Uma chamada só, mas o arquivo passa pela aplicação.
Acompanhar o processamento

Depois do envio, o vídeo entra na fila e é convertido para HLS em várias qualidades. Consulte o vídeo ou espere o webhook.

GET {BASE}/api/videos/12

{
  "video": {
    "status": "processing",
    "processing": { "progress": 42, "stage": "gerando 720p" }
  }
}

Estados: awaiting_uploaduploadingqueuedprocessingready. Em erro, failed com error_message.

Reproduzir

Vídeos public são abertos: o link funciona para qualquer um. Vídeos signed exigem um token que expira, emitido sob demanda.

POST {BASE}/api/videos/12/playback-token
{ "ttl_minutes": 120 }

{
  "token": "eyJwIjoia1I3...",
  "urls": {
    "embed": "{BASE}/embed/kR7pQm2xVt9bLnCsWd4Hga?token=...",
    "hls": "{BASE}/stream/kR7pQm2xVt9bLnCsWd4Hga/master.m3u8?token=..."
  }
}

Embutir o player

<iframe src="{BASE}/embed/kR7pQm2xVt9bLnCsWd4Hga?token=..."
        width="720" height="405" frameborder="0"
        allowfullscreen allow="autoplay; fullscreen; picture-in-picture"></iframe>

Parâmetros aceitos no embed: autoplay=1, muted=1, loop=1 e color=RRGGBB (cor dos controles).

Usar o seu próprio player

A URL hls é um master playlist HLS comum, compatível com hls.js, Video.js, Shaka e o player nativo do Safari e do iOS. Os segmentos são cifrados em AES-128 e a chave é entregue pela própria URL do manifest, então nenhuma configuração extra é necessária no player.

Referência dos endpoints
Webhooks

Configure a URL de destino em Configurações. Enviamos POST com JSON e o header x-alktea-signature (HMAC-SHA256 do corpo, calculado com o seu segredo).

{
  "event": "video.ready",
  "timestamp": "2026-08-31T18:42:10.512Z",
  "data": {
    "video_id": 12,
    "playback_id": "kR7pQm2xVt9bLnCsWd4Hga",
    "title": "Aula 01 - Introdução",
    "duration_seconds": 1834.2,
    "qualities": ["360p", "480p", "720p", "1080p"]
  }
}

Eventos: video.ready e video.failed. Repetimos a entrega até 3 vezes em falha de rede ou erro 5xx; responda 2xx para encerrar.

Códigos de erro

Toda resposta de erro traz errorCode (estável) e message (texto que pode mudar). Decida pelo código.

HTTPerrorCodeQuando acontece