# ShbUtils Core API Локальный справочник по API сервиса `https://api.shlakoblock.com`. - Источник: `https://api.shlakoblock.com/api.json` - OpenAPI: `3.1.0` - Версия сервиса: `2.1.3-SNAPSHOT` - Дата снимка: `2026-07-22` - Формат запросов и ответов, если не указано иное: `application/json` Документ является снимком контракта. В OpenAPI не описаны rate limits, гарантии идемпотентности и формат JSON-тел для большинства ошибок. ## Авторизация ### Internal endpoints Все пути `/internal/*` требуют заголовок: ```http X-Internal-Secret: ``` При отсутствующем или неверном секрете возвращается `401 invalid_internal_secret`. ### Player endpoints Пути `/api/*` требуют bearer-токен, выданный `POST /internal/auth/start`: ```http Authorization: Bearer ``` Хотя схема `BearerAuth` присутствует в OpenAPI, требования `security` не проставлены у самих операций. Необходимость токена следует из ответов `401 missing/invalid token`; для этих endpoint также возможен `403 player_offline`. ## Basic ### `GET /` Маркер сервиса. Возвращает `200` и название сервиса простым текстом. ### `GET /health` Проверяет соединения с БД и Redis. | Код | Значение | | --- | --- | | `200` | `status: ok` | | `503` | `status: degraded` | ## Internal ### `POST /internal/join` Регистрирует вход игрока. ```json { "uuid": "11111111-1111-1111-1111-111111111111", "playerName": "Player" } ``` `playerName` необязателен и может быть `null`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401 invalid_internal_secret`. ### `POST /internal/quit` Регистрирует выход игрока. Тело: `UuidRequest`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`. ### `POST /internal/auth/start` Выдаёт bearer-токен для игрока. Игрок должен быть онлайн. - Тело: `UuidRequest`. - Успех: `200 TokenResponse`. - Ошибки: `400 invalid_body / invalid_uuid`, `401`, `403 player_offline`. ### `POST /internal/verification/code` Создаёт verification-код для Minecraft UUID. Это направление «Minecraft → внешний клиент», поэтому ShbDiscordBot не использует endpoint для своего `/auth`. - Тело: `VerificationCodeRequest`. - Успех: `200 VerificationCodeResponse`. - Ошибки: `400 invalid_body / invalid_uuid`, `401`. ### `POST /internal/verification/verify` Проверяет ранее созданный код и привязывает Telegram и/или Discord. ```json { "code": "123456", "telegramId": 123456789, "telegramTag": "example", "discordId": "123456789012345678" } ``` Кроме `code`, поля необязательны и nullable. Успех: `200 VerificationVerifyResponse`. Ошибки: `400 invalid_body`, `401`, `404 invalid_or_expired_code`. ### `POST /internal/auth/password` Проверяет пароль игрока без передачи хэша наружу. ```json { "uuid": "11111111-1111-1111-1111-111111111111", "password": "plain-text-password" } ``` Успех: `200 PasswordVerifyResponse`. Ошибки: `400 invalid_body / invalid_uuid`, `401`. ### `POST /internal/auth/password/change` Заменяет пароль игрока. ```json { "uuid": "11111111-1111-1111-1111-111111111111", "newPassword": "new-plain-text-password" } ``` Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid / invalid_password`, `401`, `404 player_not_found`. ### `POST /internal/players/password/reset` Удаляет сохранённый пароль игрока. Тело: `PasswordResetRequest`. Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`. ### `POST /internal/players/unlink` Отвязывает Telegram и/или Discord. Оба флага по умолчанию равны `true`. ```json { "uuid": "11111111-1111-1111-1111-111111111111", "telegram": true, "discord": true } ``` Успех: `200 ApiMessage`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`. ### `POST /internal/players/status` Ищет игрока и возвращает состояние регистрации/привязок. В теле должно присутствовать ровно одно из полей `uuid`, `name`, `telegramId`, `discordId`. ```json { "discordId": "123456789012345678" } ``` Успех: `200 PlayerStatusResponse`; если совпадение отсутствует, возвращается объект с `exists: false`, а не `404`. Ошибки: `400 invalid_body / invalid_uuid / exactly_one_identifier_required`, `401`. ### `GET /internal/players/{uuid}` Возвращает полный `PlayerProfile` по UUID. Ошибки: `400 invalid_uuid`, `401`, `404 player_not_found`. ### `GET /internal/players/by-name/{name}` Ищет полный `PlayerProfile` по Minecraft-нику без учёта регистра. Ошибки: `401`, `404 player_not_found`. ### `GET /internal/players/by-telegram/{telegramId}` Ищет полный `PlayerProfile` по Telegram ID. Ошибки: `400 invalid_telegram_id`, `401`, `404 player_not_found`. ### `POST /internal/players/{uuid}/telegram` Устанавливает либо очищает Telegram-привязку. ```json { "telegramId": 123456789, "telegramTag": "example" } ``` Оба поля nullable; `null` используется для отвязки. Успех: `200 PlayerProfile`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`. ### `POST /internal/players/{uuid}/discord` Устанавливает либо очищает Discord-привязку. Это endpoint, используемый ShbDiscordBot после погашения локального кода. ```json { "discordId": "123456789012345678" } ``` `discordId: null` означает отвязку. Успех: `200 PlayerProfile`. Ошибки: `400 invalid_body / invalid_uuid`, `401`, `404 player_not_found`. ## Player API ### `GET /api/players/online` Возвращает массив `Player` со всеми онлайн-игроками. Ошибки: `401 missing/invalid token`, `403 player_offline`. ### `GET /api/players/registered` Возвращает массив `Player` со всеми зарегистрированными игроками. Ошибки: `401 missing/invalid token`, `403 player_offline`. ### `GET /api/players/me/state` Возвращает `MyPlayerStateResponse` для владельца bearer-токена. Ошибки: `401 missing/invalid token`, `403 player_offline`. ### `GET /api/players/{uuid}` Возвращает зарегистрированного игрока как `Player`. Ошибки: `400 invalid_uuid`, `401 missing/invalid token`, `403 player_offline`, `404 player_not_found`. ## Схемы данных `required` ниже означает обязательность по OpenAPI. Nullable-поле может явно содержать `null`. ### `ApiMessage` | Поле | Тип | required | | --- | --- | --- | | `message` | string | да | ### `JoinRequest` | Поле | Тип | required | | --- | --- | --- | | `uuid` | string | да | | `playerName` | string или null | нет | ### `UuidRequest`, `VerificationCodeRequest`, `PasswordResetRequest` Каждая схема содержит одно обязательное поле `uuid: string`. ### `TokenResponse` | Поле | Тип | required | | --- | --- | --- | | `token` | string | да | ### `VerificationCodeResponse` | Поле | Тип | required | | --- | --- | --- | | `code` | string | да | | `expiresAt` | int64 | да | OpenAPI не уточняет единицу `expiresAt`; клиенту следует согласовать её с реализацией сервиса. ### `VerificationVerifyRequest` | Поле | Тип | required | | --- | --- | --- | | `code` | string | да | | `telegramId` | int64 или null | нет | | `telegramTag` | string или null | нет | | `discordId` | string или null | нет | ### `VerificationVerifyResponse` | Поле | Тип | required | | --- | --- | --- | | `uuid` | string | да | | `name` | string | да | ### `PasswordVerifyRequest` Обязательные поля: `uuid: string`, `password: string`. ### `PasswordVerifyResponse` Обязательное поле: `valid: boolean`. ### `PasswordChangeRequest` Обязательные поля: `uuid: string`, `newPassword: string`. ### `UnlinkAccountsRequest` | Поле | Тип | required | | --- | --- | --- | | `uuid` | string | да | | `telegram` | boolean | нет | | `discord` | boolean | нет | ### `PlayerStatusRequest` Все поля необязательны/nullable, но сервер требует ровно один идентификатор: | Поле | Тип | | --- | --- | | `uuid` | string или null | | `name` | string или null | | `telegramId` | int64 или null | | `discordId` | string или null | ### `PlayerStatusResponse` Только `exists` обязательно по схеме. Остальные поля могут отсутствовать при `exists: false`. | Поле | Тип | | --- | --- | | `exists` | boolean | | `uuid` | string или null | | `name` | string или null | | `registered` | boolean | | `telegramLinked` | boolean | | `telegramId` | int64 или null | | `telegramTag` | string или null | | `discordLinked` | boolean | | `discordId` | string или null | ### `PlayerProfile` Все поля обязательны; идентификаторы внешних аккаунтов nullable. | Поле | Тип | | --- | --- | | `uuid` | string | | `name` | string | | `registered` | boolean | | `online` | boolean | | `telegramId` | int64 или null | | `telegramTag` | string или null | | `discordId` | string или null | ### `TelegramLinkRequest` Необязательные nullable-поля: `telegramId: int64`, `telegramTag: string`. ### `DiscordLinkRequest` Необязательное nullable-поле: `discordId: string`. ### `Player` | Поле | Тип | required | | --- | --- | --- | | `uuid` | string | да | | `name` | string или null | да | ### `MyPlayerStateResponse` Обязательные поля: `uuid: string`, `name: string`. ## Пример привязки Discord напрямую Проверка текущей связи: ```http POST /internal/players/status HTTP/1.1 Host: api.shlakoblock.com X-Internal-Secret: Content-Type: application/json {"discordId":"123456789012345678"} ``` Запись Discord ID игроку: ```http POST /internal/players/11111111-1111-1111-1111-111111111111/discord HTTP/1.1 Host: api.shlakoblock.com X-Internal-Secret: Content-Type: application/json {"discordId":"123456789012345678"} ```