Premium API
Roxera Premium — подписка на проекты Roxera: $5 за 30 дней или 250 Telegram Stars. Автопродления нет: каждая оплата добавляет 30 дней к текущему сроку.
| Параметр | Free | Premium |
|---|---|---|
| Цена | 0 | $5 / 30 дней · 250 XTR |
| Почтовые ящики | 1 | 3 |
| Хранилище почты | 1 ГБ | 10 ГБ |
| Временная почта | 15 минут · 1 адрес | 24 часа · 5 адресов |
| Uptime | 50 мониторов · 5 минут | 200 мониторов · 1 минута |
| Links | 100 активных ссылок | 5 000 активных ссылок |
| QR | 3 динамических | без лимита |
| Proxy | 10 ГБ · 7 дней | 20 ГБ · 14 дней |
| Zonu.org | 1 домен | 3 домена |
Публичные endpoint’ы
GET https://premium.roxera.net/api/v1/premium/plans
GET https://premium.roxera.net/api/v1/premium/projects
plans возвращает цены и полный объект лимитов. projects — включённые проекты
из реестра (ключ, имя, URL, описание, иконка). Classroom в реестр не входит.
{
"plans": [
{ "code": "free", "name": "Free", "priceUsd": 0, "periodDays": 0 },
{ "code": "premium", "name": "Premium", "priceUsd": 5, "priceStars": 250, "periodDays": 30 }
],
"currency": "USD",
"starsCurrency": "XTR"
}
Проверка для first-party проекта
Проекты на поддоменах .roxera.net используют общую cookie. Передайте её на API —
и получите статус и лимиты без OIDC-редиректа.
POST https://mail.roxera.net/api/v1/premium/check
Content-Type: application/json
{ "projectKey": "uptime" }
{
"projectKey": "uptime",
"premium": true,
"tier": "premium",
"until": "2029-06-24T12:58:14.476Z",
"limits": { "monitors": 200, "intervalSec": 60, "historyDays": 365 },
"entitlements": {
"mail": { "boxes": 3, "storageGb": 10 },
"uptime": { "monitors": 200, "intervalSec": 60 },
"link": { "activeLinks": 5000 }
}
}
Есть и короткая GET-версия для UI-бейджа:
GET https://mail.roxera.net/api/v1/premium/check/uptime
Ответ содержит premium, tier, until и limits для указанного проекта.
Проверка с сервера (ключ проекта)
Для вызовов «сервис→хаб» без cookie выпустите ключ проекта в админке
(/admin/#projects → «Ключи»). Ключ имеет вид rx_pk_..., в базе хранится
только его хэш, значение видно один раз. Передайте его в заголовке
Authorization: Bearer:
POST https://mail.roxera.net/api/v1/premium/check
Authorization: Bearer rx_pk_xxx_yyy
Content-Type: application/json
{ "email": "user@example.com", "metric": "monitors", "amount": 1 }
{
"ok": true,
"projectKey": "uptime",
"tier": "premium",
"limit": 200,
"used": 8,
"remaining": 192,
"allowed": true
}
used — дневной счётчик (usage_counters, сброс в 00:00 UTC), allowed
становится false при превышении лимита. Ключ можно ограничить набором метрик
(scopes): чужие метрики получают 403 scope_required.
Серверный middleware
import type { NextFunction, Request, Response } from 'express';
interface PremiumCheck {
premium: boolean;
tier: 'free' | 'premium';
until: string | null;
limits: { monitors: number; intervalSec: number } | null;
}
export async function requirePremiumUptime(req: Request, res: Response, next: NextFunction) {
const response = await fetch('https://mail.roxera.net/api/v1/premium/check', {
method: 'POST',
headers: {
'content-type': 'application/json',
cookie: req.headers.cookie ?? '',
},
body: JSON.stringify({ projectKey: 'uptime' }),
});
if (!response.ok) return res.status(401).json({ error: 'unauthorized' });
const premium = (await response.json()) as PremiumCheck;
if (!premium.premium) {
return res.status(402).json({
error: 'premium_required',
upgradeUrl: 'https://premium.roxera.net/#pricing',
});
}
res.locals.premium = premium;
next();
}
Ограничение по метрике
Лимиты — это числа, а не только флаг. Проверяйте количество ресурсов проекта:
const check = await response.json();
const used = await db.countMonitors(user.id);
if (used >= check.limits.monitors) {
return res.status(402).json({ error: 'limit_reached', limit: check.limits.monitors });
}
Счётчики использования (usage_counters) ведутся внутри проекта. Roxera не хранит
чужие мониторы и ссылки — только статус подписки и entitlements.
Внешний проект через OAuth
Если проект не на .roxera.net, cookie недоступна. Проверяйте ID token или
запрашивайте userinfo с access token:
const response = await fetch('https://oauth.roxera.net/oauth/userinfo', {
headers: { authorization: `Bearer ${accessToken}` },
});
const profile = await response.json();
if (profile.active) {
// Premium активен до profile.until
}
В ID token уже есть claims premium, premium_until, plan. Для UI достаточно
premium; для выдачи лимитов используйте entitlements из userinfo.
Кэшируйте результат на 60 секунд по
sub+until. Не запрашивайте userinfo на каждый HTTP-запрос.
Реестр проектов
| Проект | Ключ | URL |
|---|---|---|
| Roxera Mail | mail |
https://mail.roxera.net |
| Roxera Uptime | uptime |
https://uptime.roxera.net |
| Roxera Links | link |
https://link.s-g.lol |
| Roxera Cases | case |
https://case.roxera.net |
| Roxera Proxy | proxy |
https://proxy.roxera.net |
| Roxera QR | qr |
https://qr.roxera.net |
| Zonu.org | domains |
https://nic.zonu.org |
| Roxera Premium | premium |
https://premium.roxera.net |
Список хранится в SQLite и редактируется в админке (/admin/#projects). Лендинг
подтягивает его через /api/v1/premium/projects без пересборки.
Оплата
| Способ | Сумма | Endpoint |
|---|---|---|
| Telegram Stars | 250 XTR | POST /api/v1/premium/checkout/stars |
| CryptoBot | 5 USDT | POST /api/v1/premium/checkout/crypto |
Оба endpoint’а требуют cookie Roxera ID. Ответ содержит invoiceUrl (Stars) или
payUrl (CryptoBot). После оплаты статус обновляется автоматически; в личном
кабинете есть кнопка «Обновить статус».
const response = await fetch('/api/v1/premium/checkout/stars', {
method: 'POST',
credentials: 'include',
});
const { invoiceUrl } = await response.json();
window.location.href = invoiceUrl;
Ручные продления и возвраты выполняет администратор — каждое действие попадает в audit log. Промокодов, рефералок и автосписаний нет.
Личные ключи и вебхуки
В кабинете (/account) пользователь может выпустить личный API-ключ
(rx_k_..., область premium:read) и добавить вебхук на событие
payment.paid.
Личный ключ заменяет cookie на GET /api/v1/premium/status и
POST /api/v1/premium/check — для скриптов самого пользователя:
GET https://mail.roxera.net/api/v1/premium/status
Authorization: Bearer rx_k_xxx_yyy
Вебхук получает POST при оплате Premium. Тело подписано HMAC-SHA256 секретом вебхука (значение видно один раз при создании):
POST https://example.com/roxera
X-Roxera-Event: payment.paid
X-Roxera-Signature: sha256=<hex hmac>
Content-Type: application/json
{ "event": "payment.paid", "deliveryId": "...", "sentAt": "...", "data": { ... } }
Доставку выполняет воркер: только https, с защитой от SSRF (проверка
разрешённого IP перед запросом). При не-2xx ответе запрос повторяется; последний
статус виден в кабинете.
Как добавить новый проект
- Добавьте запись в
projectsчерез админку (/admin/#projects) с уникальнымkey. - Добавьте лимиты в
packages/shared/src/plans.tsдля Free и Premium. - Создайте OAuth-клиент и redirect URI в
/admin/#oauth. - В проекте проверяйте
/api/v1/premium/check(если он на.roxera.net) илиuserinfo(если внешний). - Ограничьте функции по
limits, а не по названию тарифа.