Перейти к основному содержимому
API v3

ETR API

Полная документация API для Eblan Trouble Register. Поддерживается только API v3.

Что такое ETR?

ETR (Eblan Trouble Register) — это бан-реестр для игровых серверов, управляемый сообществом. Серверы регистрируются в системе, и когда достаточное количество серверов голосует за бан игрока, он автоматически добавляется в чёрный список ETR.

Все зарегистрированные серверы могут проверять игроков по базе ETR при подключении и голосовать за добавление проблемных игроков. Когда 10% всех верифицированных серверов проголосуют за игрока, он автоматически блокируется.

Быстрый старт

1

Войдите через Steam

Создайте аккаунт, войдя через свой аккаунт Steam.

2

Зарегистрируйте сервер

Перейдите в Настройки → Серверы и зарегистрируйте игровой сервер. Вы сразу получите API-ключ.

3

Пройдите верификацию

Администратор верифицирует ваш сервер. После верификации сервер сможет голосовать за игроков.

4

Используйте API

Проверяйте игроков при подключении через GET /etr/v3/status/{steamId} и голосуйте через POST /etr/v3/vote/{steamId}.

Регистрация сервера через API (для аддонов)

Аддоны игровых серверов могут регистрироваться автоматически с помощью setup-токена:

1. Сгенерируйте setup-токен (из браузера, Настройки → Серверы):

POST https://sellingvika.party/etr/v3/auth/setup-token
(требуется сессия браузера — авторизованный пользователь)

2. Аддон регистрирует сервер с токеном:

POST https://sellingvika.party/etr/v3/servers/register
Header: Content-Type: application/json
Body: {
  "setup_token": "YOUR_TOKEN_HERE",
  "name": "My Game Server",
  "ip": "123.45.67.89",
  "port": "27015",
  "app_id": "4020",
  "description": "Optional description"
}

Ответ:

{
  "status": "registered",
  "server": {"id": 42, "name": "My Game Server", "ip": "123.45.67.89", "port": "27015", "app_id": "4020", "verified": false},
  "api_key": "abc123...64chars...",
  "api_secret": "xyz789...64chars...",
  "message": "Server registered. Save your key and secret."
}

Setup token is valid for 1 hour and can be reused to register multiple servers (within your account limits). You can generate 1 token per hour. Server must be verified by admin before it can vote.

Аутентификация

Все API-запросы (кроме регистрации сервера) требуют API-ключ. Передайте его одним из двух способов:

Заголовок (рекомендуется):

X-API-Key: your_64_char_key_here

Bearer-токен:

Authorization: Bearer your_64_char_key_here

POST-запросы с телом должны включать Content-Type: application/json.

HMAC-заголовки безопасности (опционально)

HMAC-подпись можно включить для каждого API-ключа в Настройках. При включении запросы должны содержать: X-Signature, X-Timestamp, X-Nonce заголовки. POST/PUT/PATCH с телом также требуют X-Body-SHA256. User-Agent рекомендуется, но не обязателен (игровые движки вроде Source/GMod не поддерживают кастомные заголовки). Подробности см. на вкладке Безопасность.

Типы API-ключей

ТипДоступКак получить
Серверный ключПроверка статуса, голосование, heartbeat — полный доступЗарегистрируйте сервер в Настройках или через setup token аддона
Автономный ключПроверка статуса (status, status-bulk). Также может добавлять игроков, если админ выдал разрешение can_add_users.Создайте в Настройках — макс. 1 на аккаунт

Автономные ключи не могут голосовать или отправлять heartbeat — для этого нужен серверный ключ. Добавление игроков (add, add-bulk) требует разрешения can_add_users от админа и работает с любым типом ключа.

Limits

  • Daily requests: 5,000 per account (all keys combined). Admin can adjust.
  • Standalone keys: Max 1 per account.
  • Registered servers: Max 10 per account.
  • Bulk status check: Up to 100 Steam IDs per request (counts as 1 request).
  • Per-minute: 100 requests per key per minute.

Как работает голосование

ETR использует систему голосования на уровне серверов:

  • Каждый **верифицированный** сервер может проголосовать **один раз** за игрока (Steam ID).
  • Голос означает: «этот сервер хочет добавить этого игрока в ETR».
  • Когда **10% всех верифицированных серверов** проголосуют за игрока, он **автоматически** добавляется в ETR.
  • Минимальный порог — 2 сервера (даже если 10% составляет меньше).
  • Когда игрок уже в ETR, за него нельзя голосовать повторно.

Пример: Если верифицированных серверов 50, порог = ceil(50 × 0.10) = 5. Когда 5 разных серверов проголосуют за игрока, он автоматически добавляется в ETR.

GET/etr/v3/status/{steamId}

Проверить, находится ли Steam ID в ETR. Возвращает true/false с причиной. Используйте ?reason= для фильтрации по категориям (напр. кикать только читеров, но не грифферов).

Доступ: Любой активный API-ключ

Параметры:

steamId — Steam64 ID, Steam2, Steam3 или URL профиля.
reason — необязательный фильтр, slug через запятую (напр. ?reason=cheating,ddos). Если указан, status=true только когда бан совпадает с одной из причин. Без фильтра — true при любом бане.
Запрос
GET /etr/v3/status/76561190000000001
X-API-Key: abcdef1234567890...
Ответ
{
  "status": true,
  "steam_id": "76561190000000001",
  "created_from": "Auto (server votes)",
  "reason": "Cheating / Exploits",
  "reason_slug": "cheating",
  "created_at": "2026-03-20 14:30:00"
}
POST/etr/v3/status-bulk

Проверить до 100 Steam ID за один запрос. Считается как один API-запрос. Поддерживает ?reason= фильтр как и status.

Доступ: Любой активный API-ключ

Параметры:

Тело: steam_ids — массив Steam ID (или строка через запятую). Макс. 100.
reason — необязательный фильтр, slug через запятую (напр. "cheating,ddos"). Фильтрует результаты по причине бана.
Запрос
POST /etr/v3/status-bulk
X-API-Key: abcdef1234567890...
Content-Type: application/json

{
  "steam_ids": [
    "76561190000000001",
    "76561190000000002"
  ]
}
Ответ
{
  "results": [
    {"steam_id": "76561190000000001", "status": true, "reason": "Cheating / Exploits", "reason_slug": "cheating"},
    {"steam_id": "76561190000000002", "status": false}
  ]
}
POST/etr/v3/vote/{steamId}

Ваш сервер голосует за добавление игрока в ETR. Каждый сервер может проголосовать один раз за игрока. Когда 10% верифицированных серверов проголосуют, игрок автоматически добавляется. Сервер должен быть верифицирован администратором.

Доступ: Только API-ключ верифицированного сервера

Параметры:

steamId — Steam64 ID (в URL или в теле как steam_id).
reason — обязательный, slug из GET /etr/v3/reasons (напр. "cheating", "ddos").
comment — необязательная строка (макс. 500).
Запрос
POST /etr/v3/vote/76561190000000001
X-API-Key: abcdef1234567890...
Content-Type: application/json

{
  "reason": "cheating",
  "comment": "Aimbot detected by anti-cheat"
}
Ответ
{
  "status": "voted",
  "steam_id": "76561190000000001",
  "server": "My Game Server",
  "vote_count": 3,
  "threshold": 5,
  "added_to_etr": false,
  "message": "Vote recorded."
}
GET/etr/v3/votings

Список всех активных голосований — игроки, за которых голосовали серверы, но ещё не добавленных в ETR. Показывает количество голосов, порог и процент.

Доступ: Только серверный API-ключ

Параметры:

limit — необязательный параметр (1-500, по умолчанию 100).
Запрос
GET /etr/v3/votings?limit=10
X-API-Key: abcdef1234567890...
Ответ
{
  "votings": [
    {
      "target_steam_id": "76561190000000001",
      "vote_count": 3,
      "threshold": 5,
      "verified_servers": 50,
      "progress": 60
    }
  ],
  "threshold": 5,
  "verified_servers": 50
}
GET/etr/v3/key-info

Возвращает информацию о вашем API-ключе: статус верификации, разрешения.

Доступ: Любой активный API-ключ

Параметры:

Без параметров.
Запрос
GET /etr/v3/key-info
X-API-Key: abcdef1234567890...
Ответ
{
  "verified": true,
  "can_add_users": false
}
POST/etr/v3/servers/register

Зарегистрировать новый сервер с помощью setup-токена из настроек аккаунта. Возвращает информацию о сервере и API-учётные данные. Токен можно использовать несколько раз в течение 1 часа.

Доступ: Setup-токен (без API-ключа)

Параметры:

setup_token — обязательный (или заголовок X-Setup-Token).
name — обязательная строка (2-255 символов).
ip — обязательная строка (IP сервера).
port — необязательная строка (1-5 цифр, например 27015).
app_id — обязательная строка (Steam App ID, например 4020 для Garry's Mod).
description — необязательная строка (макс. 1000).
Запрос
POST /etr/v3/servers/register
Content-Type: application/json

{
  "setup_token": "your_64_char_token...",
  "name": "My Game Server",
  "ip": "123.45.67.89",
  "port": "27015",
  "app_id": "4020"
}
Ответ
{
  "status": "registered",
  "server": {"id": 42, "name": "My Game Server", "app_id": "4020"},
  "api_key": "new_64_char_key...",
  "api_secret": "new_64_char_secret..."
}
GET/POST/etr/v3/add/{steamId}

Напрямую добавить Steam ID в ETR (в обход голосования). Доступно для любого ключа (серверного или автономного) с разрешением can_add_users от администратора.

Доступ: Любой ключ с разрешением can_add_users

Параметры:

steamId — Steam64 ID.
reason — обязательный, slug из GET /etr/v3/reasons (напр. "cheating", "ddos", "scam").
Запрос
POST /etr/v3/add/76561190000000001
X-API-Key: admin_key_here...
Content-Type: application/json

{"reason": "cheating"}
Ответ
{
  "status": "added",
  "steam_id": "76561190000000001",
  "reason": "cheating",
  "reason_name": "Cheating / Exploits"
}
POST/etr/v3/add-bulk

Массовое добавление до 200 Steam ID в ETR. Возвращает количество добавленных, уже имеющихся и невалидных ID.

Доступ: Любой ключ с разрешением can_add_users

Параметры:

steam_ids — массив или строка через запятую (макс. 200).
reason — обязательный, slug из GET /etr/v3/reasons (напр. "cheating", "ddos").
Запрос
POST /etr/v3/add-bulk
X-API-Key: admin_key_here...
Content-Type: application/json

{
  "steam_ids": ["76561190000000001", "76561190000000002"],
  "reason": "ddos"
}
Ответ
{
  "added": ["76561190000000001"],
  "already_in_etr": ["76561190000000002"],
  "invalid": [],
  "message": "1 added, 1 already in ETR, 0 invalid."
}
POST/etr/v3/heartbeat

Сервер отправляет heartbeat для подтверждения онлайн-статуса. Ответ содержит точное количество секунд до следующего heartbeat (next_heartbeat_in). Ваш аддон должен использовать это значение как задержку перед следующим вызовом — сервер авторитативен по времени и включает джиттер для предотвращения одновременных запросов.

Доступ: Любой активный API-ключ (с сервером)

Параметры:

Тело не требуется. Ответ включает server_time, server_timestamp, next_heartbeat_at и next_heartbeat_in (секунды).
Запрос
POST /etr/v3/heartbeat
X-API-Key: abcdef1234567890...
X-Signature: hmac_hex...
X-Timestamp: 1711929600
X-Nonce: unique-random-string
User-Agent: MyAddon/1.0
Ответ
{
  "status": "ok",
  "server": "My Game Server",
  "online": true,
  "server_time": "2026-03-24T14:30:00+00:00",
  "server_timestamp": 1711288200,
  "last_active_at": "2026-03-24T14:30:00+00:00",
  "next_heartbeat_at": "2026-03-24T17:33:45+00:00",
  "next_heartbeat_in": 11025,
  "message": "Heartbeat accepted. Send next heartbeat in 11025 seconds."
}
GET/etr/v3/time

Возвращает текущее серверное время. Используйте при запуске аддона для расчёта смещения часов для HMAC-подписи. Аутентификация не требуется.

Доступ: Публичный (ключ не требуется)

Параметры:

Без параметров.
Запрос
GET /etr/v3/time
Ответ
{
  "timestamp": 1711929600,
  "iso": "2026-03-25T14:00:00+00:00",
  "timezone": "UTC"
}
GET/etr/v3/reasons

Список всех категорий и причин ETR. Используйте при запуске аддона для заполнения выпадающего списка причин. Причины сгруппированы по категориям (security, cheating, fraud, community, system). Каждая причина имеет slug, который передаётся в add/add-bulk/vote.

Доступ: Публичный (ключ не требуется)

Параметры:

Без параметров.
Запрос
GET /etr/v3/reasons
Ответ
{
  "categories": [
    {
      "category": "security",
      "label": "Security & Infrastructure",
      "label_ru": "Безопасность и инфраструктура",
      "reasons": [
        {"slug": "crash_clients_menus", "name": "Crash clients / menus", "name_ru": "Краш клиентов / меню"},
        {"slug": "ddos", "name": "DDoS / Flooding", "name_ru": "DDoS / флуд"}
      ]
    },
    {"category": "cheating", "label": "Cheating & Exploits", "reasons": [...]},
    {"category": "fraud", "label": "Fraud & Theft", "reasons": [...]},
    {"category": "community", "label": "Community Harm", "reasons": [...]},
    {"category": "system", "label": "System", "reasons": [...]}
  ]
}
GET/etr/v3/servers

Список всех верифицированных серверов с онлайн-статусом. Используйте для Discord-ботов, дашбордов, мониторинга. Сервер считается «онлайн», если он отправил API-запрос или heartbeat в последние 5 минут.

Доступ: Публичный (ключ не требуется)

Параметры:

Без параметров.
Запрос
GET /etr/v3/servers
Ответ
{
  "servers": [
    {
      "id": 1,
      "name": "My Server",
      "ip": "1.2.3.4",
      "port": "27015",
      "app_id": "4020",
      "online": true,
      "last_active_at": "2026-03-24T14:30:00+00:00"
    }
  ],
  "total": 1,
  "online": 1
}
GET/etr/v3/servers/{id}/status

Получить статус одного верифицированного сервера по ID. Возвращает информацию о сервере и его онлайн/офлайн-статус.

Доступ: Публичный (ключ не требуется)

Параметры:

id — ID сервера (целое число, в URL).
Запрос
GET /etr/v3/servers/42/status
Ответ
{
  "id": 42,
  "name": "My Server",
  "ip": "1.2.3.4",
  "port": "27015",
  "app_id": "4020",
  "online": true,
  "last_active_at": "2026-03-24T14:30:00+00:00",
  "verified_at": "2026-03-20T10:00:00+00:00"
}

Лимиты запросов

ЛимитЗначениеОбласть
Глобальный лимит по IP180/minНа IP-адрес
Лимит ключа в минуту100/minНа API-ключ
Дневной лимит пользователянастраиваемыйНа аккаунт (все ключи)

Заголовки ответа

Каждый API-ответ включает эти заголовки:

X-API-Version: 3
X-Request-Id: unique-uuid-per-request
X-Server-Time: 1711929600         (unix timestamp — use to sync your clock)
X-Security-Policy: hmac-optional; nonce-if-hmac; body-hash-if-hmac; ua-recommended
X-RateLimit-Limit: 10000          (daily limit)
X-RateLimit-Remaining: 9999       (remaining today)
X-RateLimit-Reset: 1711929600     (unix timestamp, end of day)
X-RateLimit-Minute-Limit: 100     (per-minute limit)
X-RateLimit-Minute-Remaining: 99  (remaining this minute)
Cache-Control: no-store
X-Content-Type-Options: nosniff

Тайминг Heartbeat

Эндпоинт heartbeat возвращает точное время для следующего heartbeat. Ваш аддон должен следовать инструкциям сервера по таймингу:

// After receiving a heartbeat response:
local nextIn = response.next_heartbeat_in  // e.g. 11025 seconds
timer.Simple(nextIn, function()
    sendHeartbeat()  // send next heartbeat after exactly `nextIn` seconds
end)

Сервер добавляет случайный джиттер (0-5 минут) к базовому интервалу, чтобы предотвратить одновременные запросы. Всегда используйте next_heartbeat_in из ответа вместо захардкоженного интервала.

HMAC-подпись РЕКОМЕНДУЕТСЯ

HMAC-подпись необязательна, но настоятельно рекомендуется. Её можно включить или отключить для каждого API-ключа в Настройки → Серверы. При включении каждый запрос должен содержать следующие заголовки безопасности:

ЗаголовокОбязательныйОписание
X-SignatureHMAC вкл.HMAC-SHA256 hex-дайджест (см. формулу ниже)
X-TimestampHMAC вкл.Unix-временная метка, должна быть в пределах **2 минут** от серверного времени
X-NonceHMAC вкл.Уникальная случайная строка, 16-128 символов. Каждый nonce действителен один раз в 10-минутном окне
X-Body-SHA256HMAC вкл. + POST/PUT/PATCHSHA-256 hex-дайджест сырого тела запроса
User-AgentРекомендуетсяНеобязателен, но рекомендуется для диагностики. Идентифицирует ваш аддон/клиент (напр. MyAddon/1.0)

Формула подписи

Signature = HMAC-SHA256(
  key:     your_api_secret,
  message: "METHOD:path:body:timestamp"
)

-- METHOD  = uppercase HTTP method (GET, POST, etc.)
-- path    = request path without domain (e.g. "etr/v3/status/76561190000000001")
-- body    = raw request body (empty string "" for GET requests)
-- timestamp = same value as X-Timestamp header

Example:
  HMAC-SHA256(secret, "POST:etr/v3/vote/76561190000000001:{\"reason\":\"cheat\"}:1711929600")

For GET requests (no body):
  HMAC-SHA256(secret, "GET:etr/v3/status/76561190000000001::1711929600")

Синхронизация часов

X-Timestamp должен быть в пределах **2 минут** от времени сервера ETR. Если часы вашей машины сбиты, запросы будут отклонены с timestamp_expired.

Два способа получить серверное время:

1. Специальный эндпоинт (аутентификация не требуется):

GET https://sellingvika.party/etr/v3/time

Response: {
  "timestamp": 1711929600,
  "iso": "2026-03-25T14:00:00+00:00",
  "timezone": "UTC"
}

2. Заголовок ответа (возвращается с каждым API-ответом):

X-Server-Time: 1711929600

Вызовите GET /etr/v3/time при запуске аддона для расчёта смещения между вашими часами и сервером, затем применяйте это смещение при генерации X-Timestamp.

Примеры кода

JavaScriptNode.js / Браузер (с fetch)
const crypto = require("crypto");  // Node.js built-in

const API_KEY    = "your_64_char_api_key";
const API_SECRET = "your_64_char_api_secret";
const BASE_URL   = "https://sellingvika.party";

// Step 1: sync clock on startup
let timeOffset = 0;
async function syncClock() {
  const res = await fetch(`${BASE_URL}/etr/v3/time`);
  const data = await res.json();
  timeOffset = data.timestamp - Math.floor(Date.now() / 1000);
}

// Step 2: make signed API request
async function etrRequest(method, path, body = null) {
  const timestamp = String(Math.floor(Date.now() / 1000) + timeOffset);
  const nonce     = crypto.randomBytes(32).toString("hex");
  const bodyStr   = body ? JSON.stringify(body) : "";

  const headers = {
    "X-API-Key":  API_KEY,
    "User-Agent": "MyApp/1.0",
  };

  // HMAC signing (skip if HMAC disabled on your key)
  const payload   = `${method.toUpperCase()}:${path}:${bodyStr}:${timestamp}`;
  const signature = crypto.createHmac("sha256", API_SECRET)
                          .update(payload).digest("hex");
  headers["X-Signature"] = signature;
  headers["X-Timestamp"] = timestamp;
  headers["X-Nonce"]     = nonce;

  if (bodyStr) {
    headers["X-Body-SHA256"] = crypto.createHash("sha256")
                                     .update(bodyStr).digest("hex");
    headers["Content-Type"]  = "application/json";
  }

  const res = await fetch(`${BASE_URL}/${path}`, {
    method,
    headers,
    body: bodyStr || undefined,
  });
  return res.json();
}

// Usage
await syncClock();
const status = await etrRequest("GET", "etr/v3/status/76561190000000001");
console.log("In ETR:", status.status);
LuaИгровые серверы (Garry's Mod, FiveM и др.)
-- Uses HTTP() function (Garry's Mod) or your HTTP library
-- HMAC requires a sha256/hmac module (e.g. gmsv_hmac, luaossl, or pure-Lua impl)

local API_KEY    = "your_64_char_api_key"
local API_SECRET = "your_64_char_api_secret"
local BASE_URL   = "https://sellingvika.party"
local timeOffset = 0

-- Sync clock on startup
function ETR_SyncTime()
    http.Fetch(BASE_URL .. "/etr/v3/time", function(body)
        local data = util.JSONToTable(body)
        if data and data.timestamp then
            timeOffset = data.timestamp - os.time()
        end
    end)
end

-- Make an API request (User-Agent is optional — GMod sends "Half-Life 2" automatically)
function ETR_CheckPlayer(steamId, callback)
    http.Fetch(BASE_URL .. "/etr/v3/status/" .. steamId .. "?api_key=" .. API_KEY,
        function(body)
            local data = util.JSONToTable(body)
            if callback then callback(data) end
        end)
end

-- Example: check player on connect
hook.Add("PlayerAuthed", "ETR_Check", function(ply, steamId)
    ETR_CheckPlayer(steamId, function(data)
        if data and data.status == true then
            ply:Kick("You are in the ETR ban list.")
        end
    end)
end)
PythonDiscord-боты, скрипты, инструменты
import hashlib, hmac, json, secrets, time, requests

API_KEY    = "your_64_char_api_key"
API_SECRET = "your_64_char_api_secret"
BASE_URL   = "https://sellingvika.party"

# Sync clock once on startup
_srv = requests.get(f"{BASE_URL}/etr/v3/time").json()
_offset = _srv["timestamp"] - int(time.time())

def etr_request(method, path, body=None):
    ts       = str(int(time.time()) + _offset)
    body_str = json.dumps(body, separators=(",",":")) if body else ""
    payload  = f"{method.upper()}:{path}:{body_str}:{ts}"
    sig      = hmac.new(API_SECRET.encode(), payload.encode(),
                        hashlib.sha256).hexdigest()
    headers  = {
        "X-API-Key": API_KEY, "User-Agent": "MyBot/1.0",
        "X-Signature": sig, "X-Timestamp": ts,
        "X-Nonce": secrets.token_hex(32),
    }
    if body_str:
        headers["X-Body-SHA256"] = hashlib.sha256(body_str.encode()).hexdigest()
        headers["Content-Type"]  = "application/json"
    return requests.request(method, f"{BASE_URL}/{path}",
                            headers=headers, data=body_str or None).json()

# Check a player
print(etr_request("GET", "etr/v3/status/76561190000000001"))
cURLБыстрое тестирование из терминала (без HMAC)
# Simple status check (HMAC disabled on your key)
curl -s "https://sellingvika.party/etr/v3/status/76561190000000001" \
  -H "X-API-Key: your_api_key" \
  -H "User-Agent: curl/test"

# Get server time
curl -s "https://sellingvika.party/etr/v3/time"

Чек-лист безопасности

  • Никогда не вставляйте секреты в клиентский код. Храните API-секреты в конфигурационных файлах сервера, а не в Lua-скриптах, доступных игрокам.
  • Генерируйте новый nonce для каждого запроса. Используйте криптографическую случайность (16-128 символов). Повторно использованные nonce отклоняются с 409 nonce_reused.
  • Синхронизируйте часы. Call GET /etr/v3/time при запуске. Запросы с временными метками, отличающимися более чем на 2 минуты, отклоняются.
  • Используйте точную строку тела для подписи. Тело в HMAC-нагрузке должно совпадать с байтами, отправленными по сети. Не пересериализуйте JSON между подписью и отправкой.
  • Привязка IP (опционально). Вы можете ограничить API-ключ конкретными IP в Настройки → Серверы для дополнительной безопасности.

Common Use Cases

Game server addon (auto-kick banned players)

Register your server, get a server key. On player connect, call GET /etr/v3/status/{steamId}. If status: true, kick the player. Send heartbeats to stay online.

Discord bot (player lookup)

Create a standalone key. Use GET /etr/v3/status/{steamId} to check players. Standalone keys are read-only and perfect for bots.

Bulk check on map change

Use POST /etr/v3/status-bulk with up to 100 Steam IDs at once. Counts as 1 API request. Useful for re-checking all connected players.

Server status dashboard

No API key needed. GET /etr/v3/servers returns all verified servers with online status. Use for monitoring dashboards.

Ответы с ошибками

Все ошибки возвращают JSON с полем error и необязательным message.

HTTPКод ошибкиОписание
400missing_parameterОбязательный параметр не указан
400steamid_missingSteam ID не указан в URL или теле запроса
403invalid_keyAPI-ключ не найден или неактивен
403ip_not_allowedIP запроса не в списке разрешённых для ключа
403account_not_verifiedАккаунт не верифицирован (требуется Steam + email)
403unauthorizedУ ключа нет необходимого разрешения (напр., can_add_users)
403standalone_key_restrictedАвтономные ключи не имеют доступа к этому эндпоинту (голосование, heartbeat и серверные эндпоинты требуют серверный ключ)
403no_serverAPI-ключ не привязан к серверу (для голосования)
403server_not_verifiedСервер ожидает верификации администратором
403steamid_blockedЗащищённый Steam ID (голосование невозможно)
403hmac_requiredHMAC-подпись обязательна, но не предоставлена
400invalid_timestampX-Timestamp не является валидной Unix-временной меткой (должно быть целое число)
403timestamp_expiredX-Timestamp слишком далеко от серверного времени (макс. 2 мин)
403invalid_signatureПроверка HMAC-подписи не пройдена
400missing_nonceЗаголовок X-Nonce отсутствует (необходим для защиты от повторов)
400nonce_too_shortX-Nonce должен быть не менее 16 символов
400nonce_too_longX-Nonce должен быть не более 128 символов
400missing_body_hashЗаголовок X-Body-SHA256 отсутствует для POST/PUT/PATCH с телом
400body_hash_mismatchX-Body-SHA256 не совпадает с реальным хешем тела
missing_user_agentУстарело — User-Agent теперь необязателен (рекомендуется для диагностики)
409nonce_reusedX-Nonce уже использован (каждый запрос требует уникальный nonce)
415invalid_content_typePOST с телом должен использовать application/json
400missing_reasonSlug причины обязателен (используйте GET /etr/v3/reasons для списка)
422invalid_reasonНеизвестный slug причины (используйте GET /etr/v3/reasons для списка)
422invalid_steamidНе удалось распознать формат Steam ID
422validation_errorОшибка валидации запроса
429rate_limit_exceededПревышен лимит запросов в минуту
429daily_limit_exceededПревышен дневной лимит запросов

Пример ответа с ошибкой

{
  "error": "server_not_verified",
  "message": "Server must be verified by admin before voting.",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}