Документация API

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

Base URL: https://piarflow.com/v1 JSON API Bearer token
1Получи API keyЗарегистрируй трафик-бота или запроси ключ по bot token.
2Запроси заданияВызови /sponsors и покажи пользователю ссылки из ответа.
3Проверь результатПередай ссылки в /sponsors/check и открой доступ, если всё выполнено.

Авторизация

Передавай 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"
  }
}

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

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

Вебхук отписок

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Ссылка на задание или канал
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})

Статусы заданий

СтатусОписание
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())

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

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