Управление подписками

API подписок: управление доступами

Документ для внешних серверов: выдача, продление, отзыв и просмотр доступов к каналам/чатам бота подписок.

Хост: https://api.bot-t.com. Все методы — POST, тело application/json.

Бот должен быть ботом подписок. Лимит: 120 запросов в минуту с одного IP.


Авторизация

В каждом запросе: bot_id и один секрет.

ПолеГде взять
tokenТокен бота из BotFather
secretKeyСекретный ключ бота в кабинете

Секрет — в query или в теле. Токен и секрет храните только на своём сервере.

POST https://api.bot-t.com/v1/subscriber/users/grant?token=123456:ABC
Content-Type: application/json

{ "bot_id": 1, "telegram_id": 123456789, "resource_id": 3, "tariff_id": 12 }

Ответ

{ "result": true, "data": {} }
{ "result": false, "message": "текст ошибки" }

Булевы операции часто возвращают data строкой "1". Даты без пометки — в часовом поясе бота, ГГГГ-ММ-ДД ЧЧ:ММ:СС. Допустим unix timestamp.

Идентификаторы

ПолеЧто это
user_idВнутренний ID пользователя в BOT-T (users.id), не Telegram ID
telegram_idTelegram ID
resource_idГруппа ресурсов (каналы/чаты)
tariff_idТариф группы
idID купленной подписки (записи доступа)

user_id в методах ниже — системный. В grant можно передать telegram_id вместо него.

Статус покупки

ЗначениеСмысл
1не оплачена
2оплачена, доступ активен
3срок истёк
4ожидает оплаты

Клиент

Python

import requests

API = "https://api.bot-t.com"
TOKEN = "123456:ABC"
BOT_ID = 1

def call(path, **body):
    response = requests.post(
        f"{API}{path}",
        params={"token": TOKEN},
        json={"bot_id": BOT_ID, **body},
        timeout=30,
    )
    response.raise_for_status()
    payload = response.json()
    if not payload.get("result"):
        raise RuntimeError(payload.get("message", "ошибка API"))
    return payload["data"]

JavaScript

const API = "https://api.bot-t.com";
const TOKEN = "123456:ABC";
const BOT_ID = 1;

async function call(path, body = {}) {
  const response = await fetch(`${API}${path}?token=${encodeURIComponent(TOKEN)}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ bot_id: BOT_ID, ...body }),
  });
  const payload = await response.json();
  if (!payload.result) {
    throw new Error(payload.message || "ошибка API");
  }
  return payload.data;
}

Выдать доступ пользователю

POST /v1/subscriber/users/grant

Создаёт оплаченную подписку от имени администратора и отправляет приглашение в каналы/чаты группы (как ручная выдача в кабинете).

Ограничения:

  • пользователь уже должен хотя бы раз написать боту (быть в боте);
  • тариф должен принадлежать группе, быть обычным (не пробным);
  • активный доступ на ту же группу будет закрыт и заменён новым периодом.
ПолеОбяз.Описание
user_idда*Системный ID
telegram_idда*Telegram ID (альтернатива user_id)
resource_idдаГруппа
tariff_idдаТариф этой группы
accrue_referral_bonusнет1 по умолчанию — начислить реферальный бонус; 0 — нет

* Нужно одно из двух.

access = call(
    "/v1/subscriber/users/grant",
    telegram_id=123456789,
    resource_id=3,
    tariff_id=12,
    accrue_referral_bonus=0,
)
# access["id"], access["status"] == 2, access["end_paid_at"], ...
const access = await call("/v1/subscriber/users/grant", {
  telegram_id: 123456789,
  resource_id: 3,
  tariff_id: 12,
  accrue_referral_bonus: 0,
});

data — объект покупки (см. поля ниже).

Выдать ссылку без пользователя

POST /v1/subscriber/users/issue-link

Одноразовые invite-ссылки (member_limit = 1) на все каналы/чаты группы. Срок — длительность тарифа от текущего момента (не больше 1 года — лимит Telegram). Запись подписчика не создаётся.

ПолеОбяз.
resource_idда
tariff_idда (включённый, не пробный)
{
  "result": true,
  "data": {
    "invite": "Название: https://t.me/+…",
    "expire_date": 1767225600,
    "resource_id": 3,
    "tariff_id": 12
  }
}

Список и просмотр

Покупки по боту / группе

POST /v1/subscriber/users/index

ПолеОбяз.Описание
resource_idнетОдна группа; без поля — все группы бота
statusнетФильтр статуса
user_idнетФильтр покупателя
tariff_idнетТариф или массив
limitнетПо умолчанию 25, максимум 1000
offsetнетПо умолчанию 0

Количество

POST /v1/subscriber/users/count — те же фильтры, data строкой, например "128".

Покупки одного пользователя

POST /v1/subscriber/users/bot-user-index — обязателен user_id.

POST /v1/subscriber/users/bot-user-count — обязателен user_id.

Одна покупка

POST /v1/subscriber/users/view — обязателен id покупки.

Поля объекта покупки

ПолеОписание
idID покупки
status1–4
userid, telegram_id, username, first_name, last_name, …
resource_id, resource_titleГруппа
tariff_id, tariff_title, tariff_priceТариф
paid_at / end_paid_atНачало / конец доступа, unix UTC
paid_time / end_paid_timeТо же в часовом поясе бота
is_recurrentАвтопродление
can_edit_access_startМожно сдвинуть дату начала

Продлить / сдвинуть сроки

Дата окончания одной покупки

POST /v1/subscriber/users/edit-end-date

ПолеОбяз.
idда
end_paid_timeда — дата в TZ бота или unix

Дата окончания у нескольких

POST /v1/subscriber/users/mass-edit-end-date

ПолеОбяз.Описание
resource_idдаГруппа
end_paid_timeдаНовая дата
idнетМассив ID; без него — все активные доступы группы
{ "result": true, "data": { "updated": 14, "message": "Обновлено записей: 14" } }

Дата начала

POST /v1/subscriber/users/edit-access-start

Только если can_edit_access_start = true (оплачено, период ещё не начался). Длительность сохраняется.

ПолеОбяз.
idда
paid_timeда

Приглашения

МетодНазначение
POST /v1/subscriber/users/inviteБот сам отправит ссылку пользователю (id покупки)
POST /v1/subscriber/users/generate-inviteВернуть текст со ссылкой (data — строка)

Ссылка не выдаётся, если срок истёк или дата начала ещё не наступила.

Подтвердить неоплаченную покупку

POST /v1/subscriber/users/success — id покупки. Отмечает оплату администратором (data = "1").

Выключить автопродление

POST /v1/subscriber/users/remove-rebill — id покупки.

Удалить доступ

POST /v1/subscriber/users/delete

ПолеОбяз.Описание
idдаID или массив ID

Пользователя убирают из ресурса. data = "1".

call("/v1/subscriber/users/delete", id=[501, 502])

Типовые сценарии

CRM выдала оплату → открыть канал

  1. Узнать resource_id и tariff_id (методы resource/index, tariff/index или из кабинета).
  2. grant с telegram_id (или user_id).
  3. При необходимости дождаться вебхука subscription.status_changed со status=2.

Отозвать доступ

delete по id покупки. Вебхук при удалении не отправляется — синхронизируйте у себя сами.

Продлить без новой оплаты

edit-end-date или mass-edit-end-date.

Разовая ссылка без учёта пользователя

issue-link — подходит для офлайн-оплаты / менеджерской выдачи «на руки».


Сводка методов доступа

Ниже — краткий справочник. Во всех запросах обязательны bot_id и секрет (token или secretKey).

POST /v1/subscriber/users/grant — выдать доступ

Создаёт оплаченную подписку от имени администратора и отправляет invite в каналы/чаты группы. Пользователь уже должен быть в боте. Пробный тариф выдать нельзя. Активный доступ на ту же группу закрывается новым периодом.

ПолеОбяз.Описание
user_idда*Системный ID пользователя
telegram_idда*Telegram ID (вместо user_id)
resource_idдаГруппа ресурсов
tariff_idдаОбычный тариф этой группы
accrue_referral_bonusнет1 (по умолчанию) — реф. бонус; 0 — нет

data — объект покупки (status = 2).

POST /v1/subscriber/users/issue-link — ссылка без пользователя

Одноразовые invite-ссылки (member_limit = 1) на все чаты группы. Срок = длительность тарифа от сейчас (не больше 1 года). Запись подписчика не создаётся. Тариф должен быть включён и не пробный.

ПолеОбяз.
resource_idда
tariff_idда

data: invite (строка со ссылками), expire_date (unix), resource_id, tariff_id.

POST /v1/subscriber/users/index — список покупок

Пагинированный список купленных доступов бота. Без resource_id — по всем группам.

ПолеОбяз.Описание
resource_idнетОдна группа
statusнет1–4
user_idнетПокупатель
tariff_idнетТариф или массив
idнетКонкретная покупка
paid_time_start / paid_time_endнетПериод начала доступа
end_paid_time_start / end_paid_time_endнетПериод окончания
created_time_start / created_time_endнетПериод создания записи
paid_at / end_paid_at / notification_atнетСортировка: ASC или DESC
limitнетПо умолчанию 25, максимум 1000
offsetнетПо умолчанию 0

data — массив объектов покупки.

POST /v1/subscriber/users/count — количество покупок

Те же фильтры, что у index (без limit / offset / сортировки).

data — число строкой, например "128".

POST /v1/subscriber/users/bot-user-index — покупки одного пользователя

Все доступы пользователя по всем группам бота.

ПолеОбяз.Описание
user_idдаСистемный ID
фильтры / limit / offsetнетКак у index

data — массив объектов покупки.

POST /v1/subscriber/users/bot-user-count — сколько покупок у пользователя

ПолеОбяз.
user_idда
фильтрынет

data — число строкой.

POST /v1/subscriber/users/view — одна покупка

ПолеОбяз.
idда — ID покупки

data — объект покупки. Чужую покупку (другого бота) вернуть нельзя.

POST /v1/subscriber/users/success — подтвердить оплату

Отмечает неоплаченную покупку оплаченной администратором (как ручное подтверждение в кабинете): открывает доступ и шлёт приглашение.

ПолеОбяз.
idда — ID покупки

data — "1".

POST /v1/subscriber/users/invite — отправить приглашение

Бот сам пишет пользователю сообщение со ссылками в каналы/чаты по уже выданной покупке.

ПолеОбяз.
idда — ID покупки

data — "ok". Не сработает, если срок истёк или дата начала ещё не наступила.

POST /v1/subscriber/users/generate-invite — получить ссылку

То же приглашение, но без отправки пользователю: ссылка возвращается вам.

ПолеОбяз.
idда — ID покупки

data — строка со ссылками. Те же ограничения по сроку, что у invite.

POST /v1/subscriber/users/edit-end-date — дата окончания одной покупки

Ставит новую дату конца доступа. Если дата ещё в будущем — пересчитывается ближайшее уведомление.

ПолеОбяз.Описание
idдаID покупки
end_paid_timeдаДата в TZ бота или unix timestamp

data — обновлённый объект покупки.

POST /v1/subscriber/users/mass-edit-end-date — дата окончания у нескольких

ПолеОбяз.Описание
resource_idдаГруппа
end_paid_timeдаНовая дата (TZ бота или unix)
idнетМассив ID; без него — все активные (status = 2) доступы группы

data: { "updated": N, "message": "Обновлено записей: N" }.

POST /v1/subscriber/users/edit-access-start — дата начала

Сдвигает начало оплаченного периода. Доступно только если can_edit_access_start = true (оплачено и paid_at ещё в будущем). Длительность сохраняется, конец едет на ту же величину.

ПолеОбяз.Описание
idдаID покупки
paid_timeдаНовая дата начала (TZ бота или unix)

data — обновлённый объект покупки.

POST /v1/subscriber/users/remove-rebill — выключить автопродление

Снимает привязку рекуррентного платежа у покупки. Текущий период доступа не трогает.

ПолеОбяз.
idда — ID покупки

data — "1".

POST /v1/subscriber/users/rebuild-notification — пересчитать уведомления

Пересчитывает и сохраняет дату ближайшего уведомления об окончании. Неактивные записи пропускаются.

ПолеОбяз.Описание
idдаID покупки или массив ID

data — "1".

POST /v1/subscriber/users/delete — удалить доступ

Убирает пользователя из ресурса и удаляет запись(и) покупки. Вебхук при удалении не уходит.

ПолеОбяз.Описание
idдаID покупки или массив ID

data — "1".