PiarFlow API Reference
Документация для подключения заданий PiarFlow к Telegram-ботам. Основной сценарий: получить задания для пользователя, показать ссылки, проверить выполнение и только после этого открыть доступ.
/sponsors возвращает ссылки, которые нужно показать пользователю./sponsors/check сообщает, какие задания выполнены./traffic_bot/add и /traffic_bot/api_key нужны для ключа.Обзор методов
Главные методы интеграции — получить задания и проверить их выполнение. Методы регистрации и статистики нужны для настройки трафик-источника и управления API key.
/sponsorsПолучение спонсоровВозвращает задания для конкретного пользователя.
POST /sponsors/checkПроверка заданийПроверяет подписки перед выдачей доступа.
POST /traffic_bot/addРегистрация трафик-ботаСоздаёт или обновляет бота и возвращает API key.
POST /traffic_bot/api_keyПолучение API keyВозвращает ключ по Telegram bot token.
GET /traffic_botДанные ботаПрофиль, лимиты, продажи и заработок трафик-бота.
GET /traffic_bot/statsСтатистикаСтатистика конкретного бота за выбранную дату.
Получение спонсоров
Главный метод интеграции. Передай 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"
}
]
}
Статусы заданий
| Статус | Описание |
|---|---|
subscribed | Пользователь выполнил задание |
unsubscribed | Задание не выполнено |
not_counted | Выполнение засчитано, но деньги не начислено |
Авторизация
Передавай 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"
}
}
Вебхук отписок
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 | Ссылка, по которой пользователь выполнил задание. Для заданий с трекингом — персональная https://piarflow.com/track?...; иначе ссылка на ресурс или канал. |
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})
Ошибки
| HTTP Code | Описание |
|---|---|
400 | Неверный запрос |
401 | Неверный API ключ |
404 | Задания не найдены |
429 | Слишком много запросов |
500 | Внутренняя ошибка сервера |
Примеры запросов
Ниже один и тот же базовый сценарий на разных языках: запросить задания для пользователя и затем проверить выполнение. API key передаётся в заголовке Authorization.
Получить задания: POST /sponsors
curl -X POST "https://piarflow.com/v1/sponsors" -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"user_id": 123456789,
"chat_id": 123456789,
"max_sponsors": 5
}'
const response = await fetch("https://piarflow.com/v1/sponsors", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PIARFLOW_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: 123456789,
chat_id: 123456789,
max_sponsors: 5,
}),
});
const data = await response.json();
if (!response.ok) throw new Error(data.message || "PiarFlow error");
console.log(data.sponsors);
import os
import requests
response = requests.post(
"https://piarflow.com/v1/sponsors",
headers={
"Authorization": f"Bearer {os.environ['PIARFLOW_API_KEY']}",
"Content-Type": "application/json",
},
json={
"user_id": 123456789,
"chat_id": 123456789,
"max_sponsors": 5,
},
timeout=15,
)
response.raise_for_status()
sponsors = response.json()["sponsors"]
$payload = json_encode([
"user_id" => 123456789,
"chat_id" => 123456789,
"max_sponsors" => 5,
]);
$ch = curl_init("https://piarflow.com/v1/sponsors");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("PIARFLOW_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => $payload,
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
Проверить выполнение: POST /sponsors/check
curl -X POST "https://piarflow.com/v1/sponsors/check" -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"user_id": 123456789,
"links": ["https://t.me/cryptonews"]
}'
const response = await fetch("https://piarflow.com/v1/sponsors/check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PIARFLOW_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: 123456789,
links: ["https://t.me/cryptonews"],
}),
});
const result = await response.json();
const completed = result.sponsors.every(
(item) => item.status === "subscribed",
);
response = requests.post(
"https://piarflow.com/v1/sponsors/check",
headers={"Authorization": f"Bearer {os.environ['PIARFLOW_API_KEY']}"},
json={
"user_id": 123456789,
"links": ["https://t.me/cryptonews"],
},
timeout=15,
)
response.raise_for_status()
completed = all(
item["status"] == "subscribed"
for item in response.json()["sponsors"]
)
$payload = json_encode([
"user_id" => 123456789,
"links" => ["https://t.me/cryptonews"],
]);
$ch = curl_init("https://piarflow.com/v1/sponsors/check");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("PIARFLOW_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => $payload,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
Полный пример 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())