Pular navegação
Atualizado: 13.10.2026

O Kinescope suporta webhooks de saída — notificações sobre eventos que ocorrem com seus vídeos, streams ou reuniões do Speak. Quando ocorre um evento (por exemplo, um vídeo é processado ou um stream termina), o Kinescope envia uma solicitação HTTP para a URL que você especificou.

Para quem é este artigo

  • Desenvolvedores — precisam automatizar processos em seu sistema quando ocorrem eventos do Kinescope
  • Administradores de plataforma — precisam receber notificações sobre o status de processamento de vídeos
  • Engenheiros DevOps — precisam integrar o Kinescope com sistemas de monitoramento

Quais problemas os webhooks resolvem

Os webhooks permitem automatizar processos em seu sistema:

  • Rastreamento do processamento de vídeos — saiba quando um vídeo está pronto para assistir ou ocorreu um erro
  • Monitoramento de streams — receba notificações sobre conexões de streamers, fins de streams e outros eventos
  • Acompanhamento de reuniões no Speak — saiba quando as chamadas começam e terminam, quando os participantes entram e saem e quando a reunião é gravada
  • Integração com seu sistema — atualize automaticamente os status em seu banco de dados ou envie notificações para os usuários

Como funciona

  1. Você configura uma URL para receber webhooks (via API ou interface do Kinescope)
  2. Quando ocorre um evento, o Kinescope envia uma solicitação HTTP POST para sua URL com dados JSON
  3. Seu servidor manipula a solicitação e executa as ações necessárias (atualizações de status, envio de notificações, etc.)

Webhooks de vídeo

media.update.status

Enviado quando o status do vídeo é atualizado. Usado para rastrear processamento de vídeo, erros ou conclusão de publicação.

Exemplo 1: Atualização de status bem-sucedida

{
  "event": "media.update.status",
  "data": {
    "id": "7127f2d7-0e96-40d0-9a03-2e987c096466",
    "status": "done"
  }
}

Exemplo 2: Erro de processamento

{
  "event": "media.update.status",
  "data": {
    "id": "12706830-0e96-40d0-9a03-2e987c096466",
    "status": "error",
    "message": "import error: code=610100, message=cannot download link: https://example.ru/test.mp4, http_code=404"
  }
}

Status possíveis:

  • pending — vídeo aguardando processamento
  • uploading — vídeo sendo enviado
  • pre-processing — pré-processamento do vídeo
  • processing — vídeo sendo processado
  • aborted — processamento foi interrompido
  • done — vídeo pronto para assistir
  • error — ocorreu um erro durante o processamento
  • suspended — processamento/upload pausado

Webhooks de stream

live.created

Notificação sobre a criação de um novo evento de stream (via API ou interface).

{
  "event": "live.created",
  "data": {
    "event_id": "abc123-def456-ghi789"
  }
}

live.connected

Streamer conectado — stream RTMP começou a chegar ao servidor.

{
  "event": "live.connected",
  "data": {
    "event_id": "abc123-def456-ghi789"
  }
}

live.disconnected

Streamer desconectado — stream RTMP parou.

{
  "event": "live.disconnected",
  "data": {
    "event_id": "abc123-def456-ghi789"
  }
}

live.finished

Stream encerrado. O corpo do webhook também inclui video_id — o ID do vídeo de gravação do stream. Se o stream não foi gravado, é um UUID nulo 00000000-0000-0000-0000-000000000000.

{
  "event": "live.finished",
  "data": {
    "event_id": "abc123-def456-ghi789",
    "video_id": "7127f2d7-0e96-40d0-9a03-2e987c096466"
  }
}

live.cancelled

Stream foi cancelado.

{
  "event": "live.cancelled",
  "data": {
    "event_id": "abc123-def456-ghi789"
  }
}

live.enabled

Stream está disponível para visualização pelos clientes.

{
  "event": "live.enabled",
  "data": {
    "event_id": "abc123-def456-ghi789"
  }
}

Webhooks do Speak

Eventos sobre chamadas nas salas do Speak: início e fim da reunião, entrada e saída de participantes e gravação. Para recebê-los, liste os eventos desejados no campo events ao criar ou atualizar o webhook.

Todos os eventos do Speak trazem dois identificadores:

  • room_id — ID da sala. A sala é permanente e pode receber muitas reuniões
  • call_id — ID da chamada, ou seja, de uma reunião nesta sala

São os mesmos IDs da referência da API do Speak: com eles você pode consultar os dados da sala e da chamada.

speak.call.started

Uma chamada começou na sala.

{
  "event": "speak.call.started",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815"
  }
}

speak.call.finished

A chamada na sala terminou.

{
  "event": "speak.call.finished",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815"
  }
}

speak.participant.joined

Um participante entrou na chamada. O objeto participant traz:

  • id — ID do participante da sala
  • identity — identificador da conexão à chamada; use-o para relacionar a entrada e a saída de um mesmo participante
  • name — nome com que o participante entrou
  • role — função do participante na sala

id e role podem vir vazios — por exemplo, se a sessão do participante já tiver sido encerrada no momento do envio. Participantes de serviço, como o bot de gravação, não geram eventos speak.participant.*.

{
  "event": "speak.participant.joined",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815",
    "participant": {
      "id": "c41f7e28-3b9d-4a65-8e12-6f0d5b9a7c33",
      "identity": "8e3b5a17-2c4d-4f90-a6e1-7d9c0b3f5a24",
      "name": "Ana Souza",
      "role": "admin"
    }
  }
}

speak.participant.left

Um participante saiu da chamada. O objeto participant é o mesmo de speak.participant.joined.

{
  "event": "speak.participant.left",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815",
    "participant": {
      "id": "c41f7e28-3b9d-4a65-8e12-6f0d5b9a7c33",
      "identity": "8e3b5a17-2c4d-4f90-a6e1-7d9c0b3f5a24",
      "name": "Ana Souza",
      "role": "admin"
    }
  }
}

speak.record.started

A gravação da reunião começou. O objeto record traz o ID da gravação (id) e o seu status (status).

{
  "event": "speak.record.started",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815",
    "record": {
      "id": "3a9e6c21-5f7b-4d18-9c0e-b2a4d6f8e137",
      "status": "starting"
    }
  }
}

speak.record.finished

A gravação da reunião foi interrompida. O evento não traz o ID do vídeo: a gravação é salva no catálogo e processada como qualquer outro vídeo.

{
  "event": "speak.record.finished",
  "data": {
    "room_id": "0f8c3a52-6b1e-4c2d-9a47-3e5b8d1f2c60",
    "call_id": "5d2e9b14-7a3c-4f8e-b061-92c4a7e3d815",
    "record": {
      "id": "3a9e6c21-5f7b-4d18-9c0e-b2a4d6f8e137",
      "status": "complete"
    }
  }
}

Status possíveis:

  • complete — gravação concluída com sucesso
  • failed — gravação terminou com erro
  • aborted — gravação abortada
  • limit_reached — gravação interrompida ao atingir um limite

A retransmissão a partir do Speak sem gravação não gera eventos speak.record.*.

Exemplos de manipulação de webhooks

Exemplo 1: Atualizando o status do vídeo no banco de dados

Aqui está como manipular o webhook media.update.status e atualizar o status em seu banco de dados:

package main

import (
    "encoding/json"
    "log"
)

type MediaStatusEvent struct {
    Event string `json:"event"`
    Data  struct {
        ID      string `json:"id"`
        Status  string `json:"status"`
        Message string `json:"message,omitempty"`
    } `json:"data"`
}

func handleMediaStatusUpdate(event MediaStatusEvent) error {
    videoID := event.Data.ID
    status := event.Data.Status
    
    // Atualizar status no banco de dados
    // db.Exec("UPDATE videos SET status = ?, error_message = ?, updated_at = ? WHERE kinescope_id = ?",
    //     status, event.Data.Message, time.Now(), videoID)
    
    if status == "done" {
        notifyUser(videoID, "Seu vídeo está pronto para assistir!")
    }
    
    if status == "error" {
        log.Printf("Erro de processamento do vídeo %s: %s", videoID, event.Data.Message)
    }
    
    if status == "aborted" {
        notifyUser(videoID, "O processamento do vídeo foi interrompido")
    }
    
    return nil
}

Exemplo 2: Manipulando o fim do stream

Quando um stream termina, você pode processar automaticamente a gravação:

package main

type LiveFinishedEvent struct {
    Event string `json:"event"`
    Data  struct {
        EventID string `json:"event_id"`
        VideoID string `json:"video_id,omitempty"`
    } `json:"data"`
}

func handleLiveFinished(event LiveFinishedEvent) error {
    eventID := event.Data.EventID
    videoID := event.Data.VideoID
    
    // Atualizar status do stream
    // db.Exec("UPDATE live_events SET status = ?, recording_video_id = ?, finished_at = ? WHERE kinescope_event_id = ?",
    //     "finished", videoID, time.Now(), eventID)
    
    // Sem gravação, video_id é um UUID nulo
    if videoID != "" && videoID != "00000000-0000-0000-0000-000000000000" {
        notifyViewers(eventID, "A gravação do stream está disponível: "+videoID)
    }
    
    return nil
}

Exemplo 3: Manipulador universal de webhook

Aqui está um exemplo de um manipulador universal que pode processar diferentes tipos de webhook:

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

type WebhookEvent struct {
    Event string          `json:"event"`
    Data  json.RawMessage `json:"data"`
}

func handleWebhook(event WebhookEvent) error {
    switch event.Event {
    case "media.update.status":
        var e MediaStatusEvent
        json.Unmarshal(event.Data, &e.Data)
        e.Event = event.Event
        return handleMediaStatusUpdate(e)
        
    case "live.finished":
        var e LiveFinishedEvent
        json.Unmarshal(event.Data, &e.Data)
        e.Event = event.Event
        return handleLiveFinished(e)
        
    default:
        log.Printf("Tipo de evento desconhecido: %s", event.Event)
    }
    
    return nil
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    var event WebhookEvent
    if err := json.NewDecoder(r.Body).Decode(&event); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    if err := handleWebhook(event); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]bool{"success": true})
}

Configurando webhooks

Os webhooks são configurados via API do Kinescope. Especifique a URL do seu endpoint que receberá as notificações.

Importante: Seu endpoint deve retornar HTTP 200 em resposta ao tratamento bem-sucedido do webhook. Se o Kinescope receber um erro (4xx, 5xx), pode tentar novamente a solicitação.

Segurança

É recomendado verificar a autenticidade dos webhooks:

  • Verifique a origem da solicitação — certifique-se de que a solicitação vem do Kinescope
  • Use HTTPS — os webhooks devem ser enviados para URLs seguras
  • Valide os dados — verifique o formato e os campos obrigatórios na solicitação

Pronto! Agora você pode configurar webhooks e automatizar processos em seu sistema.

O que fazer a seguir?

  1. Regras gerais da API — autorização e formato de solicitação
  2. Referência da API — documentação completa da API para configuração de webhooks
  3. Upload de arquivos via API — upload automatizado de vídeos

Ainda tem dúvidas? Escreva para o chat de suporte na interface do Kinescope — nossos especialistas vão ajudar!