Коды ошибок WebSocket
Прикладные ошибки приходят как сообщение type: "error":
{
"type": "error",
"code": "INVALID_MESSAGE",
"message": "Missing \"type\" field in subscribe message",
"timestamp": 1714123200000
}
Прикладные коды
| Код | Условие | Что делать |
|---|---|---|
UNAUTHORIZED | API-ключ не передан или невалиден | Передать корректный ?apiKey=... при подключении |
INVALID_JSON | Тело сообщения не валидный JSON | Проверить сериализацию |
INVALID_MESSAGE | В сообщении не хватает обязательного поля (action, type, sportSlug, matchId) либо невалидный matchId | Свериться с Subscribe |
UNKNOWN_ACTION | action не один из subscribe / unsubscribe / ping | Поддерживаются только эти три |
NO_ACCESS | Тарифный план пользователя не покрывает запрошенный спорт | Сменить тариф; см. Rate limits |
SUBSCRIPTION_FAILED | Внутренняя ошибка при добавлении подписки | Retry; если повторяется — обратиться в support |
UNSUBSCRIBE_FAILED | Внутренняя ошибка при удалении подписки | Аналогично |
INTERNAL_ERROR | Прочая внутренняя ошибка | Retry с задержкой |
Коды передаются в верхнем регистре с подчёркиваниями. На клиенте можно сравнивать msg.code === 'NO_ACCESS'.
Коды закрытия соединения
Сервер использует стандартные WebSocket close codes:
| Close code | Причина | Когда |
|---|---|---|
1000 | Connection timeout due to inactivity | 120 секунд без активности — см. Overview → Heartbeat |
1001 | Server shutting down | Graceful shutdown сервера |
1008 | Unauthorized: Missing/Invalid API key | Невалидный/отсутствующий ключ при connect |
1008 | Access revoked | API-ключ удалён из Redis в процессе работы |
1008 | Connection limit exceeded. Oldest connection closed. | Открыто > 5 соединений с одним ключом — сервер закрывает старейшее |
1011 | Internal server error | Непредвиденная ошибка в обработчике connect |
После любого close — клиент должен переподключиться с экспоненциальным backoff (1s → 2s → 4s …).
Heartbeat и реальный pong
Сервер шлёт native WebSocket ping-frame каждые 30 секунд. Стандартные клиенты (ws в Node.js, websockets в Python, браузерный WebSocket) отвечают pong автоматически — отдельный код не нужен.
⚠️ Прикладной ping
{ "action": "ping" }— это другой механизм: он возвращает{ "type": "pong" }JSON и нужен, например, чтобы проверить, что обработчик сообщений жив. На native heartbeat он не влияет.
Если ни native pong, ни любые входящие сообщения от клиента не приходят на сервер 120 секунд — соединение закрывается с close code 1000.
Recovery-стратегия
function connect(retryDelayMs = 1000) {
const ws = new WebSocket('wss://ws.api.api-sport.ru/?apiKey=' + KEY);
ws.addEventListener('close', (event) => {
// Любой close, кроме 1008 (auth) — пытаемся переподключиться
if (event.code === 1008) {
console.error('Auth/access error, stop reconnecting:', event.reason);
return;
}
setTimeout(() => connect(Math.min(retryDelayMs * 2, 60000)), retryDelayMs);
});
ws.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'connected') retryDelayMs = 1000; // сбрасываем backoff
// … остальная логика
});
}