JMV Public API

API REST para gerenciamento de vídeos VOD, eventos ao vivo, playlists, streams e upload de arquivos diretamente para o storage S3/MinIO.

Versão
v2 (endpoint oficial)
Autenticação
Bearer JWT (HS256, 4h)
Formato
application/json
Upload máximo
5 TB (S3 multipart)

Base URLs

Produção https://api.jmvstream.com

Erros

A API usa códigos HTTP padrão. Respostas de erro retornam um objeto com a chave message.

CódigoSignificado
400Parâmetros inválidos ou ausentes
401Token ausente, expirado ou inválido
404Recurso não encontrado
507Sem espaço disponível no storage
500Erro interno do servidor
// Exemplo de resposta de erro
{
  "message": "not allowed, token is expired"
}

Autenticação

POST /v2/authenticate Endpoint oficial

Gera um token JWT usando apenas o UUID do plano (resource). Endpoint oficial — nenhuma credencial de usuário é necessária.

Body

CampoTipoObrig.Descrição
resource string (UUID) sim UUID do plano do cliente

Requisição

POST /v2/authenticate
Content-Type: application/json

{
  "resource": "eeba7244-e850-4064-aa61-008718b6e4b0"
}

Resposta — 200 OK

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Usando o token

Inclua o token em todas as requisições autenticadas via header Authorization:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
ℹ️
Expiração Tokens expiram em 4 horas. Após a expiração a API retorna 401 — not allowed, token is expired. Gere um novo token com o endpoint de autenticação.

Payload do JWT (decodificado)

{
  "planId":          123,
  "planUuid":        "eeba7244-e850-4064-aa61-008718b6e4b0",
  "planType":        "od",
  "planDescription": "Plano VOD Enterprise",
  "id_customers":    456,
  "sub": {
    "id_customers": 456,
    "email":        "admin@empresa.com"
  },
  "iat": 1750870000,
  "exp": 1750884400
}

Vídeos

Todas as rotas de vídeo requerem autenticação via Bearer token.

GET /v1/videos/application Lista paginada com filtros

Retorna a lista paginada de vídeos do plano com opções de filtro e ordenação.

Query Parameters

ParâmetroTipoPadrãoDescrição
pagenumber1Página atual
perPagenumber10Itens por página (máx. 50)
sortASC | DESCASCDireção da ordenação
orderBystringnameCampo de ordenação
namestringFiltro por nome (like)
initialDateYYYY-MM-DDData de início do filtro
endDateYYYY-MM-DDData de fim do filtro
GET /v1/videos/:hash Busca individual

Retorna um vídeo individual formatado com o secret do plano para geração de URLs assinadas.

Path Parameters

ParâmetroTipoDescrição
hashstringHash único do vídeo (15 chars alfanuméricos)
DELETE /v1/videos/deleteVideo/:hash/:customer_plans_id Remover vídeo

Remove um vídeo do plano. A remoção é processada de forma assíncrona — o vídeo fica indisponível imediatamente, mas a exclusão física do arquivo pode levar alguns instantes para ser concluída.

PUT /v1/videos/moveVideo/:hash Mover para outra galeria

Move um vídeo para uma galeria diferente.

Body

CampoTipoObrig.Descrição
gallerystring (UUID)simUUID da galeria destino
PUT /v1/videos/editVideo/:hash/:planId Renomear vídeo

Atualiza o nome de exibição de um vídeo.

Body

CampoTipoObrig.Descrição
namestringsimNovo nome do vídeo
PUT /v1/videos/uploadThumb/:hash/:planId Upload de thumbnail

Faz upload de thumbnail via multipart/form-data. Limite de 1 MB. A imagem é enviada para a Static API e o campo thumb do vídeo é atualizado.

ℹ️
Content-Type da requisição deve ser multipart/form-data, não application/json.
GET /v1/videos/converting/:customerPlanId Vídeos em conversão

Retorna a lista de vídeos com jobs de conversão em andamento para o plano especificado.

GET /v1/videos/job-status/:videoHash Status de conversão

Retorna o status normalizado do job de conversão de um vídeo.

Valores de retorno

StatusCondição
COMPLETEDprogress ≥ 100
CONVERTINGstatus = converting ou progress > 0
ERRORstatus = ERROR ou FAILED
AWAIT_CONVERSIONdemais casos

Galerias

GET /v1/folders Lista galerias com hierarquia

Retorna a árvore de galerias do plano, incluindo galerias filhas (children).

{
  "folders": [
    {
      "id":          1,
      "uuid":        "a1b2c3d4-...",
      "name":        "Treinamentos",
      "description": "Vídeos de treinamento interno",
      "children": []
    }
  ]
}
POST /v1/folders Criar galeria

Body

CampoTipoObrig.Descrição
namestringsimNome da galeria
descriptionstringnãoDescrição
parentstring (UUID)nãoUUID da galeria pai (para criar subgaleria)
PUT /v1/folders/:uuid Atualizar galeria

Atualiza nome e/ou descrição de uma galeria existente.

DELETE /v1/folders/:uuid Remover galeria

Remove uma galeria. Galerias com vídeos associados não podem ser removidas.


Eventos ao Vivo

POST /v1/events/insert Criar evento

Cria um novo evento com status inicial WAITING_LIVE.

Body

CampoTipoObrig.Descrição
titlestringsimTítulo do evento
scheduledDatestring (ISO 8601)simData e hora agendada
GET /v1/events/searchAll Listar eventos

Retorna lista paginada de eventos do plano.

PUT /v1/events/start-or-end-live Controlar status do evento

Altera o status de um evento ao vivo. O ciclo de vida segue a sequência:

WAITING_LIVE  →  LIVE  →  ON_DEMAND
DELETE /v1/events/delete Remover eventos

Remove um ou mais eventos. Aceita array de IDs no body.

Body

{
  "ids": [42, 43, 44]
}

Playlist

Gerenciamento de playlists para planos AVJ. Permite ordenar e controlar o conteúdo exibido.

GET /v1/playlist/:customerplan Listar playlist

Retorna todos os vídeos da playlist de um plano na ordem configurada.

POST /v1/playlist/:customerplan/add Adicionar à playlist

Body

CampoTipoObrig.Descrição
videoIdnumbersimID do vídeo a adicionar
PUT /v1/playlist/:customerplan/move/:videoId Reordenar vídeo

Altera a posição de um vídeo na playlist.

Body

CampoTipoObrig.Descrição
positionnumbersimNova posição (1-based)
DELETE /v1/playlist/:customerplan/remove Remover da playlist

Remove um vídeo da playlist sem excluí-lo do sistema.

GET /v1/playlist/:id_plan/playing Vídeo em reprodução

Retorna o vídeo atualmente em reprodução no player. Consulta o banco de dados Webtv (leitura em tempo real).


Streams v2

Proxy para o Stream Gateway. Todas as operações são encaminhadas para o serviço interno via X-API-KEY. O stream_id é gerado automaticamente no formato OT-NORMAL-{name}-{stream_key}.

POST /v2/streams Criar stream

Cria um novo target de stream no Stream Gateway.

Body

CampoTipoObrig.Descrição
namestringsimNome identificador do stream
stream_keystringsimChave única do stream
GET /v2/streams/:stream_id Status em tempo real

Retorna o status atual da transmissão diretamente do Stream Gateway.

PUT /v2/streams/:stream_id/control Habilitar / desabilitar

Body

CampoTipoObrig.Descrição
actionenable | disablesimAção a executar na transmissão
DELETE /v2/streams/:stream_id Remover stream

Remove a transmissão do Stream Gateway. Operação irreversível.


Upload S3 v2

Upload de vídeos diretamente para o MinIO (S3-compatible) usando presigned URLs. O conteúdo do arquivo nunca passa pela API — o cliente envia diretamente para o storage. Suporta arquivos de até 5 TB.

🔄
Fluxo recomendado: 3 etapas 1. POST /v2/upload/multipart/s3 → obter presigned URLs
2. PUT para cada URL diretamente no MinIO (client-side) → coletar ETags
3. POST /v2/upload/multipart/complete → finalizar e processar

Estratégias por tamanho de arquivo

TamanhoEstratégiaChunk Size
< 100 MBdirect_uploadArquivo completo (1 parte)
100 MB – 1 GBmedium_chunks16 MB
1 GB – 100 GBlarge_chunks64 MB
100 GB – 5 TBhuge_chunksDinâmico (máx. 10.000 partes)
POST /v2/upload/multipart/s3 Iniciar multipart upload

Cria um multipart upload no MinIO e retorna todas as presigned URLs de uma vez. Cada URL tem validade de 6 horas.

Body

CampoTipoObrig.Descrição
fileNamestringsimNome original do arquivo (com extensão)
fileSizenumbersimTamanho do arquivo em bytes
totalPartsnumbersimNúmero total de partes a enviar
chunkSizenumbersimTamanho de cada chunk em bytes

Requisição

POST /v2/upload/multipart/s3
Authorization: Bearer <token>
Content-Type: application/json

{
  "fileName":   "video-treinamento.mp4",
  "fileSize":   1073741824,
  "totalParts": 16,
  "chunkSize":  67108864
}

Resposta — 200 OK

{
  "uploadId":    "minio-upload-id-xyz",
  "objectName":  "uploads/vod123/a8f3k2m9x1q4p.mp4",
  "video_hash":  "a8f3k2m9x1q4p",
  "totalParts":  16,
  "presignedUrls": [
    { "partNumber": 1, "url": "https://minio.../upload?partNumber=1&uploadId=..." },
    { "partNumber": 2, "url": "https://minio.../upload?partNumber=2&uploadId=..." }
  ]
}

Envio das partes (client-side)

Para cada presigned URL, faça um PUT diretamente no MinIO com o chunk correspondente:

// JavaScript — enviar cada parte
const uploadedParts = [];

for (let i = 0; i < presignedUrls.length; i++) {
  const { partNumber, url } = presignedUrls[i];
  const start = i * chunkSize;
  const chunk = file.slice(start, start + chunkSize);

  const res = await fetch(url, {
    method: 'PUT',
    body: chunk,
    headers: { 'Content-Type': 'application/octet-stream' }
  });

  uploadedParts.push({
    partNumber,
    etag: res.headers.get('ETag')
  });
}
POST /v2/upload/multipart/complete Finalizar multipart upload

Finaliza o multipart upload no MinIO, registra o vídeo no banco e enfileira o job de processamento na fila s3-upload-queue.

Body

CampoTipoObrig.Descrição
filenamestringsimNome original do arquivo
sizenumbersimTamanho em bytes
video_hashstringsimHash retornado pelo init
objectNamestringsimObject name retornado pelo init
uploadIdstringsimUpload ID retornado pelo init
partsarraysimArray de { partNumber, etag } coletados no envio
gallerystring (UUID)nãoUUID da galeria destino

Requisição

{
  "filename":   "video-treinamento.mp4",
  "size":       1073741824,
  "video_hash": "a8f3k2m9x1q4p",
  "objectName": "uploads/vod123/a8f3k2m9x1q4p.mp4",
  "uploadId":   "minio-upload-id-xyz",
  "gallery":   "a1b2c3d4-e5f6-...",
  "parts": [
    { "partNumber": 1, "etag": "\"abc123\"" },
    { "partNumber": 2, "etag": "\"def456\"" }
  ]
}
POST /v2/upload/s3-direct Upload direto (arquivo único)

Gera uma presigned URL para upload de arquivo em uma única requisição PUT. Validade de 24 horas. Recomendado para arquivos menores que 100 MB.

Body

CampoTipoObrig.Descrição
filenamestringsimNome do arquivo com extensão
fileSizenumbersimTamanho em bytes
gallerystring (UUID)nãoUUID da galeria destino
POST /v2/upload/s3-direct-complete Confirmar upload direto

Confirma que o arquivo foi enviado para o MinIO via PUT, valida a existência do objeto (headObject), registra o vídeo e enfileira o job de processamento.

Body

CampoTipoObrig.Descrição
hashstringsimHash retornado pelo endpoint de criação
gallerystring (UUID)nãoUUID da galeria destino