Пропустить навигацию
Обновлено: 03.10.2026
Открыть как Markdown

Kinescope поддерживает исходящие вебхуки — это уведомления о событиях, которые происходят с вашими видео, трансляциями или встречами в Speak. Когда происходит событие (например, видео обработалось или трансляция завершилась), Kinescope отправляет HTTP-запрос на указанный вами URL.

Кому подходит эта статья

  • Разработчикам — нужно автоматизировать процессы в системе при событиях Kinescope
  • Администраторам платформ — требуется получать уведомления о статусе обработки видео
  • DevOps-инженерам — нужно интегрировать Kinescope с системами мониторинга

Какие задачи решают вебхуки

Вебхуки позволяют автоматизировать процессы в вашей системе:

  • Отслеживание обработки видео — узнайте, когда видео готово к просмотру или произошла ошибка
  • Мониторинг трансляций — получайте уведомления о подключении стримера, завершении трансляции и других событиях
  • Учёт встреч в Speak — узнавайте о начале и завершении звонков, входе и выходе участников, записи встречи
  • Интеграция с вашей системой — автоматически обновляйте статусы в вашей базе данных или отправляйте уведомления пользователям

Как это работает

  1. Вы настраиваете URL для получения вебхуков (через API или интерфейс Kinescope)
  2. Когда происходит событие Kinescope отправляет HTTP POST-запрос на ваш URL с JSON-данными
  3. Ваш сервер обрабатывает запрос и выполняет нужные действия (обновление статуса, отправка уведомлений и т.д.)

Вебхуки для видео

media.update.status

Отправляется при обновлении статуса видео. Используется для отслеживания процессов обработки видео, ошибок или завершения публикации.

Пример 1: Успешное обновление статуса

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

Пример 2: Ошибка при обработке

{
  "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"
  }
}

Возможные статусы:

  • pending — видео ожидает обработки
  • uploading — видео загружается
  • pre-processing — предобработка видео
  • processing — видео обрабатывается
  • aborted — обработка прервана
  • done — видео готово к просмотру
  • error — произошла ошибка при обработке
  • suspended — обработка/загрузка приостановлена

Вебхуки для трансляций

live.created

Уведомление о создании нового события трансляции (через API или интерфейс).

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

live.connected

Стример подключился — RTMP поток начал поступать на сервер.

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

live.disconnected

Стример отключился — RTMP поток прекратился.

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

live.finished

Трансляция завершена. В ответе также приходит video_id — ID видео с записью трансляции (если запись была включена).

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

live.cancelled

Трансляция отменена.

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

live.enabled

Трансляция доступна для просмотра клиентами.

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

Вебхуки для Speak

События о звонках в комнатах Speak: начало и завершение встречи, вход и выход участников, запись. Чтобы их получать, перечислите нужные события в поле events при создании или обновлении вебхука.

Во всех событиях Speak приходят два идентификатора:

  • room_id — ID комнаты. Комната постоянная, в ней может пройти много встреч
  • call_id — ID звонка, то есть одной встречи в этой комнате

Это те же ID, что в справочнике API по Speak: по ним можно запросить данные комнаты и звонка.

speak.call.started

В комнате начался звонок.

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

speak.call.finished

Звонок в комнате завершён.

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

speak.participant.joined

Участник подключился к звонку. В объекте participant приходят:

  • id — ID участника комнаты
  • identity — идентификатор подключения к звонку; по нему удобно сопоставить вход и выход одного участника
  • name — имя, под которым участник вошёл
  • role — роль участника в комнате

id и role могут прийти пустыми — например, если сессия участника к моменту отправки уже закрыта. Служебные участники, например бот записи, событий 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": "Анна Смирнова",
      "role": "admin"
    }
  }
}

speak.participant.left

Участник покинул звонок. Объект participant такой же, как в 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": "Анна Смирнова",
      "role": "admin"
    }
  }
}

speak.record.started

Началась запись встречи. В объекте record приходят ID записи (id) и её статус (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

Запись встречи остановлена. ID видео в событии нет: запись сохраняется в каталог и обрабатывается как обычное видео.

{
  "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"
    }
  }
}

Возможные статусы:

  • complete — запись завершена успешно
  • failed — запись завершилась с ошибкой
  • aborted — запись прервана
  • limit_reached — запись остановлена по достижении лимита

Рестрим из Speak без записи событий speak.record.* не порождает.

Примеры обработки вебхуков

Пример 1: Обновление статуса видео в базе данных

Вот как можно обработать вебхук media.update.status и обновить статус в вашей базе данных:

package main

import (
    "encoding/json"
    "log"
    "time"
)

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

// Пример обработки вебхука media.update.status
func handleMediaStatusUpdate(event MediaStatusEvent) error {
    videoID := event.Data.ID
    status := event.Data.Status
    
    // Обновляем статус в базе данных
    // 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, "Ваше видео готово к просмотру!")
    }
    
    // Если произошла ошибка, логируем её
    if status == "error" {
        log.Printf("Ошибка обработки видео %s: %s", videoID, event.Data.Message)
    }
    
    // Если обработка прервана, уведомляем пользователя
    if status == "aborted" {
        notifyUser(videoID, "Обработка видео была прервана")
    }
    
    return nil
}

Пример 2: Обработка завершения трансляции

Когда трансляция завершается, можно автоматически обработать запись:

package main

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

// Пример обработки вебхука live.finished
func handleLiveFinished(event LiveFinishedEvent) error {
    eventID := event.Data.EventID
    videoID := event.Data.VideoID
    
    // Обновляем статус трансляции
    // db.Exec("UPDATE live_events SET status = ?, recording_video_id = ?, finished_at = ? WHERE kinescope_event_id = ?",
    //     "finished", videoID, time.Now(), eventID)
    
    // Если есть запись, уведомляем пользователей
    if videoID != "" {
        notifyViewers(eventID, "Запись трансляции доступна: "+videoID)
    }
    
    return nil
}

Пример 3: Универсальный обработчик вебхуков

Вот пример универсального обработчика, который может обрабатывать разные типы вебхуков:

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("Неизвестный тип события: %s", event.Event)
    }
    
    return nil
}

// HTTP обработчик
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})
}

Настройка вебхуков

Вебхуки настраиваются через API Kinescope. Укажите URL вашего эндпоинта, который будет принимать уведомления.

Важно: Ваш эндпоинт должен возвращать HTTP 200 в ответ на успешную обработку вебхука. Если Kinescope получит ошибку (4xx, 5xx), он может повторить запрос.

Безопасность

Рекомендуется проверять подлинность вебхуков:

  • Проверяйте источник запроса — убедитесь, что запрос приходит от Kinescope
  • Используйте HTTPS — вебхуки должны отправляться на защищённые URL
  • Валидируйте данные — проверяйте формат и обязательные поля в запросе

Всё! Теперь вы можете настроить вебхуки и автоматизировать процессы в вашей системе.

Что дальше?

После настройки вебхуков рекомендуем:

  1. Общие правила API — авторизация и формат запросов
  2. Справочник API — полная документация API для настройки вебхуков
  3. Загрузка файлов через API — автоматическая загрузка видео

Остались вопросы? Напишите в чат поддержки — специалисты помогут!