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.
Processamento em chunks concorrentes com agregação contínua.
De 240p a 4K com master playlist `.m3u8` compatível com Shaka Player, Hls.js e players nativos.
Autenticação por token `vd_live_...` e `vd_test_...` com hash SHA-256 no banco.
Ambientes & Base URLs
Todas as chamadas à API são realizadas via HTTPS utilizando formato JSON no corpo das requisições e respostas.
Autenticação por Chave de API
Gerar Chave no Painel
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>.
Utilizada em produção. Debita créditos reais de processamento e armazena saídas no storage definitivo.
Ambiente sandbox / homologação para testes automatizados e integração de novos endpoints.
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.
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. |
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"
}'
import requests
url = "http://localhost:8080/api/v1/uploads/start"
headers = {
"X-API-Key": "vd_live_seu_token_aqui",
"Content-Type": "application/json"
}
payload = {
"file_name": "video_institucional.mp4",
"file_size_bytes": 52428800,
"chunks_number": 5,
"output_mode": "hls",
"priority": "high"
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
print("Job criado:", data["job_id"])
const res = await fetch('http://localhost:8080/api/v1/uploads/start', {
method: 'POST',
headers: {
'X-API-Key': 'vd_live_seu_token_aqui',
'Content-Type': 'application/json'
},
body: JSON.stringify({
file_name: 'video_institucional.mp4',
file_size_bytes: 52428800,
chunks_number: 5,
output_mode: 'hls',
priority: 'high'
})
});
const { job_id, upload_id, upload_urls } = await res.json();
{
"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..."
}
]
}
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"
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\"" }
]
}'
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"
{
"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.
Retorna a lista de todos os jobs registrados, ordenados do mais recente para o mais antigo, com temporizador de retenção S3.
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_..."
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.
{
"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"
}
}
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.
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!`);
}
import os, requests
API_KEY = os.getenv("VIDORA_API_KEY", "vd_live_...")
BASE_URL = "http://localhost:8080"
CHUNK_SIZE = 5 * 1024 * 1024 # 5 MB
def transcode_video(file_path):
file_size = os.path.getsize(file_path)
total_chunks = (file_size + CHUNK_SIZE - 1) // CHUNK_SIZE
# 1. Start upload
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
start_payload = {
"file_name": os.path.basename(file_path),
"file_size_bytes": file_size,
"chunks_number": total_chunks,
"output_mode": "hls",
"priority": "normal"
}
start_res = requests.post(f"{BASE_URL}/api/v1/uploads/start", json=start_payload, headers=headers).json()
job_id = start_res["job_id"]
# 2. Upload chunks via HTTP PUT
parts = []
with open(file_path, "rb") as f:
for item in start_res["upload_urls"]:
chunk = f.read(CHUNK_SIZE)
put_res = requests.put(item["url"], data=chunk)
etag = put_res.headers.get("ETag", f'"{item["part_number"]}"')
parts.append({"part_number": item["part_number"], "etag": etag})
# 3. Finish upload
finish_payload = {
"job_id": job_id,
"upload_id": start_res["upload_id"],
"file_key": start_res["file_key"],
"parts": parts
}
requests.post(f"{BASE_URL}/api/v1/uploads/finish", json=finish_payload, headers=headers)
print(f"Vídeo enviado! Acompanhe em: {BASE_URL}/api/v1/jobs/{job_id}")
transcode_video("video.mp4")
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. |