Документация API
Подключи задания PiarFlow в Telegram-бота: получи список спонсоров, покажи кнопки пользователю и проверь выполнение перед выдачей доступа.
/sponsors и покажи пользователю ссылки из ответа./sponsors/check и открой доступ, если всё выполнено.Авторизация
Передавай API key из кабинета бота в заголовке каждого запроса.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Регистрация трафик-бота
Добавляет или обновляет трафик-бота по Telegram bot token и возвращает API key для дальнейших запросов.
Request Body
{
"chat_id": 123456789,
"bot_token": "1234567890:AAExampleBotToken"
}
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
chat_id | integer | Да | Telegram ID владельца бота |
bot_token | string | Да | Токен Telegram-бота от BotFather |
Response
{
"status": "ok",
"message": "Bot registered",
"api_key": "YOUR_TRAFFIC_BOT_API_KEY",
"bot": {
"bot_id": 1234567890,
"chat_id": 123456789,
"username": "example_ref_bot",
"title": "Example Ref Bot",
"topic": "Финансы",
"is_active": true,
"max_sponsors": 3,
"reset_time": 60,
"sold_subs": 12,
"not_counted": 1,
"earned": "24.50"
}
}
Получение API key бота
Возвращает API key зарегистрированного трафик-бота по его Telegram bot token. Если бот ещё не зарегистрирован, передай chat_id, чтобы сразу зарегистрировать его.
Request Body
{
"bot_token": "1234567890:AAExampleBotToken",
"chat_id": 123456789
}
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
bot_token | string | Да | Токен Telegram-бота |
chat_id | integer | Нет | Telegram ID владельца; нужен для первой регистрации |
Response
{
"status": "ok",
"api_key": "YOUR_TRAFFIC_BOT_API_KEY",
"bot": {
"bot_id": 1234567890,
"chat_id": 123456789,
"username": "example_ref_bot",
"title": "Example Ref Bot",
"topic": "Финансы",
"is_active": true,
"max_sponsors": 3,
"reset_time": 60,
"sold_subs": 12,
"not_counted": 1,
"earned": "24.50"
}
}
Данные и статистика бота
Возвращает данные трафик-бота по API key.
curl -H "Authorization: Bearer YOUR_TRAFFIC_BOT_API_KEY" https://piarflow.com/v1/traffic_bot
Response
{
"status": "ok",
"bot": {
"bot_id": 1234567890,
"chat_id": 123456789,
"username": "example_ref_bot",
"title": "Example Ref Bot",
"topic": "Финансы",
"is_active": true,
"max_sponsors": 3,
"reset_time": 60,
"sold_subs": 12,
"not_counted": 1,
"earned": "24.50"
}
}
Возвращает статистику конкретного бота за дату в формате YYYY-MM-DD. API key можно передать в заголовке Authorization или в JSON-поле api_key.
GET Request
curl -H "Authorization: Bearer YOUR_TRAFFIC_BOT_API_KEY" "https://piarflow.com/v1/traffic_bot/stats?date=2026-06-15"
POST Request Body
{
"api_key": "YOUR_TRAFFIC_BOT_API_KEY",
"date": "2026-06-15"
}
Response
{
"status": "ok",
"date": "2026-06-15",
"bot": {
"bot_id": 1234567890,
"chat_id": 123456789,
"username": "example_ref_bot",
"title": "Example Ref Bot",
"topic": "Финансы",
"is_active": true,
"max_sponsors": 3,
"reset_time": 60,
"sold_subs": 12,
"not_counted": 1,
"earned": "24.50"
},
"stats": {
"sold_subs": 4,
"earned": "4.08"
}
}
Получение спонсоров
Главный метод интеграции. Передай Telegram ID пользователя и ID чата, получи список ссылок и покажи их кнопками в боте.
Request Body
{
"user_id": 123456789,
"chat_id": 123456789,
"max_sponsors": 5
}
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
user_id | integer | Да | Telegram ID пользователя |
chat_id | integer | Да | Telegram ID чата |
max_sponsors | integer | Нет | Количество заданий |
Response
{
"status": "ok",
"message": "Sponsors returned",
"sponsors": [
{
"link": "https://t.me/cryptonews",
"status": "unsubscribed",
"price": 5
},
{
"link": "https://t.me/PiarFlowBot",
"status": "unsubscribed",
"price": 0
}
]
}
Проверка заданий
Request Body
{
"user_id": 123456789,
"links": [
"https://t.me/cryptonews"
]
}
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
user_id | integer | Да | Telegram ID пользователя |
links | string[] | Да | Ссылки на задания |
Response
{
"status": "ok",
"sponsors": [
{
"link": "https://t.me/cryptonews",
"status": "subscribed"
}
]
}
Вебхук отписок
PiarFlow отправляет POST запрос на ваш HTTPS endpoint, когда пользователь отписался от задания. URL вебхука настраивается в боте PiarFlow в разделе продажи трафика.
Ваш endpoint должен принять JSON и вернуть любой успешный HTTP статус 200-299. Тело ответа не используется, поэтому достаточно вернуть {"ok": true}.
Request от PiarFlow
{
"tg_user_id": 12344566,
"offer_link": "https://t.me/telegram",
"status": "unsubscribed",
"chat_id": -1001234567890,
"bot_id": 1234567890
}
| Поле | Тип | Описание |
|---|---|---|
tg_user_id | integer | Telegram ID пользователя, который отписался |
offer_link | string | Ссылка на задание или канал |
status | string | Статус события. Сейчас отправляется unsubscribed |
chat_id | integer | Telegram ID чата, если он известен |
bot_id | integer | Telegram ID бота, если он известен |
test | boolean | Есть только в тестовом запросе при подключении вебхука |
Как должен отвечать ваш webhook
HTTP/1.1 200 OK
Content-Type: application/json
{
"ok": true
}
Если endpoint ответит ошибкой или не ответит за 10 секунд, PiarFlow считает отправку неуспешной.
Пример обработчика на aiohttp
from aiohttp import web
async def piarflow_webhook(request: web.Request) -> web.Response:
payload = await request.json()
if payload.get("test"):
return web.json_response({"ok": True})
if payload.get("status") == "unsubscribed":
tg_user_id = int(payload["tg_user_id"])
offer_link = str(payload["offer_link"])
# Здесь можно закрыть доступ пользователю или обновить свою базу.
return web.json_response({"ok": True})
Статусы заданий
| Статус | Описание |
|---|---|
subscribed | Пользователь выполнил задание |
unsubscribed | Задание не выполнено |
not_counted | Выполнение засчитано, но деньги не начислено |
Ошибки
| HTTP Code | Описание |
|---|---|
400 | Неверный запрос |
401 | Неверный API ключ |
404 | Задания не найдены |
429 | Слишком много запросов |
500 | Внутренняя ошибка сервера |
Пример интеграции aiogram + aiohttp
Готовая схема для бота: запросить задания, показать кнопки, проверить выполнение. API key храни в переменных окружения, а ClientSession переиспользуй.
import asyncio
import os
import aiohttp
from aiogram import Bot, Dispatcher, F, Router
from aiogram.filters import CommandStart
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message
BOT_TOKEN = os.getenv("BOT_TOKEN")
PIARFLOW_API_KEY = os.getenv("PIARFLOW_API_KEY")
PIARFLOW_API_URL = "https://piarflow.com/v1"
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
router = Router()
pending_links: dict[int, list[str]] = {}
async def piarflow_request(
session: aiohttp.ClientSession,
method: str,
path: str,
payload: dict | None = None,
) -> dict:
async with session.request(
method,
f"{PIARFLOW_API_URL}{path}",
json=payload,
headers={
"Authorization": f"Bearer {PIARFLOW_API_KEY}",
"Content-Type": "application/json",
},
) as response:
data = await response.json(content_type=None)
if response.status >= 400:
raise RuntimeError(data.get("message") or f"PiarFlow error {response.status}")
return data
def sponsors_keyboard(sponsors: list[dict]) -> InlineKeyboardMarkup:
buttons = [
[InlineKeyboardButton(text="Выполнить задание", url=sponsor["link"])]
for sponsor in sponsors
]
buttons.append([InlineKeyboardButton(text="Проверить", callback_data="piarflow:check")])
return InlineKeyboardMarkup(inline_keyboard=buttons)
@router.message(CommandStart())
async def start_handler(message: Message, session: aiohttp.ClientSession) -> None:
user_id = message.from_user.id
tasks = await piarflow_request(
session,
"POST",
"/sponsors",
{
"user_id": user_id,
"chat_id": message.chat.id,
"max_sponsors": 5,
},
)
sponsors = tasks.get("sponsors") or []
if not sponsors:
await message.answer("Сейчас нет доступных заданий.")
return
links = [sponsor["link"] for sponsor in sponsors]
await message.answer(
"Подпишись на спонсоров, затем нажми Проверить.",
reply_markup=sponsors_keyboard(sponsors),
)
pending_links[user_id] = links
@router.callback_query(F.data == "piarflow:check")
async def check_handler(callback: CallbackQuery, session: aiohttp.ClientSession) -> None:
user_id = callback.from_user.id
links = pending_links.get(user_id, [])
result = await piarflow_request(
session,
"POST",
"/sponsors/check",
{"user_id": user_id, "links": links},
)
sponsors = result.get("sponsors") or []
if sponsors and all(item.get("status") == "subscribed" for item in sponsors):
await callback.message.answer("Все задания выполнены. Доступ открыт.")
pending_links.pop(user_id, None)
else:
await callback.message.answer("Не все задания выполнены. Проверь подписки и попробуй снова.")
await callback.answer()
async def main() -> None:
timeout = aiohttp.ClientTimeout(total=15)
async with aiohttp.ClientSession(timeout=timeout) as session:
dp.workflow_data["session"] = session
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())