Справочник по API
BlankTrail Proxy предоставляет локальный HTTP API, с помощью которого вы можете открывать порты, настраивать идентичности и автоматизировать всё, что делает дашборд. На этой странице описаны базовый URL, аутентификация и соглашения.
Базовый URL
Все эндпоинты находятся под префиксом /api/v1 на том же хосте и порту, что и дашборд:
http://127.0.0.1:8891/api/v1
API и дашборд используют один и тот же источник (origin), поэтому вызовы из ваших собственных скриптов и инструментов работают сразу и без дополнительной настройки.
Аутентификация
API работает по принципу «запрещено по умолчанию»: почти каждый эндпоинт требует аутентификации. Есть два способа аутентификации:
- API-ключ — передавайте его в заголовке X-API-Key. Лучший вариант для скриптов и автоматизации.
- Сессионная cookie — получается при входе в систему; используется веб-дашбордом.
Найти и заменить свой API-ключ можно в диалоге «Настройки» дашборда. Передавайте его в каждом запросе:
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/status
Соглашения
- Запросы и ответы — в формате JSON. В запросах с телом отправляйте Content-Type: application/json.
- Конфигурация всегда передаётся в теле JSON, а не в строке запроса.
- API версионируется под префиксом /api/v1. Несовместимые изменения будут вынесены в новый префикс версии.
Коды состояния
Тело ошибки всегда одно и то же: объект с полем error и текстом на английском; у части отказов рядом стоит поле code — машиночитаемая причина. Тексты приведены в описаниях ручек: по ним отличают одну причину 400 от другой. Исключение — 405: его отдаёт маршрутизатор обычной строкой, без JSON.
| Код | Значение |
|---|---|
200 OK | Успех. |
202 Accepted | Принято и выполняется в фоне — так отвечает запуск обновления. |
400 Bad Request | Плохой ввод: тело не разбирается, поля нет, значение недопустимо. |
401 Unauthorized | Ключ API не прислан или неверен. Проверьте имя заголовка: X-API-Key. |
403 Forbidden | Действие запрещено не ключом, а состоянием: лицензия неактивна (подписка кончилась или сутки не было связи с сервером авторизации) либо возможность требует тарифа Pro. |
404 Not Found | Такого нет: путь не зарегистрирован, порт не открыт, узел не найден. |
405 Method Not Allowed | Путь есть, а метод не тот — например PUT на ручку только для чтения. Этот код отдаёт сам маршрутизатор, а не обработчик. |
409 Conflict | Состояние мешает: порт уже занят, имя уже есть, шлюз используется. |
429 Too Many Requests | Слишком часто — например, повторная отправка отчёта о проблеме. Снизьте частоту и повторите. |
500 Internal Server Error | Непредвиденная ошибка внутри приложения. |
501 Not Implemented | Узел не собран или не проведён в этой сборке — так отвечает вход в дашборд, когда авторизация не настроена. |
502 Bad Gateway | Не удалось сходить наружу: Кабинет недоступен, заход по адресу не состоялся. |
503 Service Unavailable | Нечем ответить прямо сейчас: свободного порта нет, служба не поднята, отладочные крючки не проведены. |
Справочник по темам
- Порты и трафик — открытие, закрытие, получение списка и настройка портов; тестирование вышестоящего прокси.
- Профили и маршрутизация — идентичности, пресеты, правила доменов и шлюзы.
- Пул портов — открытие пулов портов из списка прокси и управление ими.
- Лицензия и доступ — статус лицензии, аутентификация и CA-сертификат.
Служебные ручки
Эти ручки нужны не в сценарии, а рядом с ним: убедиться, что приложение живо, поднять подробность журнала на время разбирательства, узнать про обновление, задать общее правило маршрутизации.
/api/v1/log_levelТребуется авторизацияТекущая подробность журнала.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/log_level{
"level": "info"
}/api/v1/log_levelТребуется авторизацияПоднимает подробность на время разбирательства: debug пишет заметно больше и держится до перезапуска.
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
level | string | Да | debug, info, warn или error. |
{ "level": "debug" }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"level":"debug"}' \
http://127.0.0.1:8891/api/v1/log_level{
"level": "debug"
}- 400 «level must be one of: debug, info, warn, error» на любом другом значении.
/api/v1/update/statusТребуется авторизацияКакая версия стоит и есть ли новая: available пуст, пока обновления нет; state показывает, чем занят обновлятор сейчас.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/update/status{
"current": "1.3.2",
"available": "",
"state": "idle",
"last_error": "",
"download_url": ""
}- 404 «self-update not available» в сборке, где самообновление не собрано.
/api/v1/updateТребуется авторизацияСтавит обновление, о котором сообщил /update/status. Приложение перезапускается само.
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/update{
"status": "started"
}- 🔴 Ответ — 202 Accepted, а не 200: обновление принято и идёт в фоне, а не закончилось к моменту ответа. Дожидаться его нужно опросом /update/status.
- 409 «no update available», если ставить нечего; 404 «self-update not available» в сборке без самообновления.
/api/v1/domain_routingТребуется авторизацияПростое правило маршрутизации: список доменов и общий для них выходной прокси. Пустой список — правило выключено. Подробные правила с именами живут в /domain_rules.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/domain_routing{
"domains": ["example.com", "*.example.net"],
"proxy": "socks5://203.0.113.10:1080"
}/api/v1/domain_routingТребуется авторизацияЗадаёт простое правило целиком: домены и прокси. Пустой список доменов его выключает.
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
domains | array | Да | Домены и маски вида *.example.net. |
proxy | string | Да | Выходной прокси для этих доменов. |
{ "domains": ["example.com"], "proxy": "socks5://203.0.113.10:1080" }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"domains":["example.com"],"proxy":"socks5://203.0.113.10:1080"}' \
http://127.0.0.1:8891/api/v1/domain_routing{
"domains": ["example.com"],
"proxy": "socks5://203.0.113.10:1080"
}- 400 с объяснением, если домен или адрес прокси не той формы.
/api/v1/idle_timeoutТребуется авторизацияОбщий тайм-аут простоя для портов, у которых нет своего. 0 — не закрывать.
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
seconds | int | Да | Секунды простоя до автозакрытия порта; 0 — не закрывать. |
{ "seconds": 1800 }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"seconds":1800}' \
http://127.0.0.1:8891/api/v1/idle_timeout{
"idle_timeout_seconds": 1800
}- 400 «seconds must be >= 0» на отрицательном значении. Порт со своим переопределением (PUT /api/v1/port/{port}/idle) это значение не берёт.
Отчёт об ошибке
Отчёт собирает журналы и состояние портов и отправляет их в поддержку. Перед отправкой его можно посмотреть целиком — это тот же файл, который уйдёт.
/api/v1/bug-report/statusТребуется авторизацияВключена ли отправка отчётов и не завершился ли прошлый запуск аварийно — тогда дашборд сам предложит отправить отчёт.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/bug-report/status{
"enabled": true,
"unclean_previous_exit": false
}- enabled=false означает, что отправка недоступна без активной лицензии.
/api/v1/bug-report/previewТребуется авторизацияСобирает отчёт и показывает его, ничего не отправляя.
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/bug-report/preview{
"report": { "version": 1, "ports": [ … ], "log": [ … ] },
"notes_included": false
}- 404 «bug report not available», если сбор отчётов не поднят; 500 «failed to build report».
/api/v1/bug-report/sendТребуется авторизацияОтправляет отчёт в поддержку вместе с вашим описанием.
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
description | string | Да | Что случилось. Поле обязательно: пустое после обрезки пробелов отвергается. |
{ "description": "После смены выхода порт перестал отдавать 200" }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"description":"port stopped returning 200 after an egress change"}' \
http://127.0.0.1:8891/api/v1/bug-report/send{
"status": "sent",
"bug_report_id": "br-7f3a1c9d"
}- 400 «description required» без описания; 403 «activate your license to send a bug report»; 404 «bug report not available»; 429 при частой отправке; 502, если сервер поддержки недоступен.
- Тело ограничено 64 КиБ.
/api/v1/bug-report/dismissТребуется авторизацияОтказывается от предложенного отчёта: гасит уведомление об аварийном завершении до конца этого запуска.
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/bug-report/dismiss{
"status": "dismissed"
}- Отметка живёт в памяти: настоящее новое аварийное завершение поставит её снова на следующем запуске.
Диагностика
Эти пути нужны, когда приложение ведёт себя не так и к обращению в поддержку надо приложить цифры, а не описание. Продуктовой поверхностью они не являются: их формат задан средой выполнения и может измениться между версиями.
/api/v1/debugТребуется авторизацияСнимок самого процесса: горутины, системные потоки, дескрипторы, память и время работы. Это первое, что стоит приложить к обращению, если приложение стало тяжёлым.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/debug{
"goroutines": 142,
"threads": 21,
"handles": 380,
"open_ports": 2,
"uptime": "3h14m22s",
"memory": {
"alloc_mb": 96,
"total_alloc_mb": 8140,
"sys_mb": 310,
"heap_objects": 410000,
"heap_inuse_mb": 120,
"heap_released_mb": 64,
"gc_cycles": 1830,
"stack_inuse_mb": 6
}
}- Поле handles приходит всегда, но осмысленно только на Windows: там его считает сама система, а на прочих платформах оно всегда 0.
Профилирование (pprof)
Одиннадцать стандартных путей Go, открытых по обычному ключу API. Отдают они внутреннее устройство процесса, а не данные пользователя, но за ключом стоят так же, как остальной API.
| Путь | Что отдаёт |
|---|---|
/debug/pprof/ | Оглавление: список доступных профилей. |
/debug/pprof/heap | Снимок кучи — с чего начинать, если растёт память. |
/debug/pprof/goroutine | Все горутины со стеками — с чего начинать, если что-то зависло. |
/debug/pprof/allocs | Все выделения памяти за время работы. |
/debug/pprof/profile | Профиль процессора. 🔴 Держит соединение 30 секунд — это не зависание. |
/debug/pprof/trace | Трассировка выполнения. |
/debug/pprof/block | Где горутины ждали на блокировках. |
/debug/pprof/mutex | Состязание за мьютексы. |
/debug/pprof/threadcreate | Создание системных потоков. |
/debug/pprof/cmdline | Командная строка процесса. |
/debug/pprof/symbol | Разрешение адресов в имена функций. |
Снять кучу и горутины для отчёта: curl -H "X-API-Key: YOUR_API_KEY" -o heap.pprof http://127.0.0.1:8891/debug/pprof/heap и то же с goroutine. Открывать их удобно командой go tool pprof heap.pprof.
Отладочный контур примет солвера
Контур нужен для одного: проверить, совпадёт ли примета вызова, не пересобирая и не выкладывая пак. До него один такой цикл стоил пересборки пака, подписи, выкладки и до получаса ожидания, пока клиент перечитает пак.
/api/v1/debug/signaturesТребуется авторизацияСообщает, стоит ли сейчас отладочный слой примет поверх паковой базы и сколько в нём записей.
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/debug/signatures{
"debug_active": true,
"debug_vendors": 3
}- 503 «solver debug hooks not wired», если рубильник выставлен, но крючки солвера в этой сборке не проведены. Это НЕ 404: сам маршрут существует, и различить два состояния важно.
/api/v1/debug/signaturesТребуется авторизацияСтавит присланный набор примет ОТДЕЛЬНЫМ слоем поверх паковой базы — без пересборки пака, подписи и выкладки.
{ "Version": 7, "Vendors": [ { "…": "…" } ], "NavHints": [ ] }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
--data-binary @signatures.json \
http://127.0.0.1:8891/api/v1/debug/signatures{
"installed": 3,
"dropped": 1
}- Тело — база примет в том же формате, что и паковая. installed — сколько вендоров принято, dropped — сколько ПРИСЛАННЫХ условий забраковано.
- Слой переживает любое число обновлений пака и снимается только явным DELETE. Установка пишется в журнал предупреждением — забытый слой не должен остаться незаметным.
- 503 «solver debug hooks not wired»; 400 «invalid JSON body».
/api/v1/debug/signaturesТребуется авторизацияСнимает отладочный слой примет и возвращает солвер к паковой базе.
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/debug/signatures{
"cleared": true
}- 503 «solver debug hooks not wired», если крючки не проведены.
/api/v1/port/{port}/solve_probeТребуется авторизацияПриводит солвер на указанный адрес ЧЕРЕЗ конкретный порт и возвращает, что он там увидел — независимо от того, совпала примета или нет.
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
url | string | Да | Адрес, на который вести солвер. |
solve | bool | Нет | false (по умолчанию) — только распознать вендора и характер страницы, около секунды. true — ещё и принудительно решить. |
{ "url": "https://example.com/", "solve": true }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-H "Accept-Language: ru-RU,ru;q=0.9" \
-d '{"url":"https://example.com/","solve":true}' \
http://127.0.0.1:8891/api/v1/port/20134/solve_probe- 🔴 При solve=true искусственного тайм-аута здесь НЕТ намеренно: принудительное решение честно занимает десятки секунд, а у некоторых проверок — до полутора минут. Запрос не завис.
- Заголовок Accept-Language ЭТОГО запроса прокидывается в задачу дословно: язык запуска влияет на исход, и без него солв уехал бы с языком выходного узла вместо запрошенного.
- 503 «solver debug hooks not wired»; 400 «url is required»; 502 с текстом ошибки, если сам заход не удался.