События
Как узнать, что запуск вышел на канал, заказ выполнен или срок подходит к концу.
Событие — запись о том, что случилось с объектом аккаунта: запуск вышел на канал, заказ выполнен, лимит подходит к концу. События позволяют не опрашивать API в ожидании перемен, а узнавать о них.
Получать события можно двумя способами: вебхуками — сразу на свой адрес, или списком GET /events, — и их удобно сочетать: вебхуки для скорости, список — чтобы догнать пропущенное.
События пишутся, только пока у аккаунта включён доступ к API. Хранятся 30 суток.
Типы
| Тип | Объект | Когда приходит |
|---|---|---|
run.live | запуск | Начался эфир, и запуск вышел на канал. Запуск, созданный во время эфира, сначала присылает run.waiting, а в течение минуты — run.live. Если в пуле сейчас нет места, у запуска status — waiting, пока место не освободится. |
run.waiting | запуск | Запуск создан или эфир закончился: запуск ждёт эфира. Зрители выйдут сами, когда эфир начнётся. У запуска status — waiting. |
run.stopped | запуск | Запуск завершён. Причина — в stop_reason объекта: остановлен владельцем, вышло время, истёк лимит, остановлен поддержкой. |
order.started | заказ | Заказ пошёл в работу, в том числе после паузы: заказ фолловеров «только в эфире» встаёт на паузу вне эфира и продолжается с его началом. |
order.completed | заказ | Заказ выполнен; у чат-ботов и чат-панели — истёк их срок. |
order.failed | заказ | Заказ не выполнен. Сумма возвращена на счёт. |
order.cancelled | заказ | Заказ отменён. |
limit.expiring | лимит (limit из аккаунта) | До конца личного лимита зрителей осталось не больше срока предупреждения. Когда лимит истечёт, зрители на каналах остановятся. |
api_key.expiring | ключ API | До конца срока ключа API осталось не больше срока предупреждения. Когда срок выйдет, запросы с ключом перестанут приниматься. |
Новые типы могут появляться в рамках версии. Событие незнакомого типа пропускайте.
Событие
{
"id": "evt_1024",
"type": "run.stopped",
"object_type": "run",
"created_at": "2026-09-30T12:00:00.000Z",
"data": {
"object": {
"id": "run_345",
"channel_id": "ch_12",
"channel_name": "example_channel",
"platform": "twitch",
"status": "stopped",
"stop_reason": "duration_elapsed",
"viewers": 20,
"started_at": "2026-09-30T08:00:00.000Z",
"stopped_at": "2026-09-30T12:00:00.000Z",
"duration_seconds": 14400
}
}
}| Поле | Что содержит |
|---|---|
id | Идентификатор события. По нему повтор одного события отличают от нового |
type | Тип события |
object_type | Вид объекта в data.object: run, order, limit, api_key |
created_at | Когда событие случилось |
data.object | Объект в том же виде, что в ответе на его запрос: запуск — как в GET /runs, заказ — как в GET /orders/{id} |
Статус объекта в событии — на момент события; прочие поля — на момент, когда событие появилось в списке, через несколько секунд после него. К тому времени, когда событие прочитано, объект мог измениться: например, запуск, вышедший на канал, уже ждёт следующего эфира. Текущее состояние возвращает запрос самого объекта.
Чтение списком
GET /events возвращает события от новых к старым в порядке их появления в списке, постранично; параметр type оставляет события одного типа. Одно событие — GET /events/{id}.
Событие, появившееся в списке позже, всегда стоит в нём раньше. Поэтому, чтобы обрабатывать события списком, достаточно запоминать id последнего обработанного события: читайте страницы от начала, пока не встретите его, и обрабатывайте прочитанное от старых к новым. Если это событие уже удалено по сроку хранения, starting_after с ним вернёт 404 resource_missing — читайте список с начала.
async function newEvents(lastSeenId) {
const fresh = [];
let after;
while (true) {
const url = new URL("https://api.skystream.su/app/v1/events");
url.searchParams.set("limit", "100");
if (after) url.searchParams.set("starting_after", after);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
const page = await response.json();
for (const event of page.data) {
if (event.id === lastSeenId) return fresh.reverse();
fresh.push(event);
}
if (!page.has_more) return fresh.reverse();
after = page.data[page.data.length - 1].id;
}
}Порядок и повторы
- Событие появляется в списке через несколько секунд после того, что оно описывает.
- События одного объекта идут в том порядке, в каком случились. События разных объектов, случившиеся почти одновременно, могут появиться в списке в другом порядке: время события — в
created_at. - Обрабатывайте событие так, чтобы повторная обработка ничего не ломала: запоминайте
idобработанных событий.