{"openapi":"3.1.0","info":{"title":"Lorachi — Mobile API v1","version":"1.0.0","summary":"Стабильный контракт для нативного клиента: чтение, библиотека, профиль и соцслой.","description":"База: `/api/v1`. Авторизация — `Authorization: Bearer <accessToken>`; cookie и CSRF не используются.\n\nПубличные ответы несут `ETag` и `Cache-Control`, персональные — `private, no-store` без ETag (см. `MOBILE_API.md` §1.1).\n\nОшибки — конверт `{ error: { code, message, details? } }`; коды и правила — в `MOBILE_API.md`.","license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://beta.lorachi.xyz","description":"Текущий origin"}],"tags":[{"name":"Мобильный API v1","description":"Стабильный контракт для нативного клиента. База: /api/v1. Авторизация — Authorization: Bearer <accessToken>; cookie и CSRF не используются. Access живёт 30 минут, refresh — 90 дней и ротируется при каждом обмене."}],"security":[],"paths":{"/api/v1/activity/update":{"post":{"operationId":"activityUpdate","summary":"Пульс присутствия для «онлайн» и карточки профиля.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Presence"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/anime":{"get":{"operationId":"animeIndex","summary":"Каталог аниме с фильтрами и пагинацией.","description":"query: page, limit, genre, type, status, sort, order, search.","tags":["Мобильный API v1"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"genre","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["all","novel","manga","anime"]}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"sort","in":"query","schema":{"type":"string"}},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"]}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnimeCatalog"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/anime/{idOrSlug}":{"get":{"operationId":"animeShow","summary":"Тайтл, серии по сезонам и состояние библиотеки.","tags":["Мобильный API v1"],"parameters":[{"name":"idOrSlug","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, slugUrl или короткий slug"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnimeRelease"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/anime/episodes/{id}/streams":{"get":{"operationId":"animeStreams","summary":"Источники для плеера: треки, качества, встраиваемые плееры.","description":"private, no-store; скрытая серия — 404.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/anime/episodes/{id}/subtitles/{player}/{subtitle}":{"get":{"operationId":"animeSubtitles","summary":"WebVTT-субтитры через наш прокси.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"},{"name":"player","in":"path","required":true,"schema":{"type":"string"},"description":"Имя плеера"},{"name":"subtitle","in":"path","required":true,"schema":{"type":"string"},"description":"Язык или имя файла субтитров"}],"responses":{"200":{"description":"Субтитры WebVTT","content":{"text/vtt":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/link/poll":{"post":{"operationId":"authLinkPoll","summary":"Опрос статуса link-входа; токены выдаются один раз.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPollRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MobileTokens"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/link/start":{"post":{"operationId":"authLinkStart","summary":"Начать вход по ссылке через сайт (Lite-OAuth).","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkStartRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/login":{"post":{"operationId":"authLogin","summary":"Вход по username/email и паролю.","description":"Тело: login, password, deviceId?.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MobileTokens"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/logout":{"post":{"operationId":"authLogout","summary":"Выход только с этого устройства.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/auth/logout-all":{"post":{"operationId":"authLogoutAll","summary":"Выход со всех устройств.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/auth/me":{"get":{"operationId":"authMe","summary":"Пользователь, подписка и unread.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/auth/oauth/{provider}/callback":{"get":{"operationId":"authOauthCallback","summary":"Callback провайдера: одноразовый код в lorachi://oauth, без токенов в URL.","tags":["Мобильный API v1"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"},"description":"google | discord"}],"responses":{"302":{"description":"Редирект в Custom Tabs / обратно в приложение","headers":{"Location":{"schema":{"type":"string"},"description":"Адрес перехода"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/oauth/{provider}/start":{"get":{"operationId":"authOauthStart","summary":"Native OAuth/PKCE: 302 в Custom Tabs к Google или Discord.","description":"query: redirect_uri, code_challenge, code_challenge_method=S256, state, deviceId?.","tags":["Мобильный API v1"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"},"description":"google | discord"},{"name":"redirect_uri","in":"query","schema":{"type":"string"},"required":true},{"name":"code_challenge","in":"query","schema":{"type":"string"},"required":true},{"name":"code_challenge_method","in":"query","schema":{"type":"string","const":"S256"},"required":true},{"name":"state","in":"query","schema":{"type":"string"}},{"name":"deviceId","in":"query","schema":{"type":"string"}}],"responses":{"302":{"description":"Редирект в Custom Tabs / обратно в приложение","headers":{"Location":{"schema":{"type":"string"},"description":"Адрес перехода"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/oauth/{provider}/token":{"post":{"operationId":"authOauthToken","summary":"Обмен одноразового кода и PKCE verifier на Bearer-пару.","description":"Тело: code, codeVerifier, deviceId?. Повторный обмен — 410.","tags":["Мобильный API v1"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"},"description":"google | discord"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MobileTokens"}}}},"410":{"$ref":"#/components/responses/Gone"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/refresh":{"post":{"operationId":"authRefresh","summary":"Обмен refresh-токена на новую пару.","description":"Тело: refreshToken, deviceId?.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MobileTokens"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/auth/register":{"post":{"operationId":"authRegister","summary":"Регистрация, сразу возвращает пару токенов.","description":"Тело: username, email, password, captchaToken?, deviceId?.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}}},"responses":{"201":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MobileTokens"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/catalog":{"get":{"operationId":"catalog","summary":"Каталог новелл, манги и аниме.","description":"Фильтры: type, page, limit, genre, status, sort, order, search, featured.","tags":["Мобильный API v1"],"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["all","novel","manga","anime"]}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"genre","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"sort","in":"query","schema":{"type":"string"}},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"]}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"featured","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Catalog"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/chapters/{id}":{"get":{"operationId":"chapter","summary":"Текстовая глава с prev/next.","description":"Платная глава без доступа: 403 E_PAID_CHAPTER.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterDetail"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/comments":{"get":{"operationId":"commentsIndex","summary":"Комментарии с деревом ответов и liked зрителя.","description":"query: targetType, targetId, sort, page, limit.","tags":["Мобильный API v1"],"parameters":[{"name":"targetType","in":"query","schema":{"type":"string"}},{"name":"targetId","in":"query","schema":{"type":"string"}},{"name":"sort","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]},"post":{"operationId":"commentsCreate","summary":"Оставить комментарий или ответ (только аккаунт).","description":"Тело: targetType, targetId, content, parentId?, isAnonymous?.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentCreateRequest"}}}},"responses":{"201":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentCreated"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/comments/{id}":{"delete":{"operationId":"commentsDestroy","summary":"Удалить свой комментарий.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/comments/{id}/like":{"post":{"operationId":"commentsLike","summary":"Лайк/анлайк комментария.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentLike"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/devices":{"post":{"operationId":"devicesStore","summary":"Зарегистрировать FCM-токен устройства.","description":"Тело: token, platform?, deviceId?.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/devices/{token}":{"delete":{"operationId":"devicesDestroy","summary":"Удалить FCM-токен устройства.","tags":["Мобильный API v1"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"FCM-токен устройства"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceRevoke"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/home":{"get":{"operationId":"home","summary":"Главная: featured, updates, continueReading.","description":"С Bearer персонализируется.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Home"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/library":{"get":{"operationId":"libraryIndex","summary":"Библиотека пользователя и сводка.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/library/{kind}/{id}":{"delete":{"operationId":"libraryRemove","summary":"Убрать запись из библиотеки.","tags":["Мобильный API v1"],"parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string"},"description":"Вид контента: novel | manga | anime"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]},"put":{"operationId":"libraryUpsert","summary":"Добавить или обновить запись.","description":"kind: novel, manga, anime.","tags":["Мобильный API v1"],"parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string"},"description":"Вид контента: novel | manga | anime"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryUpsertRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryEntryResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/library/bulk":{"post":{"operationId":"libraryBulk","summary":"Массовая смена статуса или удаление.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryBulkRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryBulkResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/manga/{novelId}/chapters/{chapterId}/pages":{"get":{"operationId":"mangaPages","summary":"Страницы манги в правильном порядке.","tags":["Мобильный API v1"],"parameters":[{"name":"novelId","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId тайтла"},{"name":"chapterId","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId главы"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MangaPages"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/me":{"get":{"operationId":"me","summary":"Алиас пользователя, подписки и unread.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericObject"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/me/profile":{"patch":{"operationId":"meProfile","summary":"Частичная правка своего профиля.","description":"Тело: displayName, bio, status, pronouns, messagePrivacy, isPrivate — все необязательные.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdateRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfile"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications":{"get":{"operationId":"notificationsIndex","summary":"Уведомления и счётчики по категориям.","tags":["Мобильный API v1"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"unread","in":"query","schema":{"type":"string","enum":["1","true"]}},{"name":"kind","in":"query","schema":{"type":"string","enum":["novel","manga","anime"]}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/{id}":{"delete":{"operationId":"notificationsDestroy","summary":"Удалить уведомление.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDelete"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/{id}/toggle":{"post":{"operationId":"notificationsToggle","summary":"Переключить прочитано/непрочитано.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationToggle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/clear-read":{"post":{"operationId":"notificationsClearRead","summary":"Удалить прочитанные.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationClear"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/read":{"post":{"operationId":"notificationsRead","summary":"Отметить выбранные или все уведомления.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationsReadRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/settings":{"get":{"operationId":"notificationsSettings","summary":"Настройки уведомлений по категориям.","description":"kinds: chapters, anime, social, rewards, games, system. Выключенная категория гасит и уведомления, и push.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSettings"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]},"put":{"operationId":"notificationsSettingsSave","summary":"Частично изменить категории уведомлений.","description":"Тело: kinds — объект «категория → true/false». Меняются только присланные ключи; неизвестная категория — 422.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSettingsRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationSettings"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/notifications/unread":{"get":{"operationId":"notificationsUnread","summary":"Только счётчик непрочитанных.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationUnread"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/novels/{id}":{"get":{"operationId":"novel","summary":"Карточка тайтла по ObjectId, alt или slug.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NovelDetail"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/novels/{id}/chapters":{"get":{"operationId":"novelChapters","summary":"Список глав; limit до 100.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/novels/{id}/content":{"get":{"operationId":"novelContent","summary":"Том целиком для офлайна: markdown-текст или страницы манги.","description":"query: volume (по умолчанию 1). Платные главы без доступа — locked: true; том больше 4 МиБ — 413 E_VOLUME_TOO_LARGE.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"},{"name":"volume","in":"query","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumePack"}}}},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/VolumeTooLarge"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/progress":{"get":{"operationId":"progressShow","summary":"Последние прочитанные тайтлы.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]},"put":{"operationId":"progressSave","summary":"Сохранить позицию чтения.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressSaveRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressSaveResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/progress/sync":{"post":{"operationId":"progressSync","summary":"Слить офлайн-прогресс, last-write-wins.","tags":["Мобильный API v1"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressSyncRequest"}}}},"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressSync"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/search":{"get":{"operationId":"search","summary":"Поиск по тайтлам, авторам и пользователям.","description":"q — 2–100 символов.","tags":["Мобильный API v1"],"parameters":[{"name":"q","in":"query","schema":{"type":"string","description":"Поисковый запрос"}},{"name":"type","in":"query","schema":{"type":"string","enum":["all","novel","manga","anime"]}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Search"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/sessions":{"get":{"operationId":"sessionsIndex","summary":"Активные сеансы: текущее устройство и сайт.","tags":["Мобильный API v1"],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/sessions/{id}":{"delete":{"operationId":"sessionsRevoke","summary":"Завершить выбранный сеанс.","tags":["Мобильный API v1"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ObjectId, alt или slug — зависит от ручки"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionRevoke"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/users/{username}":{"get":{"operationId":"usersShow","summary":"Публичный профиль без email.","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfile"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/users/{username}/follow":{"delete":{"operationId":"usersUnfollow","summary":"Отписаться (идемпотентно).","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]},"post":{"operationId":"usersFollow","summary":"Подписаться (идемпотентно).","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"bearerAuth":[]}]}},"/api/v1/users/{username}/followers":{"get":{"operationId":"usersFollowers","summary":"Подписчики, до 200.","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowList"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/users/{username}/following":{"get":{"operationId":"usersFollowing","summary":"Подписки, до 200.","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowList"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/users/{username}/friends":{"get":{"operationId":"usersFriends","summary":"Взаимные подписки, до 200.","tags":["Мобильный API v1"],"parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"username без @"}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowList"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/users/online":{"get":{"operationId":"usersOnline","summary":"Кто активен последние 5 минут.","tags":["Мобильный API v1"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}},"/api/v1/users/search":{"get":{"operationId":"usersSearch","summary":"Поиск людей по username и нику.","description":"query: q (от 2 символов), page, limit до 50.","tags":["Мобильный API v1"],"parameters":[{"name":"q","in":"query","schema":{"type":"string","description":"Поисковый запрос"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Успех","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{},{"bearerAuth":[]}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access-токен из /api/v1/auth/login, /refresh, /auth/link/poll или OAuth-обмена."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Машиночитаемый код, например E_PAID_CHAPTER"},"message":{"type":"string","description":"Текст для человека"},"details":{"type":"object","additionalProperties":true},"messages":{"type":"array","description":"Ошибки по полям","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}},"additionalProperties":true},"MobileTokens":{"type":"object","required":["accessToken","refreshToken","tokenType","expiresIn"],"properties":{"accessToken":{"type":"string","description":"Bearer для /api/v1; живёт 30 минут"},"refreshToken":{"type":"string","description":"Одноразовый refresh; живёт 90 дней"},"tokenType":{"type":"string","const":"Bearer"},"expiresIn":{"type":"integer","description":"Секунд до истечения access"},"refreshExpiresIn":{"type":"integer","description":"Секунд до истечения refresh"},"user":{"type":"object","additionalProperties":true}},"additionalProperties":true},"NovelCard":{"type":"object","required":["id","type","title","genres","chapters","url"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["novel","manga"]},"title":{"type":"string"},"alt":{"oneOf":[{"type":"string"},{"type":"null"}]},"coverUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"blurCover":{"type":"boolean"},"status":{"type":"string","description":"Статус тайтла; строка, а не число"},"ageRating":{"oneOf":[{"type":"string"},{"type":"null"}]},"isAdult":{"type":"boolean"},"genres":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"chapters":{"type":"integer"},"views":{"type":"integer"},"ratings":{"type":"object","properties":{"average":{"type":"number"},"count":{"type":"integer"}},"additionalProperties":true},"isFeatured":{"type":"boolean"},"isStaffPick":{"type":"boolean"},"url":{"type":"string","description":"Путь на сайте"}},"additionalProperties":true},"ChapterRef":{"type":"object","required":["id","number","volume","url"],"properties":{"id":{"type":"string"},"number":{"type":"string","description":"Номер главы строкой: «12.5», «prologue»"},"volume":{"type":"integer"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"isPaid":{"type":"boolean"},"isEarlyAccess":{"type":"boolean"},"url":{"type":"string"},"publishedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"additionalProperties":true},"Navigation":{"type":"object","properties":{"prev":{"oneOf":[{"$ref":"#/components/schemas/ChapterRef"},{"type":"null"}]},"next":{"oneOf":[{"$ref":"#/components/schemas/ChapterRef"},{"type":"null"}]}},"additionalProperties":true},"LibraryEntry":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["planned","in_progress","completed","on_hold","dropped","favorite"]},"rating":{"oneOf":[{"type":"number"},{"type":"null"}]},"progress":{"type":"object","additionalProperties":true,"description":"Глава/том/процент и lastAt — форма зависит от вида"},"notify":{"type":"boolean"}},"additionalProperties":true},"ProgressEntry":{"type":"object","required":["novelId","chapter"],"properties":{"novelId":{"type":"string"},"title":{"type":"string"},"type":{"type":"string","enum":["novel","manga"]},"coverUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"chapter":{"type":"string"},"volume":{"type":"integer"},"percent":{"type":"number","minimum":0,"maximum":100},"url":{"type":"string"},"lastAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"additionalProperties":true},"UserCard":{"type":"object","required":["id","username","displayName","level"],"properties":{"id":{"type":"string"},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"level":{"type":"integer"},"verifiedBadge":{"type":"string"},"usernameStyle":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"string"},{"type":"null"}]},"isFollowing":{"type":"boolean","description":"Считается по Bearer; у гостя всегда false"}},"additionalProperties":true},"Profile":{"type":"object","required":["id","username","displayName","restricted"],"properties":{"id":{"type":"string"},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"bannerUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"bannerNsfw":{"type":"boolean"},"bio":{"type":"string"},"status":{"oneOf":[{"type":"string"},{"type":"null"}]},"statusUpdatedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"pronouns":{"oneOf":[{"type":"string"},{"type":"null"}]},"level":{"type":"integer"},"xp":{"type":"integer"},"role":{"type":"string"},"verifiedBadge":{"type":"string"},"usernameStyle":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscriptionType":{"type":"string","enum":["free","plus","pro"]},"online":{"type":"boolean"},"createdAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"isPrivate":{"type":"boolean"},"restricted":{"type":"boolean","description":"Закрытый профиль для чужого: bio и статистика скрыты"},"isFollowing":{"type":"boolean"},"followsMe":{"type":"boolean"},"stats":{"type":"object","properties":{"followingCount":{"type":"integer"},"followersCount":{"type":"integer"}},"additionalProperties":true}},"additionalProperties":true},"Session":{"type":"object","required":["id","kind"],"properties":{"id":{"type":"string","description":"web:<id> или mobile:<family> — непрозрачная строка"},"kind":{"type":"string","enum":["web","mobile"]},"kindLabel":{"type":"string"},"deviceName":{"oneOf":[{"type":"string"},{"type":"null"}]},"ip":{"oneOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"lastSeenAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"expiresAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"current":{"type":"boolean"}},"additionalProperties":true},"Notification":{"type":"object","required":["id","type","isRead"],"properties":{"id":{"type":"string"},"type":{"type":"string"},"kind":{"type":"string"},"kindLabel":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"url":{"oneOf":[{"type":"string"},{"type":"null"}]},"isRead":{"type":"boolean"},"createdAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"additionalProperties":true},"Comment":{"type":"object","required":["id","content"],"properties":{"id":{"type":"string"},"targetType":{"type":"string"},"targetId":{"type":"string"},"content":{"type":"string"},"createdAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"isAnonymous":{"type":"boolean"},"liked":{"type":"boolean","description":"Считается по зрителю"},"likes":{"type":"integer"},"replyCount":{"type":"integer"},"user":{"oneOf":[{"$ref":"#/components/schemas/UserCard"},{"type":"null"}]}},"additionalProperties":true},"AnimeCard":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"originalTitle":{"oneOf":[{"type":"string"},{"type":"null"}]},"slugUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"poster":{"oneOf":[{"type":"string"},{"type":"null"}]},"ageLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"typeLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"statusLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"releaseDate":{"oneOf":[{"type":"string"},{"type":"null"}]},"rating":{"oneOf":[{"type":"number"},{"type":"null"}]},"genres":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"episodeCount":{"type":"integer"},"library":{"oneOf":[{"$ref":"#/components/schemas/LibraryEntry"},{"type":"null"}]}},"additionalProperties":true},"AnimeEpisode":{"type":"object","required":["id","number","season"],"properties":{"id":{"type":"string"},"sourceId":{"oneOf":[{"type":"string"},{"type":"null"}]},"number":{"type":"string"},"season":{"type":"string"},"name":{"type":"string"},"heading":{"type":"string"}},"additionalProperties":true},"PaginationMeta":{"type":"object","required":["page","limit","total","hasMore"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":true},"NovelDetail":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","title","chaptersCount"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["novel","manga"]},"title":{"type":"string"},"alt":{"oneOf":[{"type":"string"},{"type":"null"}]},"coverUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"blurCover":{"type":"boolean"},"status":{"type":"string","description":"Статус тайтла; строка, а не число"},"ageRating":{"oneOf":[{"type":"string"},{"type":"null"}]},"isAdult":{"type":"boolean"},"genres":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"chapters":{"type":"integer"},"views":{"type":"integer"},"ratings":{"type":"object","properties":{"average":{"type":"number"},"count":{"type":"integer"}},"additionalProperties":true},"isFeatured":{"type":"boolean"},"isStaffPick":{"type":"boolean"},"url":{"type":"string","description":"Путь на сайте"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"author":{"oneOf":[{"type":"string"},{"type":"null"}]},"artist":{"oneOf":[{"type":"string"},{"type":"null"}]},"releaseYear":{"oneOf":[{"type":"integer"},{"type":"null"}]},"publishStatus":{"type":"string"},"chaptersCount":{"type":"integer"},"firstChapter":{"oneOf":[{"$ref":"#/components/schemas/ChapterRef"},{"type":"null"}]},"latestChapters":{"type":"array","items":{"$ref":"#/components/schemas/ChapterRef"}},"library":{"oneOf":[{"$ref":"#/components/schemas/LibraryEntry"},{"type":"null"}]}},"additionalProperties":true}},"additionalProperties":true},"ChapterDetail":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","number","content","novel","navigation"],"properties":{"id":{"type":"string"},"number":{"type":"string"},"volume":{"type":"integer"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"content":{"type":"string","description":"Markdown; пусто у манги"},"format":{"type":"string","const":"markdown"},"isPaid":{"type":"boolean"},"price":{"type":"integer"},"isEarlyAccess":{"type":"boolean"},"isIllustrationChapter":{"type":"boolean"},"isExtraChapter":{"type":"boolean"},"publishedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"views":{"type":"integer","description":"Растёт на каждом чтении; ETag считается без него"},"novel":{"$ref":"#/components/schemas/NovelCard"},"navigation":{"$ref":"#/components/schemas/Navigation"}},"additionalProperties":true}},"additionalProperties":true},"ChapterList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChapterRef"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"additionalProperties":true},"MangaPages":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","pages","novel"],"properties":{"id":{"type":"string"},"number":{"type":"string"},"volume":{"type":"integer"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"pages":{"type":"array","items":{"type":"string"}},"isPaid":{"type":"boolean"},"price":{"type":"integer"},"views":{"type":"integer"},"novel":{"$ref":"#/components/schemas/NovelCard"},"navigation":{"$ref":"#/components/schemas/Navigation"}},"additionalProperties":true}},"additionalProperties":true},"VolumePack":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["novel","volume","chapters"],"properties":{"novel":{"$ref":"#/components/schemas/NovelCard"},"volume":{"type":"integer"},"chapters":{"type":"array","items":{"$ref":"#/components/schemas/VolumeChapter"}}},"additionalProperties":true},"meta":{"type":"object","required":["volume","chapters","sizeBytes"],"properties":{"novelId":{"type":"string"},"volume":{"type":"integer"},"chapters":{"type":"integer"},"locked":{"type":"integer"},"sizeBytes":{"type":"integer"},"maxBytes":{"type":"integer"}},"additionalProperties":true}},"additionalProperties":true},"VolumeChapter":{"type":"object","required":["id","number","volume","format","locked","sizeBytes"],"properties":{"id":{"type":"string"},"number":{"type":"string"},"volume":{"type":"integer"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"format":{"type":"string","enum":["markdown","images"]},"content":{"oneOf":[{"type":"string"},{"type":"null"}]},"pages":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"locked":{"type":"boolean","description":"Платная глава без доступа: в томе есть, контента нет"},"isPaid":{"type":"boolean"},"price":{"type":"integer"},"isEarlyAccess":{"type":"boolean"},"isIllustrationChapter":{"type":"boolean"},"isExtraChapter":{"type":"boolean"},"publishedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"sizeBytes":{"type":"integer"}},"additionalProperties":true},"Home":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["featured","updates"],"properties":{"featured":{"type":"array","items":{"$ref":"#/components/schemas/NovelCard"}},"updates":{"type":"array","items":{"type":"object","additionalProperties":true}},"continueReading":{"type":"array","items":{"$ref":"#/components/schemas/ProgressEntry"}}},"additionalProperties":true},"meta":{"type":"object","required":["personalized"],"properties":{"unread":{"type":"integer"},"personalized":{"type":"boolean"},"generatedAt":{"type":"string","format":"date-time"}},"additionalProperties":true}},"additionalProperties":true},"Catalog":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NovelCard"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"additionalProperties":true},"Search":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["novels"],"properties":{"novels":{"type":"array","items":{"$ref":"#/components/schemas/NovelCard"}},"authors":{"type":"array","items":{"type":"object","additionalProperties":true}},"users":{"type":"array","items":{"$ref":"#/components/schemas/UserCard"}}},"additionalProperties":true},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"additionalProperties":true},"UserProfile":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Profile"}},"additionalProperties":true},"UserList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UserCard"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"additionalProperties":true},"FollowList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UserCard"}},"meta":{"type":"object","required":["kind","total"],"properties":{"kind":{"type":"string","enum":["followers","following"]},"total":{"type":"integer"},"limit":{"type":"integer"}},"additionalProperties":true}},"additionalProperties":true},"FollowResult":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"following":{"type":"boolean"},"followersCount":{"type":"integer"}},"additionalProperties":true}},"additionalProperties":true},"LibraryList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LibraryEntry"}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"truncated":{"type":"boolean"}},"additionalProperties":true}},"additionalProperties":true},"LibraryEntryResult":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/LibraryEntry"}},"additionalProperties":true},"LibraryBulkResult":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"removed":{"type":"integer"},"updated":{"type":"integer"}},"additionalProperties":true},"ProgressList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProgressEntry"}}},"additionalProperties":true},"ProgressSaveResult":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ProgressEntry"}},"additionalProperties":true},"ProgressSync":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"merged":{"type":"integer"},"skipped":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ProgressEntry"}}},"additionalProperties":true},"NotificationList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"kind":{"type":"string"},"counts":{"type":"object","additionalProperties":true}},"additionalProperties":true}},"additionalProperties":true},"NotificationUnread":{"type":"object","required":["count"],"properties":{"count":{"type":"integer"}},"additionalProperties":true},"NotificationToggle":{"type":"object","required":["ok","isRead"],"properties":{"ok":{"type":"boolean"},"isRead":{"type":"boolean"},"unreadCount":{"type":"integer"}},"additionalProperties":true},"NotificationDelete":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"unreadCount":{"type":"integer"}},"additionalProperties":true},"NotificationClear":{"type":"object","required":["ok","deleted"],"properties":{"ok":{"type":"boolean"},"deleted":{"type":"integer"},"unreadCount":{"type":"integer"}},"additionalProperties":true},"NotificationSettings":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":{"type":"boolean"}},"meta":{"type":"object","properties":{"allowed":{"type":"array","items":{"type":"string"}}},"additionalProperties":true}},"additionalProperties":true},"CommentList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"additionalProperties":true},"CommentCreated":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Comment"},"masked":{"type":"boolean"}},"additionalProperties":true},"CommentLike":{"type":"object","required":["ok","liked"],"properties":{"ok":{"type":"boolean"},"likesCount":{"type":"integer"},"liked":{"type":"boolean"}},"additionalProperties":true},"AnimeCatalog":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AnimeCard"}},"meta":{"type":"object","required":["page","limit","total"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"},"filters":{"type":"object","additionalProperties":true}},"additionalProperties":true}},"additionalProperties":true},"AnimeRelease":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","title","episodes","seasons"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"originalTitle":{"oneOf":[{"type":"string"},{"type":"null"}]},"slugUrl":{"oneOf":[{"type":"string"},{"type":"null"}]},"poster":{"oneOf":[{"type":"string"},{"type":"null"}]},"ageLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"typeLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"statusLabel":{"oneOf":[{"type":"string"},{"type":"null"}]},"releaseDate":{"oneOf":[{"type":"string"},{"type":"null"}]},"rating":{"oneOf":[{"type":"number"},{"type":"null"}]},"genres":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"episodeCount":{"type":"integer"},"library":{"oneOf":[{"$ref":"#/components/schemas/LibraryEntry"},{"type":"null"}]},"englishTitle":{"oneOf":[{"type":"string"},{"type":"null"}]},"episodes":{"type":"array","items":{"$ref":"#/components/schemas/AnimeEpisode"}},"seasons":{"type":"array","items":{"type":"object","properties":{"season":{"type":"string"},"episodes":{"type":"array","items":{"$ref":"#/components/schemas/AnimeEpisode"}}},"additionalProperties":true}}},"additionalProperties":true}},"additionalProperties":true},"SessionList":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}},"additionalProperties":true},"SessionRevoke":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"revoked":{"type":"integer"},"current":{"type":"boolean"},"kind":{"type":"string"}},"additionalProperties":true},"DevicesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}},"additionalProperties":true},"DeviceRevoke":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"revoked":{"type":"integer"}},"additionalProperties":true},"Presence":{"type":"object","required":["ok","online"],"properties":{"ok":{"type":"boolean"},"throttled":{"type":"boolean"},"online":{"type":"boolean"},"onlineUntil":{"type":"string"}},"additionalProperties":true},"OkResponse":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}},"additionalProperties":true},"GenericObject":{"type":"object","additionalProperties":true},"RegisterRequest":{"type":"object","required":["username","email","password"],"properties":{"username":{"type":"string","description":"3–24 символа, латиница и цифры"},"email":{"type":"string","description":"Валидный email","format":"email"},"password":{"type":"string","description":"Минимум 8 символов"},"captchaToken":{"type":"string","description":"Токен hCaptcha, если капча включена"},"deviceId":{"type":"string","description":"Стабильный id устройства для сеансов"}},"additionalProperties":true},"LoginRequest":{"type":"object","required":["login","password"],"properties":{"login":{"type":"string","description":"username или email"},"password":{"type":"string"},"deviceId":{"type":"string"}},"additionalProperties":true},"RefreshRequest":{"type":"object","required":["refreshToken"],"properties":{"refreshToken":{"type":"string"},"deviceId":{"type":"string"}},"additionalProperties":true},"OAuthTokenRequest":{"type":"object","required":["code","codeVerifier"],"properties":{"code":{"type":"string"},"codeVerifier":{"type":"string","description":"PKCE verifier"},"deviceId":{"type":"string"}},"additionalProperties":true},"LinkStartRequest":{"type":"object","properties":{"deviceId":{"type":"string"}},"additionalProperties":true},"LinkPollRequest":{"type":"object","required":["deviceCode"],"properties":{"deviceCode":{"type":"string","description":"Код из /auth/link/start"}},"additionalProperties":true},"ProfileUpdateRequest":{"type":"object","properties":{"displayName":{"oneOf":[{"type":"string"},{"type":"null"}]},"bio":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"string"},{"type":"null"}]},"pronouns":{"oneOf":[{"type":"string"},{"type":"null"}]},"messagePrivacy":{"type":"string","enum":["all","following","none"]},"isPrivate":{"type":"boolean"}},"additionalProperties":true},"DeviceRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"FCM-токен, 20–4096 символов"},"platform":{"type":"string","enum":["android","ios","web"]},"deviceId":{"type":"string"}},"additionalProperties":true},"LibraryUpsertRequest":{"type":"object","properties":{"status":{"type":"string","enum":["planned","in_progress","completed","on_hold","dropped","favorite"]},"notify":{"type":"boolean"},"rating":{"oneOf":[{"type":"number","minimum":0,"maximum":10},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"customLists":{"type":"array","items":{"type":"string"}},"lastChapter":{"type":"string"},"lastVolume":{"type":"integer"},"season":{"type":"integer"},"episode":{"type":"string"},"position":{"type":"number"}},"additionalProperties":true},"LibraryBulkRequest":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","description":"Идентификаторы записей библиотеки","items":{"type":"string"}},"status":{"type":"string","enum":["planned","in_progress","completed","on_hold","dropped","favorite"]},"remove":{"type":"boolean"}},"additionalProperties":true},"ProgressSaveRequest":{"type":"object","required":["novelId","chapter"],"properties":{"novelId":{"type":"string"},"chapter":{"oneOf":[{"type":"string"},{"type":"number"}]},"volume":{"type":"integer"},"percent":{"type":"number","minimum":0,"maximum":100}},"additionalProperties":true},"ProgressSyncRequest":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["novelId","chapter"],"properties":{"novelId":{"type":"string"},"chapter":{"oneOf":[{"type":"string"},{"type":"number"}]},"volume":{"type":"integer"},"at":{"type":"integer","description":"Клиентское время, мс — по нему решается, чья позиция свежее"}},"additionalProperties":true}}},"additionalProperties":true},"CommentCreateRequest":{"type":"object","required":["targetType","targetId","content"],"properties":{"targetType":{"type":"string","description":"novel | manga | chapter | art | …"},"targetId":{"type":"string"},"content":{"type":"string","description":"1–5000 символов"},"parentId":{"type":"string","description":"Ответ на комментарий"},"isAnonymous":{"type":"boolean"}},"additionalProperties":true},"NotificationsReadRequest":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}}},"additionalProperties":true},"NotificationSettingsRequest":{"type":"object","properties":{"kinds":{"type":"object","additionalProperties":{"type":"boolean"},"description":"Меняются только присланные категории"}},"additionalProperties":true}},"responses":{"Unauthorized":{"description":"Нет или истёк Bearer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Действие запрещено: бан, закрытый профиль, чужая запись","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Тайтл, глава или запись не найдены","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Gone":{"description":"Одноразовый код уже использован","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ValidationError":{"description":"Неверное тело или параметры; `messages[]` — по полям","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Слишком много запросов; повторите после Retry-After","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"VolumeTooLarge":{"description":"Том больше 4 МиБ: скачивайте главы по одной","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}