Plan Scale

API para desarrolladores

Una API REST para gestionar tu videoteca y automatizar tu flujo de trabajo. Todas las respuestas son JSON. URL base:

https://otakuga.com/api/v1

Introducción

La API de Otakuga te permite subir, listar y consultar tus vídeos mediante peticiones HTTP, y reaccionar a eventos con webhooks. Es una función del plan Scale.

Todos los endpoints cuelgan de https://otakuga.com/api/v1, aceptan y devuelven JSON, y requieren autenticación por clave (salvo el proxy de subida, que usa un token temporal). El contenido de vídeo se sirve por streaming HLS a través de nuestra red CDN; la API no expone detalles de la infraestructura subyacente.

Autenticación

Crea una clave de API en el panel, en Ajustes → Claves de API. La clave se muestra una sola vez al crearla (formato sv_live_…); guárdala en un lugar seguro.

Envíala en la cabecera Authorization como Bearer token en cada petición:

bash
curl https://otakuga.com/api/v1/videos \
  -H "Authorization: Bearer sv_live_tu_clave_aqui"

Trata la clave como un secreto de servidor. Da acceso a todos los vídeos de tu cuenta: úsala solo desde tu backend, nunca la incrustes en un navegador ni en una app cliente.

Errores

Los errores devuelven un código HTTP y un cuerpo JSON con el campo error:

json
{ "error": "No autorizado" }
  • 401 — clave ausente o inválida.
  • 402 — cuota de plan agotada o ancho de banda sin crédito.
  • 403 — tu plan no incluye la API (requiere Scale).
  • 404 — recurso no encontrado.
  • 500 — error interno; incluye una ref para soporte.

El objeto vídeo

json
{
  "id": "cmr...",              // identificador del vídeo
  "title": "Mi vídeo",
  "description": null,
  "status": "READY",           // ver estados abajo
  "durationSeconds": 128,
  "sizeBytes": 48213344,
  "playCount": 57,
  "collectionId": null,
  "createdAt": "2026-07-18T12:00:00.000Z"
}

El campo status puede ser: CREATED, UPLOADING, UPLOADED, PROCESSING, READY (listo para reproducir), FAILED o DELETED.

Listar vídeos

GET/videos

Devuelve tus vídeos, del más reciente al más antiguo, con paginación por cursor. Parámetros de consulta (todos opcionales):

  • limit — número de resultados (1–100, por defecto 50).
  • cursorid del último vídeo de la página anterior.
  • status — filtra por estado (p. ej. READY).
bash
curl "https://otakuga.com/api/v1/videos?limit=20&status=READY" \
  -H "Authorization: Bearer sv_live_…"
json
{
  "videos": [ { "id": "cmr…", "title": "Mi vídeo", "status": "READY", … } ],
  "nextCursor": "cmr…"   // null si no hay más páginas
}

Crear un vídeo

POST/videos

Crea el registro del vídeo y devuelve, además del objeto, un descriptor de subida que usarás en el siguiente paso. Cuerpo (JSON):

  • title — título del vídeo (opcional).
  • collectionId — id de una colección para organizarlo (opcional).
bash
curl -X POST https://otakuga.com/api/v1/videos \
  -H "Authorization: Bearer sv_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Mi vídeo" }'
json
{
  "video": { "id": "cmr…", "status": "UPLOADING", … },
  "upload": {
    "protocol": "tus",
    "endpoint": "https://otakuga.com/api/v1/upload",
    "headers": { "X-Upload-Token": "…" },
    "metadata": { "filetype": "video/mp4", "title": "Mi vídeo" }
  }
}

Subir el archivo

La subida usa el protocolo TUS (resumible), contra el endpoint y con los headers que devolvió el paso anterior. Los bytes se transmiten a través de nuestro servidor sin almacenarse en él. Ejemplo en Node con tus-js-client:

javascript
import * as tus from "tus-js-client";
import fs from "node:fs";

// 1) Crear el vídeo (paso anterior) → { video, upload }
const res = await fetch("https://otakuga.com/api/v1/videos", {
  method: "POST",
  headers: { Authorization: "Bearer sv_live_…", "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Mi vídeo" }),
});
const { video, upload } = await res.json();

// 2) Subir el archivo al endpoint devuelto
const path = "mi-video.mp4";
new tus.Upload(fs.createReadStream(path), {
  endpoint: upload.endpoint,
  headers: upload.headers,            // incluye X-Upload-Token
  uploadSize: fs.statSync(path).size,
  metadata: upload.metadata,
  chunkSize: 50 * 1024 * 1024,        // 50 MB por trozo (recomendado)
  onSuccess: () => console.log("Subido:", video.id),
  onError: (err) => console.error(err),
}).start();

Cuando termine la subida, el vídeo pasa por PROCESSING y luego a READY. Suscríbete al webhook video.ready (más abajo) para enterarte sin sondear.

Obtener un vídeo

GET/videos/:id
bash
curl https://otakuga.com/api/v1/videos/cmr… \
  -H "Authorization: Bearer sv_live_…"
json
{ "video": { "id": "cmr…", "status": "READY", … } }

Un id de otro tenant devuelve 404: cada clave solo accede a los vídeos de su propia cuenta.

Webhooks

Configura webhooks salientes en el panel (Ajustes → Webhooks) para que te avisemos cuando ocurra un evento. Eventos disponibles:

  • video.ready — un vídeo terminó de procesarse y está listo.
  • lead.captured — un espectador dejó sus datos en el reproductor.

Enviamos un POST a tu URL con este cuerpo, y las cabeceras X-Nubiux-Event y X-Nubiux-Signature:

json
{
  "event": "video.ready",
  "at": "2026-07-18T12:00:00.000Z",
  "data": { … }
}

Verificar la firma

La firma es un HMAC-SHA256 del cuerpo crudo con el secreto del webhook (que se muestra una vez al crearlo). Compárala en tiempo constante:

javascript
import crypto from "node:crypto";

function verificar(cuerpoCrudo, firma, secreto) {
  const esperada = crypto.createHmac("sha256", secreto)
    .update(cuerpoCrudo).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(firma), Buffer.from(esperada)
  );
}

¿Dudas o te falta algún endpoint? Escríbenos a soporte@otakuga.com. Consulta también los Términos.