Axionna / API docs

Публичная документация API

Подключите один Telegram-бот к Axionna, получайте задания для пользователей и проверяйте их выполнение через единый API.

Base URL: https://axionna.org

Авторизация

Используйте ключ подключённого бота. Передавайте его в каждом запросе и храните только на сервере.

Authorization: Bearer YOUR_BOT_API_KEY
Content-Type: application/json

POST/api/sponsors

Возвращает задания для конкретного пользователя. Сохраните id каждого элемента: он нужен для проверки.

ПолеТипОбязательноОписание
user_idintegerдаTelegram ID пользователя
chat_idintegerдаID чата, где работает бот
max_sponsorsintegerнетКоличество заданий, от 1 до 50
usernamestringнетUsername без символа @
first_namestringнетИмя пользователя
language_codestringнетЯзык Telegram
curl -X POST https://axionna.org/api/sponsors \
  -H "Authorization: Bearer YOUR_BOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":123456789,"chat_id":123456789,"max_sponsors":5}'
{
  "status": "ok",
  "sponsors": [
    {
      "id": "source:task-id",
      "link": "https://t.me/example",
      "title": "Название задания",
      "button_text": "Подписаться"
    }
  ],
  "errors": null
}

POST/api/check

Проверяет выполнение заданий и возвращает результат по каждому из них.

curl -X POST https://axionna.org/api/check \
  -H "Authorization: Bearer YOUR_BOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":123456789,"task_ids":["source:task-id"]}'
{
  "status": "ok",
  "results": [
    {
      "id": "source:task-id",
      "link": "https://t.me/example",
      "status": "subscribed",
      "subscribed": true,
      "credited": true
    }
  ],
  "all_subscribed": true
}
Одно задание оплачивается только один раз. Открывайте доступ пользователю только если все результаты имеют subscribed: true.

Показы и приветственные объявления

Эти форматы позволяют показывать рекламный пост в двух сценариях:

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

Для интеграции используйте персональный API-ключ Axionna, выданный для вашего подключённого бота. Все подключённые боты работают через единую интеграцию Axionna: внешний ключ пользователю не нужен и не передаётся в его код.

POST /api/views
Authorization: Bearer YOUR_BOT_API_KEY
Content-Type: application/json

{"chat_id":123456789,"greeting":false,"impression_id":"job-123"}

Для приветственного режима передайте "greeting": true. Код 1 в поле result означает успешную отправку объявления.

{"status":"ok","delivered":true,"providers":{"internal":{"configured":true,"delivered":true,"result":{"order_id":42,"reward_rub":0.9}},"gramads":{"configured":true,"delivered":false},"botohub":{"configured":true,"delivered":false}}}

Один запрос Axionna отправляет только одно объявление: сначала купленную внутри Axionna кампанию нужного формата, затем GramAds, а при его недоступности — BotoHub. Поле delivered равно true, если объявление отправлено. Для внутренней кампании владелец бота получает выплату, заданную рекламодателем; для внешнего показа действует текущий CPM. Передавайте уникальный impression_id, чтобы повтор запроса не начислил награду повторно.

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

Баланс и статистика

Владелец бота может получить текущий баланс и сводку по подключённым ботам.

POST /api/balance
Authorization: Bearer YOUR_ACCOUNT_TOKEN
{
  "status": "ok",
  "balance": 219.21,
  "bots_info": []
}

Для статистики используйте GET /api/statistic с параметрами api_token, action, start_date и end_date. Доступные действия: allbots, bots, sponsor, allads, ads, source.

Рекламные кампании

Рекламодатель может создавать и управлять кампаниями через POST /api/orders. В каждом запросе передавайте поле action.

ActionНазначениеОсновные поля
createСоздать кампаниюlink, ads_type, quantity_all, price
updateИзменить кампаниюorder_id, is_on, in_archive
infoПолучить данныеorder_id
listПолучить список кампанийнет
POST /api/orders
Authorization: Bearer YOUR_ACCOUNT_TOKEN
Content-Type: application/json

{"action":"create","link":"https://t.me/example","ads_type":"channel","quantity_all":1000}

Типы кампаний: channel, bot, resource. Статусы: Moderation, Processing, Stopped, Finished, Rejected, Archived.

Фильтры

GET /api/filters возвращает доступные языки, страны, возрастные категории и тематики для настройки кампаний.

curl https://axionna.org/api/filters
{"status":"ok","filters":{"ads":{"countries":[],"languages":[],"ages":[],"forbidden_themes":[]},"bots":{"forbidden_themes":[]}}}

Уведомления об изменении статуса

Для подключённых рекламных источников можно указать HTTPS-адрес уведомлений:

POST https://your-domain.example/webhooks/{provider}
Content-Type: application/json

{"tg_user_id":123456789,"offer_link":"https://t.me/example","status":"unsubscribed","chat_id":-1001234567890}

Сервер должен быстро вернуть HTTP 200–299 и JSON {"ok":true}. Повторная доставка одного уведомления безопасна. Для защиты запросов используйте подпись или ключ, предоставленный источником.

Ошибки

HTTPЗначение
400Неверные параметры запроса
401Отсутствует или недействителен ключ
403Ресурс недоступен для этого аккаунта
409Конфликт состояния ресурса
422Ошибка проверки данных
500Временная ошибка сервера

Минимальный пример: Aiogram + aiohttp

Пример для Aiogram 3. Сохраняйте task_ids в своей базе данных; словарь ниже нужен только для демонстрации.

import asyncio
import aiohttp

from aiogram import Bot, Dispatcher, F, Router
from aiogram.filters import CommandStart
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message

BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
AXIONNA_KEY = "YOUR_BOT_API_KEY"
API_BASE = "https://axionna.org"

bot = Bot(BOT_TOKEN)
dp = Dispatcher()
router = Router()
pending: dict[int, list[str]] = {}


async def axionna_request(path: str, payload: dict) -> dict:
    headers = {
        "Authorization": f"Bearer {AXIONNA_KEY}",
        "Content-Type": "application/json",
    }
    timeout = aiohttp.ClientTimeout(total=15)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.post(f"{API_BASE}{path}", json=payload, headers=headers) as response:
            data = await response.json(content_type=None)
            if response.status >= 400:
                raise RuntimeError(data.get("error", "Axionna API error"))
            return data


def tasks_keyboard(sponsors: list[dict]) -> InlineKeyboardMarkup:
    rows = [
        [InlineKeyboardButton(text=item.get("button_text") or "Открыть", url=item["link"])]
        for item in sponsors
    ]
    rows.append([InlineKeyboardButton(text="Проверить", callback_data="check_tasks")])
    return InlineKeyboardMarkup(inline_keyboard=rows)


@router.message(CommandStart())
async def start(message: Message) -> None:
    user = message.from_user
    data = await axionna_request("/api/sponsors", {
        "user_id": user.id,
        "chat_id": message.chat.id,
        "username": user.username,
        "first_name": user.first_name,
        "language_code": user.language_code,
        "is_premium": user.is_premium,
        "max_sponsors": 5,
    })
    sponsors = data.get("sponsors") or []
    pending[user.id] = [item["id"] for item in sponsors if item.get("id")]
    if not pending[user.id]:
        await message.answer("Заданий сейчас нет.")
        return
    await message.answer("Выполните задания и нажмите «Проверить».", reply_markup=tasks_keyboard(sponsors))


@router.callback_query(F.data == "check_tasks")
async def check(callback: CallbackQuery) -> None:
    task_ids = pending.get(callback.from_user.id, [])
    data = await axionna_request("/api/check", {
        "user_id": callback.from_user.id,
        "task_ids": task_ids,
    })
    if data.get("all_subscribed"):
        pending.pop(callback.from_user.id, None)
        await callback.message.answer("Все задания выполнены.")
        await callback.answer()
    else:
        await callback.answer("Не все задания выполнены.", show_alert=True)


async def main() -> None:
    dp.include_router(router)
    await dp.start_polling(bot)


if __name__ == "__main__":
    asyncio.run(main())