REST API & Streaming Pipeline v1.0

Documentação da API Vidora

O Vidora Core é uma infraestrutura de alto desempenho para processamento e streaming de vídeos em nuvem. Conecte seu backend para enviar payloads de vídeo e receber automaticamente streams adaptativos HLS multi-resolução, arquivos otimizados MP4/WebM e faixas de áudio isoladas com altíssima velocidade e máxima eficiência.

flash_on Micro-Chunking

Processamento em chunks concorrentes com agregação contínua.

verified Multi-Bitrate HLS

De 240p a 4K com master playlist `.m3u8` compatível com Shaka Player, Hls.js e players nativos.

security Chaves Seguras

Autenticação por token `vd_live_...` e `vd_test_...` com hash SHA-256 no banco.

dns Ambientes & Base URLs

Todas as chamadas à API são realizadas via HTTPS utilizando formato JSON no corpo das requisições e respostas.

Produção https://api.vidora.io
Desenvolvimento Local http://localhost:8080

vpn_key Autenticação por Chave de API

Gerar Chave no Painel open_in_new

Para autenticar requisições originadas do seu backend (Node.js, Python, Go, PHP, etc.), envie sua chave de API através do cabeçalho X-API-Key ou do cabeçalho padrão Authorization: Bearer <chave>.

Live Key vd_live_...

Utilizada em produção. Debita créditos reais de processamento e armazena saídas no storage definitivo.

Test Key vd_test_...

Ambiente sandbox / homologação para testes automatizados e integração de novos endpoints.

Cabeçalhos Aceitos:
X-API-Key: vd_live_3f263a64e1aab91c3072d93dc832940e30aea53f78c5340b
// ou alternativamente via Bearer:
Authorization: Bearer vd_live_3f263a64e1aab91c3072d93dc832940e30aea53f78c5340b

Ciclo de Vida do Vídeo (Multipart Flow)

O upload é otimizado para lidar com arquivos grandes de centenas de gigabytes sem sobrecarregar a memória do seu servidor.

POST /api/v1/uploads/start
Passo 1 de 3

Inicia a transação de upload no Vidora, calcula a partição de chunks e gera URLs pré-assinadas do S3 diretamente para cada parte.

Campo Tipo Obrigatório Descrição
file_name string Sim Nome do arquivo com extensão válida (.mp4, .mov, .mkv, .avi, .webm).
file_size_bytes integer Sim Tamanho total do arquivo original em bytes.
chunks_number integer Sim Quantidade de partes multipart (mínimo 1). Chunks de 5 MB a 25 MB recomendados.
output_mode string Não Modo de saída: "hls" (padrão) ou "standalone".
priority string Não Prioridade da fila: "low", "normal" (padrão) ou "high".
webhook_url string (URL) Não Endpoint HTTP POST para notificação quando o job concluir.
Exemplo de Requisição:
curl -X POST http://localhost:8080/api/v1/uploads/start \
  -H "X-API-Key: vd_live_seu_token_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "video_institucional.mp4",
    "file_size_bytes": 52428800,
    "chunks_number": 5,
    "output_mode": "hls",
    "priority": "high",
    "webhook_url": "https://meubackend.com/webhooks/vidora"
  }'
Resposta (201 Created):
{
  "job_id": "job_e6b2184a-9a99-4c12-b9a3-5c2f3089d14a",
  "upload_id": "mp_9b4e10c7-01",
  "file_key": "job_e6b2184a/video_institucional.mp4",
  "upload_urls": [
    {
      "part_number": 1,
      "url": "http://localhost:8080/mock-storage/quarantine/upload?part=1..."
    },
    {
      "part_number": 2,
      "url": "http://localhost:8080/mock-storage/quarantine/upload?part=2..."
    }
  ]
}
PUT <part_presigned_url>
Passo 2 de 3

Envie os bytes binários de cada parte diretamente para cada URL contida em upload_urls via método HTTP PUT. Capture o cabeçalho ETag retornado pelo Storage em cada requisição.

# Envio de uma parte específica via cURL:
curl -X PUT --data-binary @chunk_001.part \
  "http://localhost:8080/mock-storage/quarantine/upload?part=1..."

# O servidor responderá 200 OK com o header:
# ETag: "a4f83b12c890d"
POST /api/v1/uploads/finish
Passo 3 de 3

Consolida o upload multipart no Storage, valida as somas ETags e inicia o processamento distribuído no pipeline do Vidora Core.

curl -X POST http://localhost:8080/api/v1/uploads/finish \
  -H "X-API-Key: vd_live_seu_token_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "job_id": "job_e6b2184a-9a99-4c12-b9a3-5c2f3089d14a",
    "upload_id": "mp_9b4e10c7-01",
    "file_key": "job_e6b2184a/video_institucional.mp4",
    "parts": [
      { "part_number": 1, "etag": "\"a4f83b12c890d\"" },
      { "part_number": 2, "etag": "\"b7194c25f012e\"" }
    ]
  }'
GET /api/v1/jobs/{job_id}
Polling & Playlists

Consulta o progresso em tempo real, status (uploading, processing, completed, failed) e os links finais HLS multi-bitrate assim que a transcodificação for concluída.

curl -X GET http://localhost:8080/api/v1/jobs/job_e6b2184a-9a99-4c12-b9a3-5c2f3089d14a \
  -H "X-API-Key: vd_live_seu_token_aqui"
Resposta Completa (Status: completed):
{
  "job_id": "job_e6b2184a-9a99-4c12-b9a3-5c2f3089d14a",
  "status": "completed",
  "progress_percent": 100,
  "file_name": "video_institucional.mp4",
  "priority": "high",
  "retention_remaining_seconds": 86340,
  "outputs": {
    "output_mode": "hls",
    "hls": {
      "master_playlist_url": "http://localhost:8080/mock-storage/processed/job_e6b2184a/master.m3u8",
      "renditions": [
        { "resolution": "1080p", "bitrate_kbps": 4500, "url": ".../1080p.m3u8" },
        { "resolution": "720p",  "bitrate_kbps": 2200, "url": ".../720p.m3u8" },
        { "resolution": "480p",  "bitrate_kbps": 800,  "url": ".../480p.m3u8" }
      ]
    },
    "audio": {
      "separated": true,
      "audio_track_url": "http://localhost:8080/mock-storage/processed/job_e6b2184a/audio.aac"
    },
    "preview_url": "http://localhost:8080/mock-storage/processed/job_e6b2184a/preview.m3u8"
  }
}

Gerenciamento de Jobs

Endpoints para auditoria, contabilidade de vídeos e exclusão de arquivos.

GET /api/v1/jobs

Retorna a lista de todos os jobs registrados, ordenados do mais recente para o mais antigo, com temporizador de retenção S3.

DELETE /api/v1/jobs/{job_id}

Remove o registro do banco de dados e purga permanentemente todos os arquivos HLS, chunks e vídeos brutos do Storage S3.

curl -X DELETE http://localhost:8080/api/v1/jobs/job_123 -H "X-API-Key: vd_live_..."

webhook Webhooks & Notificações de Eventos

Em vez de realizar polling contínuo via HTTP, configure uma URL de Webhook no payload de /start ou no painel de configurações para receber um disparo automático HTTP POST com o resultado final do processamento.

Payload de Notificação Recebido no seu Servidor:
{
  "event": "job.completed",
  "job_id": "job_e6b2184a-9a99-4c12-b9a3-5c2f3089d14a",
  "status": "completed",
  "file_name": "video_institucional.mp4",
  "completed_at": "2026-09-27T18:45:00Z",
  "outputs": {
    "output_mode": "hls",
    "master_playlist_url": "http://localhost:8080/mock-storage/processed/job_e6b2184a/master.m3u8"
  }
}
Validação de Assinatura (HMAC SHA-256):

Todas as chamadas de webhook incluem o cabeçalho X-Vidora-Signature. Use seu Secret disponível nas configurações para autenticar a integridade do payload antes de atualizar seu banco de dados.

code Exemplo Completo de Integração de Backend

Veja como um servidor em Node.js ou script em Python transcodifica um vídeo completo com poucas linhas de código:

import fs from 'fs';

const API_KEY = process.env.VIDORA_API_KEY || 'vd_live_...';
const BASE_URL = 'http://localhost:8080';

async function transcodeVideo(filePath) {
  const stats = fs.statSync(filePath);
  const CHUNK_SIZE = 5 * 1024 * 1024; // 5 MB
  const totalChunks = Math.ceil(stats.size / CHUNK_SIZE);

  // 1. Iniciar upload no Vidora
  const startRes = await fetch(`${BASE_URL}/api/v1/uploads/start`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      file_name: 'video.mp4',
      file_size_bytes: stats.size,
      chunks_number: totalChunks,
      output_mode: 'hls',
      priority: 'high'
    })
  });
  const { job_id, upload_id, file_key, upload_urls } = await startRes.json();

  // 2. Upload paralelo dos chunks diretamente para as URLs presign
  const fd = fs.openSync(filePath, 'r');
  const uploadedParts = [];

  for (const part of upload_urls) {
    const buffer = Buffer.alloc(CHUNK_SIZE);
    const bytesRead = fs.readSync(fd, buffer, 0, CHUNK_SIZE, (part.part_number - 1) * CHUNK_SIZE);
    const chunkData = buffer.subarray(0, bytesRead);

    const putRes = await fetch(part.url, { method: 'PUT', body: chunkData });
    const etag = putRes.headers.get('etag') || `"${part.part_number}"`;
    uploadedParts.push({ part_number: part.part_number, etag });
  }
  fs.closeSync(fd);

  // 3. Finalizar upload e enfileirar para workers
  const finishRes = await fetch(`${BASE_URL}/api/v1/uploads/finish`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      job_id,
      upload_id,
      file_key,
      parts: uploadedParts
    })
  });

  console.log(`Job ${job_id} enviado para transcodificação com sucesso!`);
}

error_outline Códigos de Retorno & Tratamento de Erros

Código Significado Causa Comum / Solução
200 OK / 201 Created Sucesso A operação solicitada foi realizada com sucesso.
400 Bad Request Dados Inválidos Extensão de arquivo não permitida, chunks_number zero ou codec incompatível.
401 Unauthorized Não Autenticado Chave de API ausente, mal formatada ou revogada. Verifique o header X-API-Key.
404 Not Found Job Não Encontrado O job_id especificado não existe ou expirou do período de retenção (24h).
500 Server Error Falha Interna Erro de conexão com o broker RabbitMQ ou com o cluster de Storage S3.
Copiado para a área de transferência!