Roxera Premium · API для разработчиковВсё управление подпиской (привязка Telegram, оплата Stars/CryptoBot, продление) живёт в почте и в боте. Ваш сайт делает только два шага: кнопка входа и проверка isPremium для аккаунта.
Auth-домен: oauth.roxera.net (виджет, вход). API отвечает и там, и на premium.roxera.net — один сервис.
Ванильный JS, без зависимостей. Клик открывает popup хаба с выбором аккаунта (как Google Sign-In) — пароль вводится только на хабе, ваш сайт его никогда не видит.
<script src="https://oauth.roxera.net/widget.js"
data-api="https://oauth.roxera.net"></script>
<div data-roxera-login></div>
<script>
// u = { email, tier: 'free'|'premium', until, entitlements, linked }
RoxeraAuth.onLogin(function (u) {
if (u.tier === 'premium') unlockPro(u.entitlements);
else lockPro();
});
</script>
События window: roxera:login, roxera:logout. Методы: RoxeraAuth.signin(), signout(), user(), isPremium(), status(email), onLogin(fn). Состояние: localStorage 'roxera.auth.v1'.
Свой сервис с прямым Firebase-входом (как почта)? Подскажите хабу email юзера — и chooser покажет его как у Google:
// После вашего signIn: RoxeraAuth.remember(user.email);
Если ваш бэкенд доверяет проекту (см. SSO_GRANTS), хаб вернёт customToken — сайт входит в свой Firebase-проект, как будто пользователь авторизовался у него:
const u = await RoxeraAuth.signin({ project: 'r0xera' });
// u = { email, tier, entitlements, customToken, ... }
import { getAuth, signInWithCustomToken } from 'firebase/auth';
await signInWithCustomToken(getAuth(), u.customToken); // реальная сессия вашего проекта
// Строгая проверка для своего бэкенда — обмен ID-токена на custom token:
curl -X POST https://oauth.roxera.net/v1/auth/custom-token \
-H 'content-type: application/json' \
-d '{"idToken":"ROXERA_ID_TOKEN","project":"r0xera","origin":"https://link.s-g.lol"}'
Пара origin → project выдаётся только из allowlist. Юзер ищется по email: если он уже входил через Google/пароль — сессия сольётся в тот же аккаунт (link-эффект).
/v1/premium/status?email= — публичный, для UIcurl 'https://premium.roxera.net/v1/premium/status?email=user@mail.roxera.net'
# {"email":"...","tier":"premium","until":"2026-10-29T...","entitlements":{...}}
| Поле entitlements | Free | Premium 💛 |
|---|---|---|
boxes — лимит сущностей | 1 | 10 |
dailyQuota — лимит в день | 10 | 30 |
verified — галочка | false | true |
premiumDomains | [] | ["xye-coc.online","xyeglot.online"] |
tempExtend | false | true |
/v1/premium/verify — строгий, для своего бэкендаКлиент присылает Firebase ID token, сервер сам валидирует его в Google. Email из query брать нельзя — его можно подделать, токен — нет.
curl -X POST https://oauth.roxera.net/v1/premium/verify \
-H 'content-type: application/json' -d '{"idToken":"FIREBASE_ID_TOKEN"}'
# {"ok":true,"uid":"...","email":"...","tier":"premium","until":"...","entitlements":{...},"linked":{...}|null}
// Python (свой бэкенд):
import urllib.request, json
body = json.dumps({"idToken": id_token_from_client}).encode()
tier = json.load(urllib.request.urlopen("https://oauth.roxera.net/v1/premium/verify", body))["tier"]
give_pro = (tier == "premium")
| Метод | Путь | Назначение |
|---|---|---|
| GET | /v1/health | Живость |
| GET | /v1/premium/plans | Тариф и лимиты из конфига (не хардкодьте цены) |
| GET | /v1/premium/config | Публичный конфиг (bot username, флаги) |
Ошибки: bad_email (400), unauthorized (401), forbidden (403), rate_limited (429). Всё остальное — привязка, оплата, отвязка — пользователь делает в почте и в боте, не у вас.