Pular para conteúdo

Download de Gravações

O endpoint GET /recordings/files/{fileId}/download-url gera uma URL assinada e temporária para download de um arquivo de gravação. É a forma recomendada de obter uma URL de download nova a qualquer momento.

Atenção ao caminho

Este endpoint não usa o prefixo /api. O caminho correto é https://api.videochamada.com.br/recordings/files/{fileId}/download-url.

Fluxo de download

  1. Liste os arquivos da chamada com GET /api/calls/{id}/recordings.
  2. Pegue o id do arquivo desejado (o fileId).
  3. Chame GET /recordings/files/{fileId}/download-url para obter a URL assinada.
  4. Faça o download do arquivo diretamente pela URL retornada (sem autenticação adicional).

Atalho: signed_url já vem na listagem

A listagem de gravações já retorna uma URL assinada pronta (signed_url) e seu instante de expiração (expires_at) em cada item — para a maioria dos casos você pode baixar direto por ela, sem chamada extra. Use o endpoint deste documento quando quiser gerar uma URL nova (por exemplo, quando a da listagem já expirou, ou quando você só tem o fileId).

Requisição

GET https://api.videochamada.com.br/recordings/files/{fileId}/download-url

Cabeçalhos:

Authorization: Bearer {API_TOKEN}

A autenticação aceita dois esquemas:

  • API key do projeto (recomendado para integrações servidor-a-servidor) — autoriza qualquer arquivo cuja chamada pertença ao projeto da chave.
  • JWT de sessão do painel — o usuário deve pertencer à organização dona do projeto.

Parâmetros:

Parâmetro Tipo Obrigatório Descrição
fileId string (path) Sim ID do arquivo de gravação (campo id retornado na listagem de gravações)

Exemplos

curl -X GET "https://api.videochamada.com.br/recordings/files/{fileId}/download-url" \
  -H "Authorization: Bearer {API_TOKEN}"
import requests

response = requests.get(
    f"https://api.videochamada.com.br/recordings/files/{file_id}/download-url",
    headers={"Authorization": "Bearer {API_TOKEN}"},
)
data = response.json()
print("URL de download:", data["url"])
print("Expira em:", data["expiresIn"], "segundos")
const response = await fetch(
  `https://api.videochamada.com.br/recordings/files/${fileId}/download-url`,
  { headers: { Authorization: 'Bearer {API_TOKEN}' } },
);
const { url, expiresIn } = await response.json();
console.log('URL de download:', url);
console.log('Expira em:', expiresIn, 'segundos');

Resposta

{
  "url": "https://s3.sa-east-1.amazonaws.com/.../recordings/abc123.webm?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=...",
  "expiresIn": 604800
}
Campo Tipo Descrição
url string URL assinada para download direto do arquivo
expiresIn number Validade da URL em segundos: 604800 (7 dias)

Erros

Status Mensagem Quando
401 Authentication required: provide a valid API key or session JWT Sem cabeçalho Authorization, ou credencial malformada/inválida/expirada
403 Recording does not belong to this project A API key é de um projeto diferente do projeto da gravação
404 Recording file not found O fileId não existe
410 Recording expired on {data}. Retention period: {n} days O arquivo ultrapassou o período de retenção. A mensagem inclui a data em que a gravação expirou

Exemplo completo: download programático

Python — usando signed_url da listagem (1 requisição)

import os
import requests

def download_recordings(call_id, api_token, output_dir="downloads"):
    headers = {"Authorization": f"Bearer {api_token}"}

    # 1. Listar gravações — signed_url já vem na resposta
    response = requests.get(
        f"https://api.videochamada.com.br/api/calls/{call_id}/recordings",
        headers=headers,
    )
    files = response.json()["data"]

    if not files:
        print("Nenhuma gravação encontrada")
        return

    os.makedirs(output_dir, exist_ok=True)

    for file in files:
        signed_url = file.get("signed_url")
        if not signed_url:
            # signed_url = null => gravação fora do período de retenção
            print(f"Pulando {file['id']}: signed_url indisponível")
            continue

        # 2. Download direto
        extension = "mp4" if file["fileType"] == "composite" else "webm"
        filepath = os.path.join(output_dir, f"{call_id}_{file['id']}.{extension}")
        with requests.get(signed_url, stream=True) as file_response:
            with open(filepath, "wb") as f:
                for chunk in file_response.iter_content(chunk_size=8192):
                    f.write(chunk)
        print(f"Download concluído: {filepath}")

download_recordings("{callId}", "{API_TOKEN}")

Node.js — usando o endpoint /download-url (URL sempre nova)

Útil quando você só tem o fileId ou quando a signed_url da listagem já expirou:

const fs = require('fs');
const path = require('path');

async function downloadRecordings(callId, apiToken, outputDir = 'downloads') {
  const headers = { Authorization: `Bearer ${apiToken}` };

  // 1. Listar gravações da chamada
  const listResponse = await fetch(
    `https://api.videochamada.com.br/api/calls/${callId}/recordings`,
    { headers },
  );
  const files = (await listResponse.json()).data;

  if (files.length === 0) {
    console.log('Nenhuma gravação encontrada');
    return;
  }

  fs.mkdirSync(outputDir, { recursive: true });

  for (const file of files) {
    // 2. Gerar URL de download nova para o arquivo
    const urlResponse = await fetch(
      `https://api.videochamada.com.br/recordings/files/${file.id}/download-url`,
      { headers },
    );
    if (urlResponse.status === 410) {
      console.log(`Pulando ${file.id}: fora do período de retenção`);
      continue;
    }
    const { url } = await urlResponse.json();

    // 3. Baixar o arquivo
    const extension = file.fileType === 'composite' ? 'mp4' : 'webm';
    const filepath = path.join(outputDir, `${callId}_${file.id}.${extension}`);
    const fileResponse = await fetch(url);
    const buffer = Buffer.from(await fileResponse.arrayBuffer());
    fs.writeFileSync(filepath, buffer);
    console.log(`Download concluído: ${filepath}`);
  }
}

downloadRecordings('{callId}', '{API_TOKEN}');

Informações técnicas

Formato dos arquivos

Tipo Container Codecs
Gravação individual (video) WebM (.webm) Vídeo VP8/VP9, áudio Opus
Gravação composta (composite) MP4 (.mp4) Grade única com todos os participantes

Validade da URL

As URLs de download expiram em 7 dias (expiresIn: 604800 segundos). Após a expiração, basta chamar o endpoint novamente para gerar uma URL nova — ou reler a signed_url na listagem de gravações.

Política de retenção

As gravações são mantidas por um período configurável por projeto (recordingRetentionDays), com padrão de 30 dias contados a partir da criação da gravação. Após esse período:

  • A listagem passa a retornar signed_url: null para os arquivos expirados.
  • O endpoint de download retorna 410 Gone, com a data de expiração na mensagem.

Faça backup antes da retenção expirar

Se você precisa manter as gravações por mais tempo que o período de retenção do projeto, baixe e armazene os arquivos na sua infraestrutura antes do prazo.

Boas práticas

  • Baixe logo, não guarde a URL: gere a URL no momento do download em vez de armazená-la — ela expira em 7 dias.
  • Trate o 410: um arquivo listado no seu histórico pode já ter saído da retenção. Trate 410 (e signed_url: null) como "gravação expirada", não como erro transitório.
  • Download em streaming: para arquivos grandes, use streaming em vez de carregar o conteúdo inteiro em memória.
  • Retry em falhas de rede: implemente novas tentativas para falhas durante o download — a URL continua válida dentro do prazo.