ETR API
Полная документация API для Eblan Trouble Register. Поддерживается только API v3.
Что такое ETR?
ETR (Eblan Trouble Register) — это бан-реестр для игровых серверов, управляемый сообществом. Серверы регистрируются в системе, и когда достаточное количество серверов голосует за бан игрока, он автоматически добавляется в чёрный список ETR.
Все зарегистрированные серверы могут проверять игроков по базе ETR при подключении и голосовать за добавление проблемных игроков. Когда 10% всех верифицированных серверов проголосуют за игрока, он автоматически блокируется.
Быстрый старт
Войдите через Steam
Создайте аккаунт, войдя через свой аккаунт Steam.
Зарегистрируйте сервер
Перейдите в Настройки → Серверы и зарегистрируйте игровой сервер. Вы сразу получите API-ключ.
Пройдите верификацию
Администратор верифицирует ваш сервер. После верификации сервер сможет голосовать за игроков.
Используйте 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"
}
Лимиты запросов
| Лимит | Значение | Область |
|---|---|---|
| Глобальный лимит по IP | 180/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-Signature | HMAC вкл. | HMAC-SHA256 hex-дайджест (см. формулу ниже) |
| X-Timestamp | HMAC вкл. | Unix-временная метка, должна быть в пределах **2 минут** от серверного времени |
| X-Nonce | HMAC вкл. | Уникальная случайная строка, 16-128 символов. Каждый nonce действителен один раз в 10-минутном окне |
| X-Body-SHA256 | HMAC вкл. + POST/PUT/PATCH | SHA-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.
Примеры кода
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);
-- 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)
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"))
# 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 | Код ошибки | Описание |
|---|---|---|
| 400 | missing_parameter | Обязательный параметр не указан |
| 400 | steamid_missing | Steam ID не указан в URL или теле запроса |
| 403 | invalid_key | API-ключ не найден или неактивен |
| 403 | ip_not_allowed | IP запроса не в списке разрешённых для ключа |
| 403 | account_not_verified | Аккаунт не верифицирован (требуется Steam + email) |
| 403 | unauthorized | У ключа нет необходимого разрешения (напр., can_add_users) |
| 403 | standalone_key_restricted | Автономные ключи не имеют доступа к этому эндпоинту (голосование, heartbeat и серверные эндпоинты требуют серверный ключ) |
| 403 | no_server | API-ключ не привязан к серверу (для голосования) |
| 403 | server_not_verified | Сервер ожидает верификации администратором |
| 403 | steamid_blocked | Защищённый Steam ID (голосование невозможно) |
| 403 | hmac_required | HMAC-подпись обязательна, но не предоставлена |
| 400 | invalid_timestamp | X-Timestamp не является валидной Unix-временной меткой (должно быть целое число) |
| 403 | timestamp_expired | X-Timestamp слишком далеко от серверного времени (макс. 2 мин) |
| 403 | invalid_signature | Проверка HMAC-подписи не пройдена |
| 400 | missing_nonce | Заголовок X-Nonce отсутствует (необходим для защиты от повторов) |
| 400 | nonce_too_short | X-Nonce должен быть не менее 16 символов |
| 400 | nonce_too_long | X-Nonce должен быть не более 128 символов |
| 400 | missing_body_hash | Заголовок X-Body-SHA256 отсутствует для POST/PUT/PATCH с телом |
| 400 | body_hash_mismatch | X-Body-SHA256 не совпадает с реальным хешем тела |
| — | missing_user_agent | Устарело — User-Agent теперь необязателен (рекомендуется для диагностики) |
| 409 | nonce_reused | X-Nonce уже использован (каждый запрос требует уникальный nonce) |
| 415 | invalid_content_type | POST с телом должен использовать application/json |
| 400 | missing_reason | Slug причины обязателен (используйте GET /etr/v3/reasons для списка) |
| 422 | invalid_reason | Неизвестный slug причины (используйте GET /etr/v3/reasons для списка) |
| 422 | invalid_steamid | Не удалось распознать формат Steam ID |
| 422 | validation_error | Ошибка валидации запроса |
| 429 | rate_limit_exceeded | Превышен лимит запросов в минуту |
| 429 | daily_limit_exceeded | Превышен дневной лимит запросов |
Пример ответа с ошибкой
{
"error": "server_not_verified",
"message": "Server must be verified by admin before voting.",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}