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

API для ботов

Показывайте задания рекламодателей своим пользователям и ставьте обязательную подписку — 60% цены каждого выполнения ваши. Проверку выполнения в Telegram биржа делает сама: вам — два запроса.

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

  1. Войдите в кабинет через Telegram → «Боты и API» → «Подключить бота». Сохраните ключ — он показывается один раз.
  2. Все запросы — на https://lifeseo.ru/api/v1/… с заголовком Authorization: Bearer lseo_…, тело — JSON.
  3. Покажите человеку задания (POST /tasks); когда он нажмёт «Проверить» — вызовите POST /tasks/check.
  4. Засчитанное выполнение — в холде 72 часа, потом деньги переходят на счёт к выводу. События приходят вебхуком.

Основное

POST /tasks — задания для человека

Поля запроса: user_id — обязательно, limit — сколько заданий вернуть (1–20, по умолчанию 5). Дорогие задания — первыми.

Запрос
POST https://lifeseo.ru/api/v1/tasks
Authorization: Bearer lseo_…
Content-Type: application/json

{"user_id": 123456789, "limit": 5}
Ответ
{
  "ok": true,
  "tasks": [
    {
      "task_id": "6718a2c4e1f0a93b2c5d7e10",
      "type": "channel",
      "title": "Подпишитесь на канал о крипте",
      "description": "Новости и разборы каждый день",
      "link": "https://t.me/example_channel",
      "reward": 30,
      "check": "auto"
    },
    {
      "task_id": "6718a2c4e1f0a93b2c5d7e11",
      "type": "link",
      "title": "Откройте сайт партнёра",
      "description": "",
      "link": "https://lifeseo.ru/go/6718a2c4…",
      "reward": 12,
      "check": "auto"
    }
  ]
}
ПолеЧто это
task_idId задания — для /tasks/check
typechannel — подписка на канал, group — вступление в группу, bot — запуск бота, link — переход по ссылке, report — задание с отчётом
title, descriptionТекст для человека (без разметки и угловых скобок)
linkКуда вести человека. Для link — ссылка на бота биржи: он выдаст человеку личную ссылку перехода — так переход засчитывается только тому, кто реально перешёл
rewardВаша доля за выполнение, копейки
checkauto — проверяем сами по /tasks/check; report — нужен отчёт со скриншотом (ниже)
instructions, criteriaТолько у report: что сделать и что должно быть на скриншоте

Каналы, где человек уже был до показа задания, и боты, которые он уже запускал, не возвращаются: за старых подписчиков рекламодатель не платит.

POST /tasks/check — проверить выполнение

Запрос
POST https://lifeseo.ru/api/v1/tasks/check

{"user_id": 123456789, "task_id": "6718a2c4e1f0a93b2c5d7e10"}
Ответы
{ "ok": true, "status": "completed", "reward": 30, "hold_until": "2026-10-24T12:00:00.000Z" }
{ "ok": true, "status": "incomplete" }
{ "ok": true, "status": "unavailable" }
statusЧто делать
completedЗасчитано. reward — ваша доля, hold_until — когда она станет доступна к выводу. Повторный запрос снова вернёт completed
incompleteЕщё не выполнено: не подписался, не запустил бота, не перешёл по ссылке. Для ссылки переход засчитывается через 5 секунд после открытия личной ссылки из бота биржи
unavailableЗадание закончилось, остановлено или выполнено через другой бот — уберите его из списка
waitingТолько у report: отчёт на проверке. Для отказа приходят reason и attempts_left

Задания с отчётом

Задание вне Telegram (отзыв, регистрация, действие на сайте): человек делает его и присылает скриншот и текст — вы передаёте их нам. Отчёт проверяет ИИ по критериям рекламодателя. Если ИИ не уверен — решает рекламодатель (72 часа, потом отчёт засчитывается); обжалованный отказ ИИ решает рекламодатель или админ, без автоприёма. Итог — вебхуком report.reviewed и через /tasks/check.

Отчёт
POST https://lifeseo.ru/api/v1/tasks/report

{
  "user_id": 123456789,
  "task_id": "6718a2c4e1f0a93b2c5d7e30",
  "text": "Оставил отзыв, ник Иван П.",
  "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg…"
}

{ "ok": true, "status": "review", "report_id": "6718c0aa…", "attempts_left": 2 }

POST /op/check — обязательная подписка

Вызывайте перед тем, как пустить человека дальше. passed: false — покажите каналы кнопками и кнопку «Я подписался», которая снова вызывает /op/check. Каждая подписка — оплаченное выполнение. После прохождения человек час не видит новых каналов, а запрос отвечает сразу — его можно звать хоть на каждое сообщение.

Запрос
POST https://lifeseo.ru/api/v1/op/check

{"user_id": 123456789}
Ответ
{
  "ok": true,
  "passed": false,
  "channels": [
    {
      "task_id": "6718a2c4e1f0a93b2c5d7e20",
      "title": "Подпишитесь, чтобы продолжить",
      "channel": "Крипто-новости",
      "link": "https://t.me/example_news",
      "reward": 24
    }
  ]
}

Если Telegram не ответил, канал в этот раз не показывается: ОП никогда не запирает человека в вашем боте из-за сбоя.

GET /me и GET /stats

GET /api/v1/me
{
  "ok": true,
  "bot": { "id": "6718…", "title": "Мой бот", "username": "my_bot" },
  "share_percent": 60,
  "hold_hours": 72,
  "balances": { "hold": 1800, "earn": 12400 }
}
GET /api/v1/stats
GET https://lifeseo.ru/api/v1/stats?days=7

{
  "ok": true,
  "days": [
    { "date": "2026-10-21", "completed": 140, "confirmed": 0, "penalized": 3, "earned": 4110 }
  ]
}

Вебхуки

Адрес задаётся в кабинете (только https). Ответьте 2xx за 10 секунд — иначе повторим через 1 мин, 5 мин, 30 мин, 2 ч, 6 ч и 24 ч. Один и тот же id может прийти дважды — обрабатывайте идемпотентно.

Вебхук
POST https://ваш-адрес/lifeseo-hook
X-LifeSEO-Event: task.completed
X-LifeSEO-Delivery: 6718b0d2e1f0a93b2c5d7f01
X-LifeSEO-Signature: sha256=5f1c…

{
  "event": "task.completed",
  "id": "6718b0d2e1f0a93b2c5d7f01",
  "created_at": "2026-10-21T12:00:00.000Z",
  "data": {
    "user_id": 123456789,
    "task_id": "6718a2c4e1f0a93b2c5d7e10",
    "source": "task",
    "reward": 30,
    "hold_until": "2026-10-24T12:00:00.000Z"
  }
}
СобытиеКогда
task.completedВыполнение засчитано (через /tasks/check или ОП); деньги — в холде
task.confirmedХолд прошёл — доля перешла на счёт к выводу
task.penaltyЧеловек отписался в холде — доля списана; можно забрать награду у пользователя
report.reviewedОтчёт проверен: verdict — approved (с reward) или rejected (с reason)

Подпись — X-LifeSEO-Signature: sha256=<hex>, HMAC-SHA256 тела запроса как оно пришло; ключ — «секрет подписи» бота из кабинета.

Node.js
const crypto = require('node:crypto');

// raw — тело запроса как пришло (Buffer), до JSON.parse
function verifyLifeseo(raw, signatureHeader, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(raw).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(String(signatureHeader || ''));
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Python
import hashlib, hmac

def verify_lifeseo(raw: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")
PHP
<?php
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_LIFESEO_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
}
$event = json_decode($raw, true);

Холд и штрафы

Бот биржи — админ каналов рекламодателей, поэтому подписку видно сразу. Выход из канала в течение 72 часов отменяет выполнение: ваша доля списывается из холда, рекламодателю возвращаются деньги, вам приходит task.penalty. Ещё мы перепроверяем подписку через сутки и в конце холда. Если рекламодатель убрал бота биржи из админов, перепроверить нельзя — такие выполнения засчитываются без штрафа.

Примеры кода

Node.js — telegraf
// npm i telegraf
const { Telegraf, Markup } = require('telegraf');

const bot = new Telegraf(process.env.BOT_TOKEN);
const KEY = process.env.LIFESEO_KEY; // ключ из кабинета LifeSEO

async function lifeseo(path, body) {
  const res = await fetch(`https://lifeseo.ru/api/v1${path}`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  return res.json();
}

bot.command('tasks', async (ctx) => {
  const { tasks = [] } = await lifeseo('/tasks', { user_id: ctx.from.id, limit: 5 });
  if (!tasks.length) return ctx.reply('Заданий пока нет — загляните позже.');
  for (const t of tasks) {
    await ctx.reply(`${t.title}\nНаграда: ${(t.reward / 100).toFixed(2)} ₽`, Markup.inlineKeyboard([
      [Markup.button.url('Выполнить', t.link)],
      [Markup.button.callback('Проверить', `check:${t.task_id}`)],
    ]));
  }
});

bot.action(/^check:(\w{24})$/, async (ctx) => {
  const r = await lifeseo('/tasks/check', { user_id: ctx.from.id, task_id: ctx.match[1] });
  if (r.status === 'completed') return ctx.answerCbQuery('Засчитано!', { show_alert: true });
  if (r.status === 'incomplete') return ctx.answerCbQuery('Ещё не выполнено', { show_alert: true });
  return ctx.answerCbQuery('Задание уже недоступно', { show_alert: true });
});

// Обязательная подписка перед любым действием
bot.use(async (ctx, next) => {
  if (!ctx.from || ctx.callbackQuery?.data === 'op') return next();
  const op = await lifeseo('/op/check', { user_id: ctx.from.id });
  if (!op.ok || op.passed) return next();
  const rows = op.channels.map((c) => [Markup.button.url(c.channel || c.title, c.link)]);
  rows.push([Markup.button.callback('Я подписался', 'op')]);
  return ctx.reply('Чтобы продолжить, подпишитесь:', Markup.inlineKeyboard(rows));
});
bot.action('op', async (ctx) => {
  const op = await lifeseo('/op/check', { user_id: ctx.from.id });
  await ctx.answerCbQuery(op.passed ? 'Готово, спасибо!' : 'Подписка ещё не найдена', { show_alert: !op.passed });
});

bot.launch();
Python — aiogram 3
# pip install aiogram aiohttp
import os, aiohttp
from aiogram import Bot, Dispatcher, F
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton

KEY = os.environ["LIFESEO_KEY"]
bot = Bot(os.environ["BOT_TOKEN"])
dp = Dispatcher()

async def lifeseo(path: str, body: dict) -> dict:
    async with aiohttp.ClientSession() as s:
        async with s.post(f"https://lifeseo.ru/api/v1{path}", json=body,
                          headers={"Authorization": f"Bearer {KEY}"}) as r:
            return await r.json()

@dp.message(Command("tasks"))
async def tasks(m: Message):
    data = await lifeseo("/tasks", {"user_id": m.from_user.id, "limit": 5})
    for t in data.get("tasks", []):
        kb = InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="Выполнить", url=t["link"])],
            [InlineKeyboardButton(text="Проверить", callback_data=f"check:{t['task_id']}")],
        ])
        await m.answer(f"{t['title']}\nНаграда: {t['reward'] / 100:.2f} ₽", reply_markup=kb)

@dp.callback_query(F.data.startswith("check:"))
async def check(c: CallbackQuery):
    r = await lifeseo("/tasks/check", {"user_id": c.from_user.id, "task_id": c.data.split(":", 1)[1]})
    text = {"completed": "Засчитано!", "incomplete": "Ещё не выполнено"}.get(r.get("status"), "Задание недоступно")
    await c.answer(text, show_alert=True)

dp.run_polling(bot)
PHP — curl
<?php
function lifeseo(string $path, array $body): array {
    $ch = curl_init('https://lifeseo.ru/api/v1' . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('LIFESEO_KEY'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode($body),
    ]);
    $result = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $result ?: ['ok' => false];
}

$tasks = lifeseo('/tasks', ['user_id' => $userId, 'limit' => 5]);
$check = lifeseo('/tasks/check', ['user_id' => $userId, 'task_id' => $taskId]);

Ошибки

HTTPerrorЧто значит
400bad_input, bad_jsonНеверные поля — текст в message
401unauthorizedНет ключа, ключ перевыпущен или бот заблокирован
404, 405not_found, methodНет такого метода или не тот HTTP-метод
409unavailable, already_open, no_attempts, bad_stateОтчёт сейчас не принять: задание недоступно, предыдущий на проверке, попытки кончились, обжаловать нельзя
413too_largeТело больше 16 КБ (у отчёта — 6 МБ)
429rate_limitedСлишком часто — подождите Retry-After секунд
500, 503internal, telegram_unavailableСбой у нас или в Telegram — повторите позже