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

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

Всё, что делает панель, доступно по HTTP. Направьте SMM-панель на один эндпоинт или управляйте всей платформой — каталогом, кампаниями, логами, счетами — из скрипта или ИИ-агента.

На этой странице

Обзор

Toplistbot предоставляет два HTTP API. Оба работают с JSON поверх HTTPS, оба тратят один и тот же баланс токенов, и любого из них достаточно, чтобы вести кампании, ни разу не открыв панель.

Базовый URL

Base URL
https://backend.toplistbot.com/api
https://backend.toplistbot.com

Справочник ниже написан для этих двух хостов. От выбора хоста зависит способ аутентификации — см. раздел «Аутентификация».

Начало работы

От нового аккаунта до работающей кампании за пять шагов. Всё ниже использует эндпоинт SMM — самый быстрый путь; API платформы работает так же, как только вы получите JWT.

  1. Создайте аккаунт

    Зарегистрируйтесь и подтвердите почту. Подтверждение начисляет 100 бесплатных токенов — этого хватит на настоящую кампанию, прежде чем вы что-то потратите.

  2. Скопируйте ключ API

    Откройте личный кабинет и создайте ключ API. Относитесь к нему как к паролю — он тратит ваш баланс токенов. Ключ можно перевыпустить в любой момент, старый сразу перестаёт работать.

  3. Найдите нужный сервис

    Получите список всех сайтов, на которых можно оформить заказ. У каждой записи есть числовой id сервиса и тариф в токенах за 1 000 действий. Запишите id сайта, на котором хотите продвигаться.

    cURL
    curl -X POST https://backend.toplistbot.com/api/v2 -d "key=YOUR_API_KEY" -d "action=services"
  4. Оформите первый заказ

    Отправьте id сервиса, URL, на котором будет работать кампания, и количество действий. Стоимость списывается сразу, а в ответе приходит id заказа.

    cURL
    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"
  5. Отслеживайте выполнение

    Запрашивайте статус по id заказа, чтобы видеть, сколько уже выполнено. Когда схема вас устроит, встройте те же вызовы в свою панель или скрипты.

    cURL
    curl -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-запросы. Держите ключ в переменной окружения, а не в самом сообщении.

Prompt
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/getAllJWTВсё, где входит живой человек
/orders/getAllAPI-ключСкрипты, планировщики, агенты

Для автоматизации лучше пути без префикса. Нет входа, нет истечения, нет сессии, которую надо поддерживать: один ключ делает всё, и двухфакторная защита никогда не мешает.

API-ключ

Передавайте ключ полем `key` в любом запросе: параметром строки запроса, полем формы, полем JSON или заголовком `Authorization: Bearer`. Создавайте и меняйте его в панели. GET на /api/v2 возвращает статус ok — дешёвый способ проверить, что ключ жив.

cURL
# 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"
Health check
curl https://backend.toplistbot.com/api/v2?key=YOUR_API_KEY

JWT

Войдите, чтобы получить токен, и передавайте его как bearer-токен на маршрутах /api. Токены истекают, поэтому вызывайте /auth/refresh заранее. Если на аккаунте включена двухфакторная защита, при входе нужен ещё и `two_factor_code`.

Login
curl -X POST https://backend.toplistbot.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"..."}'
Response
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": { "id": 4211, "email": "[email protected]", "tokens": 528.41, "...": "..." }
}
Authenticated request
curl https://backend.toplistbot.com/api/orders/getAll \
  -H "Authorization: Bearer YOUR_JWT"

Вызовы из браузера

Все маршруты отвечают с открытым Access-Control-Allow-Origin, поэтому страница, расширение браузера или работающий в браузере агент могут обращаться к API напрямую — собственный прокси не нужен. Предупреждение выше остаётся в силе: ключ, отданный браузеру, — это опубликованный ключ, так что это для ваших собственных инструментов, а не для публичной страницы.

JavaScript
// 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 formula
cost_in_tokens = (rate * quantity) / 1000

Сайт с тарифом 13 стоит 13 токенов за 1 000 действий, значит заказ на 500 обойдётся в 6,5 токена. Стоимость списывается при принятии заказа, а отмена возвращает неизрасходованный остаток.

Ответы balance и status указывают валюту USD ради совместимости с Perfect Panel, но значение — это баланс токенов, а не доллары. Считайте это число токенами.

API SMM-панели

Всё выполняет один эндпоинт. Передавайте поле `action` в каждом POST-запросе, чтобы выбрать операцию; каждый запрос также содержит ваш `key`.

POSThttps://backend.toplistbot.com/api/v2
ДействиеПараметры
services
addservice, link, quantity, interval?
statusorders
balance
cancelorders

`refill` и `refill_status` принимаются ради совместимости и обе отвечают «не реализовано». Здесь ничего нельзя дозаправить — оформите новый заказ.

action=services

Возвращает все сайты, на которых можно оформить заказ, с текущим тарифом и ограничениями. Используйте id `service` в вызовах add.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=services"
Response
[
  {
    "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обязательныйintegerId сервиса из действия services.
linkобязательныйurlURL, на котором работает кампания. Должен быть корректным URL.
quantityобязательныйintegerКоличество действий, от 1 до 50000.
intervalintegerДействий в час. По умолчанию 15, максимум 4000, и не может превышать собственный лимит сайта.
cURL
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"
Response
{
  "order_id": 184223
}

action=status

Возвращает прогресс по одному или нескольким заказам. Передайте один id, чтобы получить простой объект, или список через запятую.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "orders=184223"
Response — single order
{
  "charge": 13.5,
  "start_count": 0,
  "status": "Completed",
  "remains": 1000,
  "currency": "USD"
}

При нескольких id ответ индексируется по id заказа, а неизвестные или чужие заказы возвращают запись об ошибке, не обрушивая весь запрос.

Response — multiple orders
{
  "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
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=balance"
Response
{
  "balance": 528.41,
  "currency": "USD"
}

action=cancel

Останавливает заказ и возвращает неизрасходованный остаток на баланс. Завершённые заказы отменить нельзя.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=cancel" \
  -d "orders=184223,184224"
Response
[
  { "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
curl "https://backend.toplistbot.com/orders/getAllWebsites"

Просите меньше

Полный каталог занимает около 665 КБ на 396 сайтов, и половину этого веса дают два поля, с которыми вы никогда не оформите заказ: JSON-блок популярности и маркетинговое описание. Оставьте только поля, которыми заказываете, отбросьте неактивные сайты — и останется около 40 КБ.

cURL + jq
# 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_hourintegerПотолок доставки, обрезается до максимума самого сайта.
extra_colstringСвободное текстовое поле, которое хранится с заказом.
cURL
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
    }
  ]'
Response
200 OK
Successfully purchased with token balance

Строка подписки

Для сайтов, у которых признак `subscribeable` равен 1. Цена считается как subscription_price_1d сайта, умноженная на число дней и на скидку уровня: Weekly — 0,90, Monthly — 0,80, всё остальное — 1,00. Доставляемое количество выводится на сервере из собственного subscription_speed сайта, поэтому ничем из запроса его не изменить.

Body
[
  {
    "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], поэтому корзина с тремя плохими строками чинится за один заход, а не за три.

422 body
{
  "errors": {
    "items.2.amount": ["Enter 0 or more votes; a negative amount is not allowed."]
  }
}

POST /orders/update

`id` обязателен; отправляйте только те поля, которые меняете. Заказы-подписки изменить нельзя.

ПараметрТипОписание
idобязательныйintegerКампания, которую меняем.
amount_to_dointegerНовое общее число голосов. Увеличение списывает разницу, уменьшение возвращает её, между изменениями пауза в 30 секунд.
urlurlАдрес голосования.
custom_namestringВаше собственное название кампании.
custom_max_per_hourintegerПотолок доставки.
username_profile_idintegerПривязать профиль голосов.
proxy_profile_idintegerПривязать профиль прокси.
http_referralurlРеферер, отправляемый с каждым голосом.
extra_colstringСвободное текстовое поле.
cURL
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
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 у кампании. Приводите их к числу до арифметики, иначе получите склейку строк вместо сложения.

Types to watch
{
  "accept_rate": "70",          // string, not number
  "timeout": "150000",          // string, not number
  "custom_max_per_hour": "60"   // string, not number
}

Объект сайта

Возвращают /orders/getAllWebsites и /orders/getWebsiteDetailsByName; он же вложен в каждую кампанию под ключом `website`.

ПараметрТипОписание
idintegerИдентификатор сайта. Передаётся как `id` в строке корзины или как `service` в SMM-эндпоинте.
namestringОтображаемое имя и та самая строка, с которой сравнивает /orders/getWebsiteDetailsByName.
price_per_1000numberТокенов за 1 000 принятых голосов. Именно это число использует формула стоимости.
accept_ratestringПроцент отправленных голосов, которые принимаются. От него зависят все расчёты прогресса и возврата.
max_per_hourintegerСобственный потолок доставки сайта. И custom_max_per_hour, и interval в SMM обрезаются по нему.
activeinteger1 означает, что заказ возможен. Неактивные сайты тоже возвращаются, поэтому фильтруйте сами.
vote_reset_timeintegerЧерез сколько часов та же личность может проголосовать снова.
speed_changeableinteger1 означает, что сайт учитывает заданную вами скорость доставки.
referer_must_be_setinteger1 означает, что у кампании должен быть задан http_referral.
optional_data_possibleinteger1 означает, что сайт принимает поле optional_data кампании.
track_votesinteger1 означает, что для кампаний на этом сайте доступны логи по каждому голосу.
subscribeableinteger1 означает, что строки подписки принимаются.
subscription_price_1dnumberТокенов за день подписки, до скидки уровня.
subscription_speedintegerГолосов в час, которые выдаёт подписка. Количество выводится из этого на сервере, а не из вашего запроса.

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

Объект кампании

Возвращают /orders/getAll и /orders/get/. Обратите внимание на то, чего нет: поля статуса не существует.

ПараметрТипОписание
idintegerИдентификатор кампании. Все эндпоинты раздела «Кампании» принимают его как `id`.
vote_website_idintegerСайт, на котором работает кампания.
websiteobjectПолный объект сайта, вложенный внутрь. Есть в /orders/getAll и отсутствует в /orders/get/.
urlstringАдрес голосования — тот самый `ownName`, который вы отправили при оформлении.
custom_namestringВаше название кампании или null.
amount_to_dointegerКуплено принятых голосов. Считает принятые голоса, а не попытки.
amount_doneintegerОтправлено голосов на текущий момент. Единица измерения не та же, что у amount_to_do — см. раздел о прогрессе.
runninginteger1 — доставляет, 0 — на паузе.
doneinteger1 означает закрыта: отменена, возвращена, обе величины обнулены. Это не признак завершения.
archiveinteger1 означает в архиве. Архивные кампании всё равно возвращаются из /orders/getAll.
custom_max_per_hourstringВаш потолок доставки для этой кампании, строкой.
max_votes_per_dayintegerДневной лимит голосов или null, если лимита нет.
is_subscriptioninteger1 означает подписку. Подписки нельзя редактировать после покупки.
paused_unpauseddatetimeКогда кампанию в последний раз ставили на паузу, возобновляли или меняли объём. Именно отсюда отсчитывается 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 наполовину доставленная выглядит нетронутой. Всегда сначала переводите отправленные голоса в принятые.

JavaScript
// 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 платформы вообще не нужен.

bash
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Зависимость недоступна. Повторите позже.
Validation error
{
  "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` — чтобы узнать доставленное.
  • Подписки нельзя менять после покупки — приостановите или отмените их.
  • Сайты-каталоги устанавливают собственные правила и со временем их меняют. Вы сами отвечаете за то, чтобы использование сервиса соответствовало правилам любого сайта, на котором вы продвигаетесь. Мы не обещаем какую-либо позицию или место в рейтинге.
Начните бесплатно

Начните продвижение прямо сейчас!

Подтвердите электронную почту и получите 100 бесплатных токенов, чтобы попробовать наш сервис. Без обязательств.

Без банковской карты
Отмена в любой момент
Поддержка 24/7