Документация для Telegram-ботов

PiarFlow API для монетизации трафика

Подключи задания PiarFlow в своего бота: получай спонсоров, показывай ссылки пользователю и проверяй выполнение перед выдачей доступа.

Быстрый старт

JSONпростые запросы и ответы для backend-интеграции
BearerAPI key трафик-бота в заголовке Authorization
3 шагаполучи ключ, запроси задания, проверь подписки

PiarFlow API Reference

Документация для подключения заданий PiarFlow к Telegram-ботам. Основной сценарий: получить задания для пользователя, показать ссылки, проверить выполнение и только после этого открыть доступ.

Base URL: https://piarflow.com/v1 JSON API Bearer token
1Получи задания/sponsors возвращает ссылки, которые нужно показать пользователю.
2Проверь подписки/sponsors/check сообщает, какие задания выполнены.
3Подключи API key/traffic_bot/add и /traffic_bot/api_key нужны для ключа.
4Обработай отпискиWebhook помогает закрыть доступ, если пользователь отписался.

Обзор методов

Главные методы интеграции — получить задания и проверить их выполнение. Методы регистрации и статистики нужны для настройки трафик-источника и управления API key.

Получение спонсоров

POST/sponsors

Главный метод интеграции. Передай Telegram ID пользователя и ID чата, получи список ссылок и покажи их кнопками в боте.

Request Body

{
  "user_id": 123456789,
  "chat_id": 123456789,
  "max_sponsors": 5
}
ПараметрТипОбязательноОписание
user_idintegerДаTelegram ID пользователя
chat_idintegerДаTelegram ID чата
max_sponsorsintegerНетКоличество заданий

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
    }
  ]
}

Проверка заданий

POST/sponsors/check

Request Body

{
  "user_id": 123456789,
  "links": [
    "https://t.me/cryptonews"
  ]
}
ПараметрТипОбязательноОписание
user_idintegerДаTelegram ID пользователя
linksstring[]ДаСсылки на задания

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

Регистрация трафик-бота

POST/v1/traffic_bot/add
POST/traffic_bot:add

Добавляет или обновляет трафик-бота по Telegram bot token и возвращает API key для дальнейших запросов.

Request Body

{
  "chat_id": 123456789,
  "bot_token": "1234567890:AAExampleBotToken"
}
ПараметрТипОбязательноОписание
chat_idintegerДаTelegram ID владельца бота
bot_tokenstringДаТокен 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 бота

POST/v1/traffic_bot/api_key

Возвращает API key зарегистрированного трафик-бота по его Telegram bot token. Если бот ещё не зарегистрирован, передай chat_id, чтобы сразу зарегистрировать его.

Request Body

{
  "bot_token": "1234567890:AAExampleBotToken",
  "chat_id": 123456789
}
ПараметрТипОбязательноОписание
bot_tokenstringДаТокен Telegram-бота
chat_idintegerНет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"
  }
}

Данные и статистика бота

GET/v1/traffic_bot

Возвращает данные трафик-бота по 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"
  }
}
GET/v1/traffic_bot/stats?date=YYYY-MM-DD
POST/v1/traffic_bot/stats

Возвращает статистику конкретного бота за дату в формате 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_idintegerTelegram ID пользователя, который отписался
offer_linkstringСсылка, по которой пользователь выполнил задание. Для заданий с трекингом — персональная https://piarflow.com/track?...; иначе ссылка на ресурс или канал.
statusstringСтатус события. Сейчас отправляется unsubscribed
chat_idintegerTelegram ID чата, если он известен
bot_idintegerTelegram ID бота, если он известен
testbooleanЕсть только в тестовом запросе при подключении вебхука

Как должен отвечать ваш 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.

В production храни API key в переменных окружения или secret manager. Не вставляй ключ прямо в frontend-код.

Получить задания: POST /sponsors

cURLshell
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
  }'
JavaScriptNode.js / fetch
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);
Pythonrequests
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"]
PHPcURL extension
$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

cURLshell
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"]
  }'
JavaScriptNode.js / fetch
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",
);
Pythonrequests
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"]
)
PHPcURL extension
$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())

Логика работы

1Пользователь открывает бота
2Бот вызывает /sponsors
3API возвращает задания
4Пользователь выполняет задания
5Бот вызывает /sponsors/check
6API возвращает статусы
7Если всё выполнено, открыть доступ