Быстрый старт
Войдите в кабинет
Откройте веб-кабинет под тем Telegram-аккаунтом, на который оформлена сеть. В «Моих ботах» есть карточка вашей сети.
Получите ключ
В карточке сети откройте «Интеграция» и нажмите «Новый ключ». Ключ показывается один раз — сохраните его на сервере и не публикуйте. Если ключ утёк, выпустите новый там же: старый сразу перестанет работать.
Вставьте код в ботов
Возьмите готовый код ниже. Он один для всех ботов сети: имя бота подставляется само.
Вызывайте в двух местах
При /start — приветственный показ, после того как бот выдал человеку результат, — обычный. Подробно — в разделе «Когда вызывать».
Проверьте
Пройдите проверку из пяти пунктов на одном боте, затем выкатывайте на остальные.
Регистрировать ботов заранее не нужно. Бот появляется в сети в момент первого запроса с его именем и сразу получает рекламу: отдельной модерации каждого бота нет.
Запрос
POST https://hiviews.net/ с JSON-телом.
Заголовки
| Заголовок | Значение |
|---|---|
Authorization | Ключ сети как есть, без префикса Bearer |
Content-Type | application/json |
Поля тела
| Поле | Тип | Описание |
|---|---|---|
UserId | int, обязательное | ID пользователя Telegram, которому бот покажет рекламу. Только личные чаты. |
Bot | string, обязательное | Имя бота, для которого запрашивается реклама, без @ (регистр не важен). Это должен быть настоящий username бота: латиница, цифры и подчёркивание, оканчивается на bot. |
StartPlace | bool | true — приветственный показ (при /start), false — обычный показ после выдачи результата. Если поле не передать, запрос считается обычным показом. |
UserFirstName | string | Имя пользователя: подставляется в текст поста вместо $name. |
Username | string | Username пользователя без @, если есть. |
Language | string | Язык пользователя из Telegram (language_code). По нему подбираются кампании. Если не передать, мы попробуем определить язык сами (по прошлым показам этому человеку и по имени), но точнее — передавать. |
HasPhoto | boolean | Необязательно. true, если у пользователя есть аватар (getUserProfilePhotos → total_count > 0; результат стоит кешировать). Нужно для кампаний с отметкой «Verified»: их получают только люди с аватаром и обычным именем. Если поле не передавать, мы сами проверяем тех, у кого есть username, — поэтому Username передавайте всегда. Не ставьте true всем подряд: такие боты видны по переходам и лишаются оплаты показов. |
Пример
curl -X POST https://hiviews.net/api/partner/ad \
-H "Authorization: YOUR_NETWORK_KEY" \
-H "Content-Type: application/json" \
-d '{"UserId": 123456789, "UserFirstName": "Ivan", "Language": "ru", "StartPlace": true, "Bot": "my_first_bot"}'Ответ
Ответ всегда JSON. Если реклама есть — "ok": true и объект ad; если нет — "ok": false и поле reason (все значения).
{
"ok": true,
"ad": {
"text": "<a href=\"https://hiviews.net/api/go/v/…\">​</a>Ivan, …",
"parse_mode": "HTML",
"reply_markup": {"inline_keyboard": [[{"text": "Open", "url": "https://hiviews.net/api/go/…"}]]},
"photo": "https://hiviews.net/api/go/m/…",
"delete_after": 60
}
}Поле ad | Что с ним делать |
|---|---|
text | Текст поста в разметке HTML. Отправьте без изменений. Если есть медиа — это подпись к нему. |
parse_mode | Всегда HTML — передайте в метод отправки. |
reply_markup | Клавиатура с кнопками-ссылками. Передайте как есть. |
photo / video / animation | Присутствует не больше одного: ссылка на файл. Отправьте методом sendPhoto, sendVideo или sendAnimation, передав ссылку как файл. Если поля нет — sendMessage. |
delete_after | Если есть — удалите сообщение через столько секунд. Так помечается внешняя реклама, которая показывается недолго. |
Как отправить пост, чтобы показ оплатили
Мы не видим, что бот отправил пользователю, поэтому показ подтверждает сам Telegram. В начале текста каждого поста стоит невидимая ссылка: когда сообщение отправлено, серверы Telegram открывают её, и показ засчитывается.
- Отправляйте пост ровно в том виде, в каком получили. Не вырезайте начало текста, не пересобирайте разметку, не меняйте ссылки в тексте и кнопках.
- Не отключайте превью ссылок. Не передавайте
disable_web_page_previewиlink_preview_optionsс отключением. Во многих библиотеках превью выключают глобально в настройках бота — для рекламного сообщения включите. - Отправляйте сразу. Подтверждение принимается в течение 3 минут после выдачи поста. Пост, отправленный позже, не оплачивается.
- Один запрос — одно сообщение одному человеку. Не рассылайте полученный пост другим пользователям и не запрашивайте рекламу без действия пользователя.
Неподтверждённый пост не оплачивается: ни показ, ни переходы по нему. Если бот берёт посты и не отправляет больше половины из них, он перестаёт получать рекламу — ответ unconfirmed_sends.
Когда вызывать
| Момент | StartPlace | Формат |
|---|---|---|
| Человек нажал /start | true | Приветственный показ. Вызывайте до своего приветствия или сразу после него. |
| Бот выдал результат: нашёл трек, скачал файл, ответил на запрос | false | Обычный показ. Вызывайте после того, как результат уже отправлен, чтобы реклама была последним сообщением. |
- Вызывайте в обоих местах — так боты зарабатывают на обоих форматах.
- Не ставьте
StartPlace: trueвезде: приветственный показ одному человеку в одном боте выдаётся не чаще раза в сутки, лишние запросы вернутся без рекламы. - Запрос не должен задерживать бота: ставьте таймаут 5 секунд и ловите ошибки. Готовый код так и делает.
Готовый код
Код один для всех ботов сети. Имя бота в поле Bot берётся у самого бота, поэтому при запуске нового бота ничего менять не нужно.
Python, aiogram 3
# HiViews, сеть ботов: один ключ на все боты. Бот сам отправляет рекламу.
# pip install aiogram aiohttp
import asyncio, aiohttp
from aiogram import Bot
from aiogram.types import InlineKeyboardMarkup
HIVIEWS_KEY = "YOUR_NETWORK_KEY"
async def show_ad(bot: Bot, user, start: bool = False) -> None:
"""При /start вызывайте с start=True, после выдачи результата — с start=False."""
me = await bot.me() # имя бота, который сейчас отвечает пользователю
payload = {"UserId": user.id, "UserFirstName": user.first_name, "Username": user.username,
"Language": user.language_code, "StartPlace": start, "Bot": me.username}
try:
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5)) as s:
async with s.post("https://hiviews.net/api/partner/ad", json=payload,
headers={"Authorization": HIVIEWS_KEY}) as r:
ad = (await r.json()).get("ad")
if not ad:
return # сейчас рекламы для этого человека нет
kw = {"parse_mode": "HTML", "reply_markup": InlineKeyboardMarkup.model_validate(ad["reply_markup"])}
if ad.get("photo"):
msg = await bot.send_photo(user.id, ad["photo"], caption=ad["text"], **kw)
elif ad.get("video"):
msg = await bot.send_video(user.id, ad["video"], caption=ad["text"], **kw)
elif ad.get("animation"):
msg = await bot.send_animation(user.id, ad["animation"], caption=ad["text"], **kw)
else:
msg = await bot.send_message(user.id, ad["text"], **kw) # превью ссылок не отключайте
if ad.get("delete_after"): # такой пост убираем через минуту, если по нему не перешли
asyncio.get_running_loop().call_later(
ad["delete_after"], lambda: asyncio.ensure_future(_quiet_delete(bot, user.id, msg.message_id)))
except Exception:
pass # реклама никогда не должна ломать бота
async def _quiet_delete(bot: Bot, chat_id: int, message_id: int) -> None:
try:
await bot.delete_message(chat_id, message_id)
except Exception:
pass
# Пример: await show_ad(bot, message.from_user, start=True) # /start
# await show_ad(bot, message.from_user) # после выдачи результатаNode.js, Telegraf
// HiViews, сеть ботов: один ключ на все боты. Node.js 18+, Telegraf.
const HIVIEWS_KEY = process.env.HIVIEWS_KEY; // YOUR_NETWORK_KEY
async function showAd(ctx, start = false) {
// При /start вызывайте showAd(ctx, true), после выдачи результата — showAd(ctx, false).
try {
const u = ctx.from;
const res = await fetch("https://hiviews.net/api/partner/ad", {
method: "POST",
headers: { Authorization: HIVIEWS_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ UserId: u.id, UserFirstName: u.first_name, Username: u.username,
Language: u.language_code, StartPlace: start,
Bot: ctx.botInfo.username }), // имя бота, который сейчас отвечает пользователю
signal: AbortSignal.timeout(5000),
});
const { ad } = await res.json();
if (!ad) return; // сейчас рекламы для этого человека нет
const extra = { parse_mode: "HTML", reply_markup: ad.reply_markup };
let msg;
if (ad.photo) msg = await ctx.telegram.sendPhoto(u.id, ad.photo, { caption: ad.text, ...extra });
else if (ad.video) msg = await ctx.telegram.sendVideo(u.id, ad.video, { caption: ad.text, ...extra });
else if (ad.animation) msg = await ctx.telegram.sendAnimation(u.id, ad.animation, { caption: ad.text, ...extra });
else msg = await ctx.telegram.sendMessage(u.id, ad.text, extra); // превью ссылок не отключайте
if (ad.delete_after) { // такой пост убираем через минуту, если по нему не перешли
setTimeout(() => ctx.telegram.deleteMessage(u.id, msg.message_id).catch(() => {}), ad.delete_after * 1000);
}
} catch (e) { /* реклама никогда не должна ломать бота */ }
}
// Пример: bot.start(async (ctx) => { await showAd(ctx, true); /* ... */ });PHP
<?php
// HiViews, сеть ботов: один ключ на все боты.
const HIVIEWS_KEY = 'YOUR_NETWORK_KEY';
/** $user — массив from из апдейта Telegram, $botUsername — имя бота без @. При /start: $start = true, после выдачи результата: false.
* Возвращает [message_id, delete_after] — если delete_after не null, удалите сообщение через столько секунд. */
function hiviews_show_ad(string $botToken, string $botUsername, array $user, bool $start = false): ?array
{
$ch = curl_init('https://hiviews.net/api/partner/ad');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5,
CURLOPT_HTTPHEADER => ['Authorization: ' . HIVIEWS_KEY, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'UserId' => $user['id'], 'UserFirstName' => $user['first_name'] ?? '',
'Username' => $user['username'] ?? null, 'Language' => $user['language_code'] ?? null,
'StartPlace' => $start, 'Bot' => $botUsername, // имя бота, который сейчас отвечает пользователю
]),
]);
$ad = json_decode((string) curl_exec($ch), true)['ad'] ?? null;
curl_close($ch);
if (!$ad) {
return null; // сейчас рекламы для этого человека нет
}
$params = ['chat_id' => $user['id'], 'parse_mode' => 'HTML', 'reply_markup' => json_encode($ad['reply_markup'])];
if (!empty($ad['photo'])) {
$method = 'sendPhoto'; $params += ['photo' => $ad['photo'], 'caption' => $ad['text']];
} elseif (!empty($ad['video'])) {
$method = 'sendVideo'; $params += ['video' => $ad['video'], 'caption' => $ad['text']];
} elseif (!empty($ad['animation'])) {
$method = 'sendAnimation'; $params += ['animation' => $ad['animation'], 'caption' => $ad['text']];
} else {
$method = 'sendMessage'; $params += ['text' => $ad['text']]; // превью ссылок не отключайте
}
$ch = curl_init('https://api.telegram.org/bot' . $botToken . '/' . $method);
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10,
CURLOPT_POSTFIELDS => $params]);
$sent = json_decode((string) curl_exec($ch), true);
curl_close($ch);
return [$sent['result']['message_id'] ?? null, $ad['delete_after'] ?? null];
}
// Пример: hiviews_show_ad($botToken, 'my_first_bot', $update['message']['from'], true); // /startЕсли рекламы нет: значения reason
При "ok": false ничего отправлять не нужно — бот просто продолжает работу. Поле reason помогает понять причину.
| HTTP | reason | Что означает и что делать |
|---|---|---|
| 200 | no_ads | Сейчас нет подходящей рекламы для этого человека. Обычная ситуация. |
| 200 | cap_viewer_window, cap_hello_window, cap_daily_cap, cap_external | Этот человек недавно уже видел рекламу. Лимиты защищают пользователей: не больше одного объявления в час и шести в сутки по всей сети, приветственное — раз в сутки в одном боте. |
| 200 | placement_off | Этот формат показа выключен в настройках сети в кабинете. |
| 200 | parallel | Для этого человека одновременно пришёл другой запрос. Ничего делать не нужно. |
| 200 | rate_limited | Слишком много запросов в минуту (см. лимиты). Запросы сверх лимита просто остаются без рекламы. |
| 200 | unconfirmed_sends | Больше половины последних постов этого бота Telegram не подтвердил. Проверьте, что пост отправляется без изменений и с превью ссылок. Выдача возобновится сама, когда доля подтверждений восстановится. |
| 400 | bad_request | Тело не JSON, нет UserId или он не положительное число. |
| 400 | bad_key | Нет заголовка Authorization или ключ неверный. |
| 400 | bad_bot | Поле Bot не передано или не похоже на имя бота. |
| 400 | bot_taken | Бот с таким именем уже подключён к HiViews отдельно (с токеном или без). Чтобы он работал через сеть, удалите его отдельное подключение в кабинете. |
| 400 | too_many_bots | В сети больше 50 000 ботов — напишите в поддержку. |
| 403 | bot_paused | Сеть поставлена на паузу в кабинете. |
| 403 | bot_moderation, bot_banned | Сеть на проверке или заблокирована — напишите в поддержку. |
За что и как платим
- За показы. Оплачивается каждый показ платной кампании, отправку которого подтвердил Telegram, — и приветственный, и обычный. Ставка за показ без токена ниже, чем у ботов, подключённых с токеном.
- За переходы. По кампаниям с оплатой за клик — $0.04 за переход. Оплачивается первый переход по показу, не чаще одного с одного адреса в час.
- Внешняя реклама. Показывается, когда своих подходящих кампаний нет, чтобы бот не простаивал. Оплата только за переходы, цена зависит от страны и аудитории, доход начисляется на следующий день.
- Вывод. Доход всех ботов сети идёт на один баланс. Он становится доступен к выводу через 7 дней (проверка на накрутку), вывод от $50 в USDT (TRC20), комиссия за вывод — $3. Подробнее — в гайде по финансам.
Статистика в карточке сети показывает показы, переходы и доход по всем ботам вместе.
Контроль качества
Все ссылки в рекламе идут через наше отслеживание, и мы знаем, как часто по тем же кампаниям переходят в ботах, где доставку отправляем сами. Поэтому для каждого бота и для сети целиком известно, сколько переходов должно быть на такое число показов.
- Если показов много, а переходов почти нет или их неправдоподобно много, оплата за показы отключается автоматически — у этого бота или у всей сети, если расхождение по сети в целом. Остаётся оплата за переходы.
- Переходы считаются по источнику: много ссылок, открытых с одного адреса, — это один переход.
- Доход за накрученные показы возвращается рекламодателям. Не запрашивайте рекламу на выдуманные
UserIdи не отправляйте посты в служебные чаты.
Лимиты
| Что | Значение |
|---|---|
| Запросов в минуту на одного бота | 1 200 |
| Запросов в минуту на всю сеть | 120 000 |
| Ботов в сети | до 50 000 |
| Время на отправку поста после получения | 3 минуты |
| Рекомендуемый таймаут запроса | 5 секунд |
Нужно больше — напишите в поддержку, лимиты поднимаются.
Проверка интеграции
Запрос проходит
Отправьте пример запроса со своим ключом и именем одного из ботов. Ответ
"ok": trueс объектомadили"ok": falseсno_ads— оба означают, что ключ и имя бота приняты.Пост приходит целиком
Нажмите /start в боте со своего аккаунта. Реклама должна прийти с кнопкой, а если в посте есть картинка или видео — с ними.
Кнопка ведёт через hiviews.net
Ссылка кнопки начинается с
https://hiviews.net/api/go/. Если она другая — код меняет ссылки, переходы не будут засчитаны.Показ появился в статистике
Через минуту откройте карточку сети в кабинете: показ должен быть в статистике. Если его нет — пост изменён или отключено превью ссылок.
Обычный показ идёт после результата
Сделайте в боте запрос и убедитесь, что реклама приходит после результата, а не перед ним.
Настройки сети
Настройки задаются один раз в карточке сети в кабинете и действуют для всех её ботов.
- Форматы: можно выключить приветственный или обычный показ.
- Категории рекламы: можно отказаться от любых — ставок, VPN, знакомств и других.
- Внешняя реклама и реклама с оплатой за переходы: включаются и выключаются отдельно.
- Пауза: останавливает рекламу во всех ботах сети сразу.
- Тематики сети задаёт поддержка при создании сети; чтобы изменить их, напишите в поддержку.
Частые вопросы
Нужно ли передавать токены ботов?
Нет. Боты отправляют рекламу сами, своим токеном, который остаётся у вас. Нам нужен только ключ сети в заголовке запроса.
Как добавить нового бота в сеть?
Никак отдельно: начните отправлять запросы с его именем в поле Bot. Бот регистрируется при первом запросе и сразу получает рекламу.
Можно ли использовать ключ сети для бота, который уже подключён отдельно?
Нет, запрос вернёт bot_taken. Удалите отдельное подключение бота в кабинете — после этого он заработает через сеть. Учтите, что у бота, подключённого с токеном, ставка за показ выше.
Почему показы есть, а оплаты за них нет?
Оплачиваются показы, которые подтвердил Telegram. Проверьте, что пост отправляется без изменений, с превью ссылок и в течение 3 минут после получения.
Что будет, если один бот сети нарушит правила?
Оплата за показы отключится у этого бота, остальные продолжат работать. Если расхождение между показами и переходами заметно по сети в целом, оплата за показы отключается у всей сети.
Нужен ключ сети или остались вопросы? Сеть оформляется по запросу: напишите в поддержку, сколько у вас ботов и какой они тематики.