Pterohost docs

REST API и Web Query TeamSpeak 6: подключение, API-ключи, примеры

Как включить транспорты SSH/HTTP/HTTPS в TeamSpeak 6, создать API-ключ с ограниченными правами вместо пароля ServerAdmin, и обращаться к серверу через curl и Python requests.

TeamSpeak 6 убрал классический telnet-протокол ServerQuery и заменил его набором транспортов поверх SSH и HTTP(S), плюс добавил API-ключи с ограниченными правами вместо единого пароля serveradmin. По сути это тот же язык команд, что и в TeamSpeak 3 ServerQuery, но доставленный по-другому и с более гибкой моделью доступа. Проблема в том, что схема ещё в бете и меняется от сборки к сборке - часть деталей эндпоинтов не задокументирована стабильно даже на официальном форуме сообщества. В этой статье - как включить транспорты, создать ограниченный API-ключ, и как обращаться к серверу через curl и Python на подтверждённых базовых примерах, с честными оговорками там, где схема ещё нестабильна.

Транспорты: SSH, HTTP, HTTPS

TS6 предлагает три способа подключиться к query-интерфейсу сервера, и все три включаются и настраиваются раздельно:

ТранспортФлаг включенияПеременная окруженияФлаг порта
SSH-query--query-ssh-enableTSSERVER_QUERY_SSH_ENABLED--query-ssh-port
HTTP web-query--query-http-enableTSSERVER_QUERY_HTTP_ENABLED--query-http-port
HTTPS web-query--query-https-enableTSSERVER_QUERY_HTTPS_ENABLED--query-https-port

Официальные представители проекта на форуме community.teamspeak.com подтверждали, что “запрос со всеми командами, знакомыми по серверам TeamSpeak 3, всё ещё доступен” через SSH и HTTP/HTTPS - именно эти два семейства транспортов заменили голый telnet. По умолчанию используются порты, унаследованные от WebQuery TeamSpeak 3: 10022 для SSH-query, 10080 для HTTP и 10443 для HTTPS - но проверяйте актуальные значения через --help вашей сборки, так как порты по умолчанию могут отличаться от версии к версии.

Включить нужный транспорт можно и в Docker-запуске через переменные окружения:

docker run -d \
  --name teamspeak-server \
  -p 9987:9987/udp \
  -p 10022:10022 \
  -p 10080:10080 \
  -e TSSERVER_LICENSE_ACCEPTED=accept \
  -e TSSERVER_QUERY_SSH_ENABLED=true \
  -e TSSERVER_QUERY_HTTP_ENABLED=true \
  -v teamspeak-data:/var/tsserver/ \
  teamspeaksystems/teamspeak6-server:latest

В продакшне HTTPS-транспорт предпочтительнее HTTP - подробности в разделе про безопасность ниже.

Аутентификация: API-ключи вместо пароля serveradmin

Базовый доступ к query-интерфейсу по-прежнему завязан на аккаунт ServerAdmin (в TS3 - serveradmin), учётные данные которого выдаются или генерируются при первом запуске сервера - подробно об этом в статье про установку TeamSpeak 6. Но для интеграций и ботов TS6 предлагает более гибкий механизм - API-ключи с ограниченным scope и временем жизни, создаваемые изнутри уже открытой query-сессии под ServerAdmin.

Судя по обсуждениям на официальном форуме сообщества, ключ создаётся командой вида:

apikeyadd scope=manage lifetime=0

где scope определяет уровень доступа ключа, а lifetime - время жизни в секундах (значение по умолчанию/бессрочное поведение стоит уточнять в справке вашей сборки). Это подтверждённый факт существования такой команды, но не гарантированно стабильный синтаксис - разработчик проекта прямо говорил на форуме, что в TS6 “нет API в классическом смысле, а есть учётные записи, которые могут подключаться к серверу и использоваться для мониторинга или управления” - то есть API-ключ по сути создаёт ограниченную query-учётку, а не токен в отрыве от концепции пользователя. Перед использованием в проде сверьте точный синтаксис и доступные значения scope с doc/webquery.md внутри вашего дистрибутива сервера или с --help.

Полученный ключ передаётся в HTTP/HTTPS-запросах заголовком:

x-api-key: ВАШ_КЛЮЧ

Базовая структура запросов

Схема эндпоинтов всё ещё меняется между бета-сборками, поэтому не переносите слепо примеры из статей, написанных под другую версию - в разных источниках встречаются варианты путей вида /whoami, /1/clientlist, /version, где префикс версии API (1, v1 или отсутствие префикса вовсе) отличается от сборки к сборке. Общий подход стабилен: HTTP-запрос на порт web-query, заголовок с API-ключом, ответ в JSON. Актуальный список доступных путей для вашей установки правильнее всего смотреть в поставляемом файле документации (doc/webquery.md) или, если ваша сборка его поднимает, в Swagger-интерфейсе на том же HTTP-порту.

Проверочный запрос, чтобы убедиться, что ключ и транспорт работают - обычно это будет что-то вроде опроса собственной идентичности ключа:

curl -H "x-api-key: ВАШ_КЛЮЧ" "http://ваш-сервер:10080/whoami"

Если получаете JSON-ответ с данными о текущей query-сессии, а не ошибку 401/403 - транспорт и ключ настроены верно, и дальше можно переходить к прикладным командам.

Pterohost - серверы TeamSpeak 6 с открытыми query-портами и настроенным firewall из коробки, не нужно поднимать транспорты вручную. Промокод 4START даёт -20% на первый заказ. Арендовать TeamSpeak 6

Примеры на curl

Список подключённых клиентов (путь и версия префикса зависят от сборки - в примере используется распространённый в обсуждениях сообщества вариант):

curl -H "x-api-key: ВАШ_КЛЮЧ" \
  "http://ваш-сервер:10080/1/clientlist"

Кик клиента (структура тела запроса - обобщённый пример, сверяйте точные имена полей с документацией вашей сборки):

curl -X POST \
  -H "x-api-key: ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"clid": 12, "reason": "Нарушение правил"}' \
  "http://ваш-сервер:10080/1/clientkick"

Бан по IP или уникальному идентификатору клиента следует той же логике - POST-запрос с JSON-телом на соответствующий путь. Прежде чем использовать команды бана/кика в продакшне, обязательно протестируйте их на тестовом сервере той же версии, что и продакшн - синтаксис полей мог измениться в последней бете.

Примеры на Python requests

Минимальный клиент для получения списка клиентов и отправки сообщения в канал:

import requests

BASE_URL = "http://ваш-сервер:10080"
API_KEY = "ВАШ_КЛЮЧ"
HEADERS = {"x-api-key": API_KEY}


def get_clients():
    resp = requests.get(f"{BASE_URL}/1/clientlist", headers=HEADERS, timeout=5)
    resp.raise_for_status()
    return resp.json()


def kick_client(clid: int, reason: str):
    payload = {"clid": clid, "reason": reason}
    resp = requests.post(
        f"{BASE_URL}/1/clientkick",
        headers=HEADERS,
        json=payload,
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()


def send_channel_message(cid: int, text: str):
    payload = {"cid": cid, "msg": text}
    resp = requests.post(
        f"{BASE_URL}/1/sendtextmessage",
        headers=HEADERS,
        json=payload,
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()


if __name__ == "__main__":
    clients = get_clients()
    print(f"Подключено клиентов: {len(clients)}")

Точные имена путей и полей в примерах выше (clid, cid, msg, /1/clientkick, /1/sendtextmessage) даны по аналогии с известной структурой команд ServerQuery TS3 и упоминаниями в обсуждениях сообщества TS6 - перед использованием в проде обязательно сверьте их с документацией установленной у вас версии сервера. Такая осторожность оправдана: между бета-сборками уже менялась обработка прав и структура ответов клиентского списка, значит могли поменяться и поля запросов.

Обработка ошибок

По подтверждённым сведениям с официального форума, REST API TS6 возвращает стандартные HTTP-коды состояния:

КодПричинаЧто делать
401Неверный или истёкший API-ключПроверить значение ключа, пересоздать через query-сессию
403Недостаточно прав у ключаПроверить scope ключа, создать новый с нужным уровнем доступа
404Несуществующий путь или версия APIСвериться с doc/webquery.md вашей сборки
500Внутренняя ошибка сервераСмотреть логи сервера, возможен баг конкретной беты

Оборачивайте вызовы в try/except с проверкой статус-кода (в примере Python это делает raise_for_status()) и логируйте полное тело ответа при ошибке - в бета-версии полезно сохранять сырые ответы сервера, чтобы позже понять, была ли проблема в вашем коде или в баге конкретной сборки.

Безопасность: как не слить доступ к серверу

REST API даёт управление сервером не хуже полного пароля serveradmin, если выдать ключу широкий scope - относитесь к нему соответственно.

  • Не публикуйте ключ в открытом виде. Не коммитьте его в git, не передавайте в URL (только в заголовке), не логируйте целиком на проде.
  • Используйте HTTPS-транспорт вместо HTTP в продакшне - HTTP передаёт заголовок с ключом в открытом виде, и его можно перехватить на пути между вашим кодом и сервером.
  • Ограничивайте доступ к query-портам по IP через firewall - если бот или скрипт обращается к API с известного статического адреса, не открывайте порт 10080/10443/10022 всему интернету. Базовые правила для игровых серверов разобраны в статье про firewall UFW.
  • Выдавайте ключам минимальный scope под конкретную задачу - боту для логирования онлайна не нужны права на управление правами и удаление каналов.
  • Ограничивайте время жизни ключа, если сценарий это позволяет, вместо бессрочных ключей на всё - в бете, где схема ещё меняется, скомпрометированный бессрочный ключ с широким доступом - больший риск, чем в стабильном протоколе.

Pterohost - серверы TeamSpeak 6 с NVMe и DDoS-защитой Guard Rise, готовые под интеграции через REST API. Промокод 4START даёт -20% на первый заказ. Заказать TeamSpeak 6

Часто задаваемые вопросы

Чем REST API / Web Query TeamSpeak 6 отличается от ServerQuery TeamSpeak 3?

Набор команд похож, но транспорт другой: TS3 использует сырой telnet-протокол на порту 10011, а TS6 убрал telnet и открывает тот же функционал через SSH-query и HTTP/HTTPS web-query. Дополнительно TS6 добавляет API-ключи с ограниченным набором прав вместо единого пароля serveradmin.

Как создать API-ключ в TeamSpeak 6?

Ключ создаётся через query-сессию (SSH или HTTP) под учётной записью ServerAdmin командой генерации ключа с параметрами области действия и времени жизни, например apikeyadd scope=manage lifetime=0. Точный синтаксис команды может отличаться между бета-сборками - сверяйтесь с doc/webquery.md вашей версии сервера.

Какой порт использует REST API / Web Query TeamSpeak 6?

По умолчанию HTTP web-query слушает порт 10080, HTTPS - 10443, а SSH-query - 10022, это те же порты, что исторически использовались под WebQuery в TeamSpeak 3. Транспорты включаются раздельно флагами —query-http-enable, —query-https-enable и —query-ssh-enable или соответствующими переменными окружения, и порты в конкретной сборке стоит проверять через —help.

Безопасно ли открывать REST API TeamSpeak 6 в интернет?

Не рекомендуется без ограничений. HTTP-транспорт передаёт API-ключ в открытом виде - используйте HTTPS в проде, ограничивайте доступ к query-портам через firewall по IP доверенных систем, и выдавайте ключам минимально необходимый scope вместо полного доступа.

Можно ли получить полную документацию по эндпоинтам REST API TeamSpeak 6?

Официальная документация неполная и меняется вместе с бета-сборками: она поставляется файлом doc/webquery.md внутри дистрибутива сервера, часть версий также поднимает Swagger-интерфейс на HTTP-порту. Точные пути эндпоинтов лучше проверять именно в файлах вашей установленной версии, а не в сторонних гайдах, написанных под другую сборку.