На этой странице
- Обзор
- Начало работы
- Автоматизация агентом
- Аутентификация
- Токены и цены
- API SMM-панели
- services
- add
- status
- balance
- cancel
- API платформы
- Каталог
- Аккаунт
- Двухфакторная защита и вход
- Настройки и оповещения
- Кампании
- Создание заказа
- Изменение заказа
- Логи и аналитика
- Профили голосов и прокси
- Токены Discord
- Счета и платежи
- Сохранённая корзина
- Внутренние эндпоинты
- Формат ответов
- Объект сайта
- Объект кампании
- Состояние кампании
- Прогресс и возвраты
- Пример от начала до конца
- Ошибки
- Ограничения частоты
- Ограничения и примечания
Обзор
Toplistbot предоставляет два HTTP API. Оба работают с JSON поверх HTTPS, оба тратят один и тот же баланс токенов, и любого из них достаточно, чтобы вести кампании, ни разу не открыв панель.
API SMM-панели
Один эндпоинт, совместимый с Perfect Panel. Если ваша панель уже говорит на стандартном протоколе SMM, направьте её сюда — код менять не нужно.
API платформы
REST API, на котором работает панель: каталог, создание и управление кампаниями, логи доставки по каждому голосу, профили, прокси и счета.
Базовый URL
https://backend.toplistbot.com/api
https://backend.toplistbot.comСправочник ниже написан для этих двух хостов. От выбора хоста зависит способ аутентификации — см. раздел «Аутентификация».
Начало работы
От нового аккаунта до работающей кампании за пять шагов. Всё ниже использует эндпоинт SMM — самый быстрый путь; API платформы работает так же, как только вы получите JWT.
Создайте аккаунт
Зарегистрируйтесь и подтвердите почту. Подтверждение начисляет 100 бесплатных токенов — этого хватит на настоящую кампанию, прежде чем вы что-то потратите.
Скопируйте ключ API
Откройте личный кабинет и создайте ключ API. Относитесь к нему как к паролю — он тратит ваш баланс токенов. Ключ можно перевыпустить в любой момент, старый сразу перестаёт работать.
Найдите нужный сервис
Получите список всех сайтов, на которых можно оформить заказ. У каждой записи есть числовой id сервиса и тариф в токенах за 1 000 действий. Запишите id сайта, на котором хотите продвигаться.
cURLcurl -X POST https://backend.toplistbot.com/api/v2 -d "key=YOUR_API_KEY" -d "action=services"Оформите первый заказ
Отправьте id сервиса, URL, на котором будет работать кампания, и количество действий. Стоимость списывается сразу, а в ответе приходит id заказа.
cURLcurl -X POST https://backend.toplistbot.com/api/v2 \ -d "key=YOUR_API_KEY" \ -d "action=add" \ -d "service=9" \ -d "link=https://arena-top100.com/index.php?a=in&u=yourserver" \ -d "quantity=1000"Отслеживайте выполнение
Запрашивайте статус по id заказа, чтобы видеть, сколько уже выполнено. Когда схема вас устроит, встройте те же вызовы в свою панель или скрипты.
cURLcurl -X POST https://backend.toplistbot.com/api/v2 -d "key=YOUR_API_KEY" -d "action=status" -d "orders=184223"
Подключение Perfect Panel
Если вы используете Perfect Panel или совместимое ПО для SMM-панелей, писать код не нужно — добавьте Toplistbot как провайдера с этими настройками и импортируйте список сервисов.
- URL API
- https://backend.toplistbot.com/api/v2
- Ключ API
- YOUR_API_KEY
- HTTP-метод
- POST
Начните с небольшого объёма на одном сайте, чтобы убедиться, что формат ссылки принимается, и только потом масштабируйтесь. Неверная ссылка тоже расходует токены.
Автоматизация с ИИ-агентом
У этой страницы есть текстовый двойник, написанный для машин. Дайте агенту эту ссылку и свой API-ключ — у него будет всё нужное: полный список эндпоинтов, форматы запросов и ответов, арифметика цен, коды ошибок и готовые примеры.
Машиночитаемый справочник
Один документ, без аутентификации и без JavaScript. Скачайте его, вставьте в промпт или передайте ссылку инструменту, который умеет ходить в интернет.
https://toplistbot.com/llms.txtСтартовый промпт
Вставьте это в Claude или любого агента, умеющего делать HTTP-запросы. Держите ключ в переменной окружения, а не в самом сообщении.
Read https://toplistbot.com/llms.txt — it is the complete Toplistbot API reference.
My API key is in the TOPLISTBOT_KEY environment variable. Using the API-key
surface (paths without the /api prefix):
1. list the sites in the catalog that cost under 20 tokens per 1,000 votes
2. tell me my token balance
3. propose a campaign for <my vote URL> that fits a budget of <N> tokens
Do not place the order until I confirm the cost.API-ключ — правильный вид доступа для агента: он не истекает, на него не влияет двухфакторная защита, а его ротация из панели мгновенно отзывает доступ, если это понадобится.
Аутентификация
Есть два вида доступа, и какой нужен — зависит от пути, а не от эндпоинта. Почти каждый эндпоинт смонтирован дважды.
Префикс /api определяет вид доступа
За обоими путями стоит один и тот же обработчик. Уберите префикс /api — и API платформы примет долгоживущий API-ключ; оставьте его — и эндпоинт ждёт JWT, полученный при входе.
| Путь | Доступ | Для чего |
|---|---|---|
| /api/orders/getAll | JWT | Всё, где входит живой человек |
| /orders/getAll | API-ключ | Скрипты, планировщики, агенты |
Для автоматизации лучше пути без префикса. Нет входа, нет истечения, нет сессии, которую надо поддерживать: один ключ делает всё, и двухфакторная защита никогда не мешает.
API-ключ
Передавайте ключ полем `key` в любом запросе: параметром строки запроса, полем формы, полем JSON или заголовком `Authorization: Bearer`. Создавайте и меняйте его в панели. GET на /api/v2 возвращает статус ok — дешёвый способ проверить, что ключ жив.
# any of these three carry the key
curl "https://backend.toplistbot.com/orders/getAll?key=YOUR_API_KEY"
curl -X POST https://backend.toplistbot.com/orders/pause -d "key=YOUR_API_KEY" -d "id=184223"
curl https://backend.toplistbot.com/orders/getAll -H "Authorization: Bearer YOUR_API_KEY"curl https://backend.toplistbot.com/api/v2?key=YOUR_API_KEYJWT
Войдите, чтобы получить токен, и передавайте его как bearer-токен на маршрутах /api. Токены истекают, поэтому вызывайте /auth/refresh заранее. Если на аккаунте включена двухфакторная защита, при входе нужен ещё и `two_factor_code`.
curl -X POST https://backend.toplistbot.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"..."}'{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"expires_in": 3600,
"user": { "id": 4211, "email": "[email protected]", "tokens": 528.41, "...": "..." }
}curl https://backend.toplistbot.com/api/orders/getAll \
-H "Authorization: Bearer YOUR_JWT"Вызовы из браузера
Все маршруты отвечают с открытым Access-Control-Allow-Origin, поэтому страница, расширение браузера или работающий в браузере агент могут обращаться к API напрямую — собственный прокси не нужен. Предупреждение выше остаётся в силе: ключ, отданный браузеру, — это опубликованный ключ, так что это для ваших собственных инструментов, а не для публичной страницы.
// Works from a page, an extension, or a browser-based agent.
const sites = await fetch(
'https://backend.toplistbot.com/orders/getAllWebsites'
).then(r => r.json())Ваш API-ключ тратит настоящий баланс токенов. Держите его на сервере: любой ключ, попавший в браузер или в репозиторий, считайте скомпрометированным и меняйте в панели.
Токены и цены
Кампании оплачиваются токенами, купленными заранее. У каждого сайта есть тариф — сколько токенов стоит 1 000 действий кампании на нём — он возвращается в поле `rate` действия services.
cost_in_tokens = (rate * quantity) / 1000Сайт с тарифом 13 стоит 13 токенов за 1 000 действий, значит заказ на 500 обойдётся в 6,5 токена. Стоимость списывается при принятии заказа, а отмена возвращает неизрасходованный остаток.
Ответы balance и status указывают валюту USD ради совместимости с Perfect Panel, но значение — это баланс токенов, а не доллары. Считайте это число токенами.
API SMM-панели
Всё выполняет один эндпоинт. Передавайте поле `action` в каждом POST-запросе, чтобы выбрать операцию; каждый запрос также содержит ваш `key`.
https://backend.toplistbot.com/api/v2| Действие | Параметры |
|---|---|
services | — |
add | service, link, quantity, interval? |
status | orders |
balance | — |
cancel | orders |
`refill` и `refill_status` принимаются ради совместимости и обе отвечают «не реализовано». Здесь ничего нельзя дозаправить — оформите новый заказ.
action=services
Возвращает все сайты, на которых можно оформить заказ, с текущим тарифом и ограничениями. Используйте id `service` в вызовах add.
curl -X POST https://backend.toplistbot.com/api/v2 \
-d "key=YOUR_API_KEY" \
-d "action=services"[
{
"service": 9,
"name": "arena-top100.com 1000 upvotes",
"type": "Default",
"category": "Votes",
"rate": 15,
"min": 1,
"max": 50000,
"refill": false,
"cancel": true
}
]`rate` указан в токенах за 1 000 действий. Для всех сервисов `min` равен 1, `max` — 50000.
action=add
Создаёт кампанию и сразу списывает её стоимость с баланса.
| Параметр | Тип | Описание |
|---|---|---|
keyобязательный | string | Ваш ключ API. |
actionобязательный | string | Должно быть `add`. |
serviceобязательный | integer | Id сервиса из действия services. |
linkобязательный | url | URL, на котором работает кампания. Должен быть корректным URL. |
quantityобязательный | integer | Количество действий, от 1 до 50000. |
interval | integer | Действий в час. По умолчанию 15, максимум 4000, и не может превышать собственный лимит сайта. |
curl -X POST https://backend.toplistbot.com/api/v2 \
-d "key=YOUR_API_KEY" \
-d "action=add" \
-d "service=9" \
-d "link=https://arena-top100.com/index.php?a=in&u=yourserver" \
-d "quantity=1000" \
-d "interval=60"{
"order_id": 184223
}action=status
Возвращает прогресс по одному или нескольким заказам. Передайте один id, чтобы получить простой объект, или список через запятую.
curl -X POST https://backend.toplistbot.com/api/v2 \
-d "key=YOUR_API_KEY" \
-d "action=status" \
-d "orders=184223"{
"charge": 13.5,
"start_count": 0,
"status": "Completed",
"remains": 1000,
"currency": "USD"
}При нескольких id ответ индексируется по id заказа, а неизвестные или чужие заказы возвращают запись об ошибке, не обрушивая весь запрос.
{
"184223": { "charge": 13.5, "start_count": 0, "status": "Completed", "remains": 1000, "currency": "USD" },
"184224": { "error": "Incorrect order ID" }
}Читайте `remains`, а не `status`
`status` всегда равен строке "Completed". Поле существует потому, что его требует любой клиент Perfect Panel, а панели считают любое другое значение поводом для дозаправки, которой эта платформа не предлагает. Прогресс — в числах: `remains` — это принятые голоса, которые ещё предстоит доставить, поэтому `remains == 0` означает, что заказ выполнен. `start_count` — сколько доставлено, `charge` — сколько это стоило. Оба считаются с учётом процента принятия сайта, то есть считают купленные голоса, а не сырые попытки.
`status` и `cancel` принимают не более 100 идентификаторов заказов за вызов. Группируйте вместо перебора: один вызов со 100 идентификаторами намного дешевле для обеих сторон, чем 100 вызовов.
action=balance
Возвращает остаток вашего баланса токенов.
curl -X POST https://backend.toplistbot.com/api/v2 \
-d "key=YOUR_API_KEY" \
-d "action=balance"{
"balance": 528.41,
"currency": "USD"
}action=cancel
Останавливает заказ и возвращает неизрасходованный остаток на баланс. Завершённые заказы отменить нельзя.
curl -X POST https://backend.toplistbot.com/api/v2 \
-d "key=YOUR_API_KEY" \
-d "action=cancel" \
-d "orders=184223,184224"[
{ "order": "184223", "cancel": 1, "refund": 4.5 },
{ "order": "184224", "cancel": { "error": "Incorrect order ID" } }
]API платформы
Тот же REST API, который использует панель. Пути ниже написаны в форме с API-ключом, без префикса /api. Добавьте /api и замените ключ на JWT, чтобы использовать сессионную форму; эндпоинты, помеченные JWT, существуют только под /api.
Каталог и поиск
Открытый доступ, ключ не нужен. Начинать стоит с getAllWebsites: он отдаёт идентификатор, цену, часовой потолок и процент принятия — всё, что нужно, чтобы посчитать стоимость и задать параметры заказа.
- GET
/orders/getAllWebsitesОткрытыйПолный каталог: каждый сайт с тарифами, лимитами и метаданными - GET
/orders/getAllBasicWebsitesDetailsОткрытый20 случайных названий сайтов — для виджетов и автодополнения - POST
/orders/getWebsiteDetailsByNameОткрытыйОдин сайт по точному названию - POST
/products/getSuggestionsОткрытыйСайты, связанные с набором идентификаторов - GET
/products/demand?days=30ОткрытыйСколько заказов было на каждый сайт в последнее время - GET
/products/tokensОткрытыйПакеты токенов, доступные к покупке - POST
/products/suggestAPI-ключПопросить добавить новый сайт - GET
/api/news/timelineОткрытыйИстория изменений продукта
curl "https://backend.toplistbot.com/orders/getAllWebsites"Просите меньше
Полный каталог занимает около 665 КБ на 396 сайтов, и половину этого веса дают два поля, с которыми вы никогда не оформите заказ: JSON-блок популярности и маркетинговое описание. Оставьте только поля, которыми заказываете, отбросьте неактивные сайты — и останется около 40 КБ.
# The whole catalog is ~665 KB across 396 sites.
# Projected to what you actually order with: ~40 KB.
curl -s "https://backend.toplistbot.com/orders/getAllWebsites" \
| jq '[.[]
| select(.active == 1)
| {id, name, price_per_1000, max_per_hour, accept_rate, subscribeable}]'Для ИИ-агента это разница между примерно 170 000 токенов и 10 000 — между тем, чтобы первый вызов сработал, и тем, чтобы он исчерпал окно контекста. Отфильтруйте до разбора.
Аккаунт и сессии
Регистрация требует браузера: её защищает проверка Cloudflare. Зарегистрируйтесь один раз на app.toplistbot.com, а всё дальнейшее автоматизируйте.
- POST
/api/auth/registerОткрытыйСоздать аккаунт — только из браузера, защищено капчей - POST
/api/auth/loginОткрытыйОбменять учётные данные на JWT - POST
/api/auth/refreshJWTВыдать новый JWT взамен истекающего - POST
/api/auth/logoutJWTАннулировать текущий JWT - GET
/api/auth/user-profileJWTТекущий аккаунт с балансом и API-ключом - GET
/api/userJWTТот же объект пользователя по более короткому пути - GET
/api/api_tokenAPI-ключОпределить владельца API-ключа — так проверяют ключ - POST
/api/auth/reset-api-keyJWTСменить API-ключ; старый умирает сразу - POST
/api/auth/fingerprintJWTЗаписать отпечаток браузера в аккаунт - POST
/api/auth/ipJWTЗаписать текущий IP аккаунта - POST
/api/auth/forgot-passwordОткрытыйОтправить ссылку на сброс пароля, действует 60 минут - POST
/api/auth/reset-passwordОткрытыйЗадать новый пароль по присланному токену
Двухфакторная защита и вход
Двухфакторная защита прикрывает вход по паролю. На API-ключи она не распространяется — поэтому для работы без присмотра ключ подходит лучше.
- POST
/api/2fa/enableJWTНачать привязку: вернёт секрет, ссылку на QR и коды восстановления - POST
/api/2fa/verifyJWTПодтвердить шестизначный код и включить двухфакторную защиту - POST
/api/2fa/disableJWTВыключить двухфакторную защиту - POST
/api/account/verification/requestJWTОтправить письмо с подтверждением на адрес аккаунта - GET
/api/account/verification/confirm?token=ОткрытыйПоказать страницу подтверждения — ничего не записывает - POST
/api/account/verification/confirmОткрытыйЗавершить подтверждение - GET
/api/auth/googleОткрытыйНачать вход через Google - GET
/api/auth/google/callbackОткрытыйВозврат после входа через Google - GET
/api/auth/discordОткрытыйНачать вход через Discord - GET
/api/auth/discord/callbackОткрытыйВозврат после входа через Discord
Настройки и оповещения
Переключатели писем и уведомлений, а также лента оповещений аккаунта.
- GET
/api/user/email-preferencesJWTСостояние подписки на маркетинговые письма - POST
/api/user/email-preferencesJWTИзменить его - GET
/api/user/notification-preferencesJWTНастройка всплывающих уведомлений о голосах - POST
/api/user/notification-preferencesJWTИзменить её: нужен настоящий булев тип JSON - GET
/api/user/alerts?limit=20JWTОповещения аккаунта, свежие первыми, с постраничностью по ?before - POST
/api/user/alerts/readJWTПометить оповещение прочитанным - POST
/api/user/alerts/dismissJWTСкрыть оповещение - GET
/api/email/unsubscribe?token=ОткрытыйОтписка в один клик по присланному токену
Кампании
Создавайте кампании, управляйте ими на ходу и завершайте их. Это ядро API платформы.
- GET
/orders/getAllAPI-ключВаши кампании, свежие первыми, вместе с их сайтами - GET
/orders/get/{id}API-ключОдна кампания - POST
/orders/checkoutAPI-ключСоздать кампании и списать с баланса - POST
/orders/updateAPI-ключИзменить кампанию - POST
/orders/pauseAPI-ключПриостановить активную кампанию - POST
/orders/unpauseAPI-ключВозобновить приостановленную кампанию - POST
/orders/archiveAPI-ключАрхивировать кампанию - POST
/orders/unarchiveAPI-ключВернуть кампанию из архива - PATCH
/orders/updateLimitAPI-ключЗадать или снять дневной потолок голосов
POST /orders/checkout
Тело запроса — это JSON-массив строк корзины на верхнем уровне, а не объект. Каждая строка — отдельная кампания. Вся корзина проверяется до любого списания, а списание и вставки идут одной транзакцией: заказ либо проходит целиком, либо не проходит вовсе.
Строка с фиксированным количеством
Обычный случай: доставить заданное число голосов на один адрес.
| Параметр | Тип | Описание |
|---|---|---|
idобязательный | integer | Идентификатор сайта из /orders/getAllWebsites. |
amountобязательный | integer | Сколько голосов доставить. От 0 и не более 2 147 483 647. |
ownNameобязательный | url | Адрес голосования. Сохраняется как поле `url` заказа. |
custom_max_per_hour | integer | Потолок доставки, обрезается до максимума самого сайта. |
extra_col | string | Свободное текстовое поле, которое хранится с заказом. |
curl -X POST "https://backend.toplistbot.com/orders/checkout?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"id": 9,
"amount": 1000,
"ownName": "https://arena-top100.com/index.php?a=in&u=yourserver",
"custom_max_per_hour": 60
}
]'200 OK
Successfully purchased with token balanceСтрока подписки
Для сайтов, у которых признак `subscribeable` равен 1. Цена считается как subscription_price_1d сайта, умноженная на число дней и на скидку уровня: Weekly — 0,90, Monthly — 0,80, всё остальное — 1,00. Доставляемое количество выводится на сервере из собственного subscription_speed сайта, поэтому ничем из запроса его не изменить.
[
{
"type": "subscription",
"website": { "id": 9 },
"subscription_days": 30,
"tier": { "name": "Monthly" },
"url": "https://arena-top100.com/index.php?a=in&u=yourserver"
}
]Ответы
200Все строки созданы, с баланса списано. Тело ответа — обычный текст.400Тело запроса не является корректным JSON.402Не хватает токенов. В сообщении указана нужная сумма, списания не было.422Одна или несколько строк некорректны. Списания не было.429Та же корзина отправлялась в последние 60 секунд. Повторите после указанной паузы.
Ответ 422 указывает на проблемную строку: ошибки нумеруются как items.[index].[field], поэтому корзина с тремя плохими строками чинится за один заход, а не за три.
{
"errors": {
"items.2.amount": ["Enter 0 or more votes; a negative amount is not allowed."]
}
}POST /orders/update
`id` обязателен; отправляйте только те поля, которые меняете. Заказы-подписки изменить нельзя.
| Параметр | Тип | Описание |
|---|---|---|
idобязательный | integer | Кампания, которую меняем. |
amount_to_do | integer | Новое общее число голосов. Увеличение списывает разницу, уменьшение возвращает её, между изменениями пауза в 30 секунд. |
url | url | Адрес голосования. |
custom_name | string | Ваше собственное название кампании. |
custom_max_per_hour | integer | Потолок доставки. |
username_profile_id | integer | Привязать профиль голосов. |
proxy_profile_id | integer | Привязать профиль прокси. |
http_referral | url | Реферер, отправляемый с каждым голосом. |
extra_col | string | Свободное текстовое поле. |
curl -X POST "https://backend.toplistbot.com/orders/update?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id":184223,"amount_to_do":2000,"custom_name":"EU launch"}'Дневной потолок
`type: "delete"` снимает потолок. Валидатор всё равно требует `max_votes_per_day` — отправьте любое целое число.
curl -X PATCH "https://backend.toplistbot.com/orders/updateLimit?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id":184223,"max_votes_per_day":500,"type":"set"}'Логи и аналитика
Данные о доставке — по каждому голосу и в агрегате. Они читают отдельную базу логов и медленнее остального API: опрашивайте их раз в минуты, а не в секунды.
- GET
/orders/logs/{id}API-ключЛог доставки кампании по каждому голосу - GET
/orders/graph/{id}API-ключВременной ряд одной кампании, готовый к отрисовке - GET
/api/orders/graph/summaryJWTОдин ряд по всем вашим кампаниям - GET
/orders/grouped/usernames/{id}API-ключДоставки, сгруппированные по голосовавшему имени - POST
/orders/averageAPI-ключСредняя доставка по нескольким кампаниям - GET
/api/logs/{id}/filtered-graphJWTОтфильтрованный временной ряд
Профили голосов и прокси
Профиль голосов — это именованный список имён, от которых голосует кампания. Профиль прокси — именованный список разрешённых стран для используемых IP. Привяжите любой из них к кампании через username_profile_id или proxy_profile_id в /orders/update.
- GET
/advanced/profile/getAPI-ключВаши профили голосов - GET
/advanced/profile/get/{id}API-ключОдин профиль голосов - POST
/advanced/profile/createAPI-ключСоздать профиль голосов или перезаписать по идентификатору - DELETE
/advanced/profile/delete/{id}API-ключУдалить профиль голосов - GET
/advanced/profile/proxy/getAPI-ключВаши профили прокси - GET
/advanced/profile/proxy/get/{id}API-ключОдин профиль прокси - POST
/advanced/profile/proxy/createAPI-ключСоздать профиль прокси или перезаписать по идентификатору - DELETE
/advanced/profile/proxy/delete/{id}API-ключУдалить профиль прокси
Токены Discord
Для топов, которые проверяют голосующих через Discord. Повторное добавление того же токена отклоняется как дубликат.
- GET
/api/discord-tokensJWTВаши токены Discord - POST
/api/discord-tokensJWTДобавить токен - GET
/api/discord-tokens/statsJWTСтатистика использования ваших токенов - GET
/api/discord-tokens/{id}JWTОдин токен - PATCH
/api/discord-tokens/{id}JWTИзменить токен или его активность - DELETE
/api/discord-tokens/{id}JWTУдалить токен - PUT
/api/discord-tokens/{id}/toggleJWTПереключить токен между включённым и выключенным
Счета и платежи
Покупка токенов всегда заканчивается на размещённой у провайдера странице оплаты, поэтому пополнение нельзя сделать полностью автоматическим. Всё, что после пополнения, — можно.
- GET
/invoices/getAPI-ключИстория счетов - GET
/api/subscriptions/subscriptionsJWTАктивные подписки - GET
/products/tokensByUserAPI-ключПакеты токенов по ценам вашего аккаунта - POST
/company/getAPI-ключВаш платёжный адрес - POST
/company/createAPI-ключЗадать его: country, region, city, address, postalCode - GET
/api/stripe/checkout?product_id=JWTСсылка Stripe Checkout для пакета токенов - GET
/api/stripe/subscription?plan=JWTСсылка Stripe Checkout для тарифа - GET
/api/stripe/portalJWTСсылка на платёжный портал Stripe - GET
/api/stripe/documentsJWTСчета и квитанции Stripe - GET
/coinpayments/checkoutAPI-ключСсылка на оплату криптовалютой
Сохранённая корзина
Корзина панели, которая хранится на сервере и переживает смену устройства. Для оформления заказов она не нужна: /orders/checkout принимает корзину прямо в запросе.
- GET
/api/cartJWTСохранённая корзина - PUT
/api/cartJWTЗаменить её - POST
/api/cartJWTЗаменить её — то же, что PUT - DELETE
/api/cartJWTОчистить её
Внутренние эндпоинты
Они существуют для Stripe, планировщика задач и защиты регистрации от злоупотреблений. Аутентифицируются общими секретами или подписями и не входят в интеграционную поверхность: перечислены здесь только ради полноты списка.
- POST
/api/stripe/webhookСобытия оплаты Stripe, проверяются по подписи - POST
/api/jobs/tickЗапускает подошедшие задачи, доступ по общему секрету - POST
/api/pow/challengeПроверка proof-of-work при регистрации - POST
/api/logs/updateУчёт активности в письмах - POST
/api/order/{email}Создаёт заказ на другом аккаунте — только для списка администраторов - GET
/reset-password/{token}Старая серверная страница сброса пароля, оставлена ради уже отправленных ссылок - GET
/ОткрытыйПроверка доступности
Формат ответов
Почти всё, что вы будете читать, приходит в двух объектах: сайт — из эндпоинтов каталога и кампания — из эндпоинтов заказов. В каждом около сорока колонок; в таблицах ниже те, которые действительно нужны интеграции.
Три поля приходят JSON-строками, хотя содержат числа: accept_rate и timeout у сайта, custom_max_per_hour у кампании. Приводите их к числу до арифметики, иначе получите склейку строк вместо сложения.
{
"accept_rate": "70", // string, not number
"timeout": "150000", // string, not number
"custom_max_per_hour": "60" // string, not number
}Объект сайта
Возвращают /orders/getAllWebsites и /orders/getWebsiteDetailsByName; он же вложен в каждую кампанию под ключом `website`.
| Параметр | Тип | Описание |
|---|---|---|
id | integer | Идентификатор сайта. Передаётся как `id` в строке корзины или как `service` в SMM-эндпоинте. |
name | string | Отображаемое имя и та самая строка, с которой сравнивает /orders/getWebsiteDetailsByName. |
price_per_1000 | number | Токенов за 1 000 принятых голосов. Именно это число использует формула стоимости. |
accept_rate | string | Процент отправленных голосов, которые принимаются. От него зависят все расчёты прогресса и возврата. |
max_per_hour | integer | Собственный потолок доставки сайта. И custom_max_per_hour, и interval в SMM обрезаются по нему. |
active | integer | 1 означает, что заказ возможен. Неактивные сайты тоже возвращаются, поэтому фильтруйте сами. |
vote_reset_time | integer | Через сколько часов та же личность может проголосовать снова. |
speed_changeable | integer | 1 означает, что сайт учитывает заданную вами скорость доставки. |
referer_must_be_set | integer | 1 означает, что у кампании должен быть задан http_referral. |
optional_data_possible | integer | 1 означает, что сайт принимает поле optional_data кампании. |
track_votes | integer | 1 означает, что для кампаний на этом сайте доступны логи по каждому голосу. |
subscribeable | integer | 1 означает, что строки подписки принимаются. |
subscription_price_1d | number | Токенов за день подписки, до скидки уровня. |
subscription_speed | integer | Голосов в час, которые выдаёт подписка. Количество выводится из этого на сервере, а не из вашего запроса. |
Опущенные здесь поля обслуживают интерфейс самой панели. Читайте их, если хотите, но они не входят в контракт интеграции и могут измениться без предупреждения.
Объект кампании
Возвращают /orders/getAll и /orders/get/. Обратите внимание на то, чего нет: поля статуса не существует.
| Параметр | Тип | Описание |
|---|---|---|
id | integer | Идентификатор кампании. Все эндпоинты раздела «Кампании» принимают его как `id`. |
vote_website_id | integer | Сайт, на котором работает кампания. |
website | object | Полный объект сайта, вложенный внутрь. Есть в /orders/getAll и отсутствует в /orders/get/. |
url | string | Адрес голосования — тот самый `ownName`, который вы отправили при оформлении. |
custom_name | string | Ваше название кампании или null. |
amount_to_do | integer | Куплено принятых голосов. Считает принятые голоса, а не попытки. |
amount_done | integer | Отправлено голосов на текущий момент. Единица измерения не та же, что у amount_to_do — см. раздел о прогрессе. |
running | integer | 1 — доставляет, 0 — на паузе. |
done | integer | 1 означает закрыта: отменена, возвращена, обе величины обнулены. Это не признак завершения. |
archive | integer | 1 означает в архиве. Архивные кампании всё равно возвращаются из /orders/getAll. |
custom_max_per_hour | string | Ваш потолок доставки для этой кампании, строкой. |
max_votes_per_day | integer | Дневной лимит голосов или null, если лимита нет. |
is_subscription | integer | 1 означает подписку. Подписки нельзя редактировать после покупки. |
paused_unpaused | datetime | Когда кампанию в последний раз ставили на паузу, возобновляли или меняли объём. Именно отсюда отсчитывается 30-секундная пауза между правками. |
Опущенные здесь поля обслуживают интерфейс самой панели. Читайте их, если хотите, но они не входят в контракт интеграции и могут измениться без предупреждения.
Работает ли она? Закончилась ли?
У кампании нет поля статуса, поэтому состояние выводится из четырёх колонок. Проверяйте условия по порядку и берите первое совпадение.
| Проверка | Означает |
|---|---|
1done === 1 | Отменена. Неизрасходованный остаток возвращён, обе величины обнулены, кампания отправлена в архив. |
2running === 0 | Вы поставили её на паузу. Возобновите через /orders/unpause. |
3remaining_accepted === 0 | Всё оплаченное доставлено. |
4running === 1 | Работает штатно. |
5archive === 1 | Скрыта в панели, но всё ещё возвращается из /orders/getAll. Отфильтруйте её, если хотите совпасть с тем, что показывает панель. |
Порядок важен. Отмена выставляет done и archive одновременно, поэтому проверка archive первой показала бы отменённую кампанию просто архивной, а проверка остатка раньше running показала бы приостановленную кампанию как доставляющую.
Прогресс и возвраты
amount_to_do считает принятые голоса, amount_done — отправленные. Принимается лишь accept_rate процентов отправленных, поэтому величины в разных единицах и вычитать одну из другой напрямую неверно.
Это самая частая ошибка интеграции, и она проваливается молча: числа выглядят правдоподобно, а полоса прогресса просто врёт. При проценте принятия 70 завершённая кампания читается как выполненная на 70 процентов; при 50 наполовину доставленная выглядит нетронутой. Всегда сначала переводите отправленные голоса в принятые.
// accept_rate arrives as a STRING, and it is per-site, not global.
const rate = Number(order.website.accept_rate)
// amount_done counts SUBMISSIONS; amount_to_do counts ACCEPTED votes.
// Convert before comparing them.
const delivered = order.amount_done * rate / 100
const remaining = Math.max(order.amount_to_do - delivered, 0)
const percent = 100 * delivered / order.amount_to_do
// What cancelling right now would put back on your balance:
const refund = (remaining / 1000) * order.website.price_per_1000Та же арифметика оценивает отмену: возвращается неизрасходованный остаток по прайсовой цене сайта, так что вы можете узнать, чего стоит остановка кампании, ещё до решения.
Кампания от начала до конца
Шесть вызовов, один API-ключ, без браузера и без входа. То же самое через SMM-эндпоинт — это три вызова (services, add, status), и API платформы вообще не нужен.
KEY=YOUR_API_KEY
BASE=https://backend.toplistbot.com
# 1. What can I order, and what does it cost?
curl -s "$BASE/orders/getAllWebsites" \
| jq '.[] | {id, name, price_per_1000, max_per_hour}'
# 2. What can I afford?
curl -s -X POST "$BASE/api/v2" -d "key=$KEY" -d "action=balance"
# 3. Launch it. cost = price_per_1000 * amount / 1000
curl -s -X POST "$BASE/orders/checkout?key=$KEY" \
-H "Content-Type: application/json" \
-d '[{"id":9,"amount":1000,
"ownName":"https://arena-top100.com/index.php?a=in&u=me",
"custom_max_per_hour":60}]'
# 4. Find the campaign that was just created.
curl -s "$BASE/orders/getAll?key=$KEY" | jq '.[0] | {id, url, amount_to_do, amount_done}'
# 5. Watch it. Poll every few minutes.
curl -s "$BASE/orders/graph/184223?key=$KEY"
# 6. Slow it down, or stop it.
curl -s -X PATCH "$BASE/orders/updateLimit?key=$KEY" \
-H "Content-Type: application/json" -d '{"id":184223,"max_votes_per_day":200,"type":"set"}'
curl -s -X POST "$BASE/orders/pause?key=$KEY" \
-H "Content-Type: application/json" -d '{"id":184223}'Ошибки
Ошибки возвращаются с соответствующим HTTP-статусом. При ошибках валидации приходит объект `errors`, где ключи — имена полей.
400Запрос не удалось прочитать: некорректный JSON или действие, неизвестное SMM-эндпоинту.401Доступ отсутствует, истёк или неверен.402Не хватает токенов. Списания не было.403Аутентификация прошла, но действие не разрешено.404Такой записи нет — включая ту, что принадлежит другому пользователю.409Конфликтует с текущим состоянием аккаунта, например повторное включение двухфакторной защиты.422Проверка не пройдена. В теле названо каждое поле.429Превышена частота. В сообщении указано, сколько ждать.500Наша ошибка. Списания не было.503Зависимость недоступна. Повторите позже.
{
"errors": {
"quantity": ["The quantity must be at least 1."]
}
}Если телом запроса был массив, ключи ошибок содержат номер строки, которая не прошла проверку.
Несколько эндпоинтов отвечают обычным текстом, а не JSON: среди них /orders/checkout, /orders/pause и /orders/updateLimit. Ориентируйтесь на код статуса, а не на форму тела.
Ограничения частоты
Ответ 429 всегда сообщает, сколько ждать. Соблюдайте паузу вместо слепых повторов.
- Одна и та же корзина принимается не чаще раза в 60 секунд.
- Общее число голосов кампании можно менять раз в 30 секунд.
- Попытки входа ограничены по адресу и по IP.
- Сброс пароля: 3 на адрес и 10 на IP за 15 минут.
- `status` и `cancel` принимают не более 100 идентификаторов заказов за вызов.
- Опрашивайте прогресс раз в минуты, а не в секунды. Доставка измеряется в голосах в час.
Ограничения и примечания
- Количество в заказе должно быть от 1 до 50000 действий.
- Интервал по умолчанию — 15 в час, максимум 4000. Запрос выше собственного лимита сайта отклоняется с ошибкой 400, в которой указан лимит.
- Действия `refill` и `refill_status` не реализованы — вместо этого создайте новый заказ.
- Поле `status` всегда равно строке "Completed" и не показывает прогресс. Используйте `remains == 0`, чтобы понять, что заказ завершён, и `start_count` — чтобы узнать доставленное.
- Подписки нельзя менять после покупки — приостановите или отмените их.
- Сайты-каталоги устанавливают собственные правила и со временем их меняют. Вы сами отвечаете за то, чтобы использование сервиса соответствовало правилам любого сайта, на котором вы продвигаетесь. Мы не обещаем какую-либо позицию или место в рейтинге.
