API — 许可证、访问与证书
通过 API 查询许可证状态、管理身份验证、读取整体系统状态,并下载根证书。
许可证
/api/v1/license/status需要鉴权返回许可证是否处于激活状态,以及您的套餐、端口池权限 (pool) 和 Challenge Breaker 进程上限。此处不返回端口上限:实际生效的上限见 GET /api/v1/status 的 max_ports 字段。
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/license/status{
"activated": true,
"email": "demo@blanktrail.pro",
"plan": "pro",
"period_end": "2027-02-15T00:00:00Z",
"pool": true,
"js_solver_max_procs": 4,
"js_solver_procs": 4,
"js_solver_live_procs": 1
}- label 与 allowed_domains 两个字段仅在服务(促销)套餐下返回,因此上面的示例中没有它们:label 是套餐名称的后缀,控制面板显示为 “Pro (WB)”;allowed_domains 是该套餐被限制到的域名列表,面板会在套餐名称下方显示“仅限以下域名:…”。
- 🔴 allowed_domains 是限制而非提示:只要列表非空,端口就只放行这些域名。不带前缀的条目覆盖该域名及其全部子域;以 “=” 开头的条目只精确匹配该名称;裸 IP 地址永远不会匹配。列表为空(字段缺失)即不受限制。
- 🔴 拒绝来自代理端口本身,而不是这个 API:HTTP CONNECT 与普通 HTTP 收到空响应体的 403 Forbidden——没有 JSON,也没有 error 字段;SOCKS5 收到应答码 0x02 “connection not allowed by ruleset”;在此类套餐下根本不会授予 UDP ASSOCIATE。这与上游代理无关——更换出口没有用,请把地址与列表核对。
- 对列表之外的主机不会启动 Challenge Breaker。API 接口、端口测试以及控制面板的其余部分照常工作。
身份验证
此处的密码属于控制面板,而非 API:API 请求通过 X-API-Key 头中的密钥进行鉴权,无需会话 Cookie。这些接口服务于界面与初次配置脚本。
/api/v1/auth/login无需鉴权使用密码登录控制面板;设置会话 Cookie。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
password | string | 是 | 控制面板密码。 |
{ "password": "your-dashboard-password" }curl -X POST -H "Content-Type: application/json" -c cookies.txt \
-d '{"password":"your-dashboard-password"}' \
http://127.0.0.1:8891/api/v1/auth/login{
"status": "ok"
}- 401 “invalid password”;同一地址连续失败后返回 429 “too many attempts — try again later”。
- 若该构建未配置控制面板登录,返回 501 “auth not configured”。
/api/v1/auth/logout需要鉴权清除控制面板的会话 Cookie。
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/auth/logout{
"status": "ok"
}/api/v1/auth/status需要鉴权登录与密码的状态:是否已登录、是否已设置密码,以及密码是否仍为初始值。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/auth/status{
"authenticated": true,
"password_is_initial": false,
"password_set": true
}- password_is_initial=true 表示密码仍是安装时下发的初始密码;这正是要求更换密码的理由。
/api/v1/auth/password需要鉴权修改控制面板密码。需要提供当前密码。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
current_password | string | 是 | 当前密码。🔴 字段名为 current_password,而不是 current。 |
new_password | string | 是 | 新密码,至少 8 个字符。🔴 字段名为 new_password,而不是 new。 |
{ "current_password": "old-password", "new_password": "new-password" }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"current_password":"old-password","new_password":"new-password"}' \
http://127.0.0.1:8891/api/v1/auth/password{
"status": "ok"
}- 🔴 使用 current 与 new 作为字段名时,两者都会被解析为空字符串,接口返回 401 “current password is incorrect”——看上去像是密码错了,实则是字段名错了。
- 新密码过短时返回 400 “password must be at least 8 characters”。
- 若该构建未配置控制面板登录,返回 501 “auth not configured”。
/api/v1/auth/apikey/rotate需要鉴权签发新的 API 密钥并返回。旧密钥立即失效。
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/auth/apikey/rotate{
"api_key": "a1b2c3d4e5f6a7b8c9d0"
}- 该请求使用旧密钥发出,而响应携带新密钥——没有其他途径可以获知它。
- 若无法保存新密钥,返回 500 “could not rotate key”;若未配置登录,返回 501。
系统状态
/api/v1/status需要鉴权返回整体状态:版本、已开启端口数与端口上限(max_ports 为生效上限,即配置上限与许可证上限中的较小值)、身份数量、运行时长等信息。
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/status{
"version": "1.3.2",
"commit": "a1b2c3d",
"commit_time": "2026-09-01T10:00:00Z",
"open_ports": 2,
"max_ports": 1000,
"idle_timeout_seconds": 1800,
"ports": [
"…"
],
"profile_count": 143900,
"profile_counts": {
"chrome_152+windows": 41000,
"chrome_152+macos": 22000,
"firefox_152+windows": 17400,
"safari_18+ios": 9800
},
"uptime": "3d14h22m",
"domain_routing": {
"domains": [],
"proxy": ""
},
"domain_rules_count": 3,
"pack_loaded": true,
"solver_bundle_state": "ready",
"solver_bundle_total": 1,
"vision_bundle_state": "ready",
"vision_bundle_total": 1,
"font_bundle_state": "ready",
"font_bundle_total": 1,
"build_state": "ok",
"device_bound": true
}{
"pack_loaded": true,
"solver_bundle_state": "downloading",
"vision_bundle_state": "dormant",
"font_bundle_state": "failed",
"font_bundle_reason": "macos: connection refused",
"build_state": "mismatch",
"build_reason": "the program file does not match the published build — please reinstall",
"device_bound": true,
"device_rebound_at": "2026-09-01T10:00:00Z"
}- 第一个示例是成功的情况。solver_bundle_state、vision_bundle_state 和 font_bundle_state 各有四种取值:dormant——尚未开始下载(对 vision 而言这是正常的:模型在首次遇到验证码时才下载)、downloading——正在下载、ready——已安装、failed——下载失败。
- 🔴 不要把就绪判断写成“等于 ready,其余都是故障”:全新安装首先返回 downloading,这样的脚本无法区分“仍在下载”和“已失败”。
- 每个状态都有配对的原因字段——solver_bundle_reason、vision_bundle_reason、font_bundle_reason:一段不含机密的简短说明。状态为 ready 或 dormant 时该字段不出现。font_bundle_reason 会列出所有失败的操作系统(macos: connection refused; windows: 404),因为该状态取各操作系统字体池中最差的一个。
- 🔴 vision_bundle_state 为 ready 但 vision_bundle_reason 非空并不代表正常:包已下载,但内容密钥获取失败(许可证没有解算器权限、令牌过旧、无法连接 Cabinet),此时 reCAPTCHA 会静默地始终无法通过。
- pack_loaded 为 false 表示未加载真实的指纹配方;pack_reason 会同时返回原因(not yet attempted、无法连接 Cabinet)。false 且原因为空,表示许可证不包含配方包权限。
- build_state 表示程序文件与授权服务器发布的构建是否一致。取值:ok、mismatch、unregistered。🔴 该字段可能完全不出现在响应中——那表示“尚无信号”,不得当作 ok。为 mismatch 或 unregistered 时,build_reason 会给出可直接展示的说明文本:mismatch——文件被损坏或被篡改,需要重新安装;unregistered——该构建从未由授权服务器发布,重装同一版本无济于事。
- device_bound 为 false 表示该安装未绑定到其设备密钥。device_rebound_at(最近一次重新绑定的时间)只有在发生过重新绑定时才出现。
/api/v1/health无需鉴权一个始终返回 OK 的简单健康检查。
curl http://127.0.0.1:8891/api/v1/health
{
"status": "ok"
}
无需密钥即可访问的路径恰好有四个:本健康检查、POST /api/v1/auth/login、GET /crl(拉取吊销列表的是操作系统的证书校验栈,而不是人)以及 GET /export/{token}/…(地址中的令牌本身即为访问凭据)。其余一律返回 401。监控系统或容器 shell 用健康检查确认进程存活;它不提供端口或许可的任何状态信息。
根证书(CA)
应用使用自有根证书拆解 TLS,系统必须信任该证书——否则浏览器会在每个站点上显示证书错误。三个接口以三种形式提供该证书,第四个负责安装它。
/api/v1/ca需要鉴权以 PEM 文本形式返回根证书。
curl -H "X-API-Key: YOUR_API_KEY" -o blanktrail-ca.pem \
http://127.0.0.1:8891/api/v1/ca- 若未配置证书路径,返回 404 “CA certificate path not configured”;若文件不可读,返回 500 “failed to read CA certificate”。此处不做 PEM 解析——文件按原样返回;“不是 PEM”的拒绝属于需要解析证书的接口,即 /ca.crt 与 /ca.mobileconfig。
/api/v1/ca.crt需要鉴权同一证书的二进制 DER 形式——macOS 与 iOS 的系统安装程序可识别该格式。
curl -H "X-API-Key: YOUR_API_KEY" -o blanktrail-ca.crt \
http://127.0.0.1:8891/api/v1/ca.crt/api/v1/ca.mobileconfig需要鉴权Apple 的 .mobileconfig 配置文件:在设备上打开后会自行安装该证书。
curl -H "X-API-Key: YOUR_API_KEY" -o blanktrail.mobileconfig \
http://127.0.0.1:8891/api/v1/ca.mobileconfig- 在 iPhone 上,仅安装描述文件还不够:还需在“设置 → 通用 → 关于本机 → 证书信任设置”中将该证书标记为受信任。
/api/v1/ca/install需要鉴权把根证书安装到用户的受信任根存储中。
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/ca/install{
"status": "installed"
}- 仅适用于 Windows:在其他系统上返回 501,需手动下载并添加证书。
- 安装后必须完全重启浏览器——关闭所有窗口,而不是只开新窗口:它在启动时读取信任存储。
- 若系统存储拒绝该证书,返回 500 “install failed: …”。
Challenge Breaker
这些接口显示挑战解题器当前的工作情况,以及它被允许占用的机器资源量。任何套餐都可使用:没有 Challenge Breaker 时求解计数保持为零,但仍能看到遇到的验证——由此可了解您的流量遭遇了什么。
/api/v1/solver/stats需要鉴权自启动以来的计数:按验证家族统计的尝试与成功、遇到的验证,以及占用的资源。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/solver/stats{
"families": [ { "family": "recaptcha", "attempts": 41, "solved": 38 } ],
"total_attempts": 41,
"total_solved": 38,
"since_start": true,
"resources": { "live_procs": 2, "busy_procs": 1, "cap": 4,
"constrained": false, "reason": "", "last_error": "",
"launch_failures": 0, "proc_deaths": 0, "mem_recycles": 0 },
"seen": { "total": 47, "since_unix_ms": 1757116800000,
"vendors": [ { "vendor": "recaptcha", "count": 41 },
{ "vendor": "turnstile", "count": 6 } ] }
}- 🔴 在没有 Challenge Breaker 的套餐上,只有 seen 非空:没有求解,但确实遇到了验证。该字段正是为此而设。
/api/v1/solver/queue需要鉴权实时队列:当前等待数与求解中数量、队列上限,以及每个请求一行的明细。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/solver/queue{
"queued": 2,
"running": 1,
"max_len": 16,
"items": [ { "port": 20134, "host": "example.com", "vendor": "recaptcha",
"class": "chrome-152-win", "state": "solving",
"waiters": 1, "age_ms": 4120 } ]
}- 它是独立接口而非 /solver/stats 中的字段:队列的变化速度比计数快几个数量级,面板按自己的节奏轮询它。此处没有队列控制——只读。
/api/v1/solver/procs需要鉴权设置同时运行的解题进程数量。无需重启即可生效,并可跨重启保留。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
procs | int | 是 | 进程数量;0 表示关闭求解。 |
{ "procs": 4 }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"procs":4}' \
http://127.0.0.1:8891/api/v1/solver/procs{
"js_solver_procs": 4
}- 400 “procs must be >= 0”;若请求数量超过许可允许值,返回 409——该上限可在 GET /api/v1/license/status 的响应中以 js_solver_max_procs 查看。
- 未设置该值时按许可上限执行:无需手动分配进程。
设置与密钥
/api/v1/settings/network需要鉴权网络设置:代理端口是否接受来自局域网的连接、是否要求登录,以及证书吊销列表可从哪个地址访问。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/settings/network{
"allow_lan": false,
"crl_public_host": "",
"proxy_auth_enabled": true,
"proxy_auth_user": "proxy"
}- 响应中永远不会返回代理密码——它只能被设置。
/api/v1/settings/network需要鉴权修改网络设置。只需发送要改动的项:请求体中未出现的字段保持原样。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
allow_lan | bool | 否 | 允许代理端口接受来自局域网的连接,而不仅限本机。 |
crl_public_host | string | 否 | 从另一台机器访问证书吊销列表所用的地址:host 或 host:port,不含协议与路径。回环地址会被拒绝——必须是本机在外部可达的地址。 |
proxy_auth_enabled | bool | 否 | 要求代理端口进行用户名与密码验证。 |
proxy_auth_user | string | 否 | 代理用户名。 |
proxy_auth_pass | string | 否 | 代理密码。 |
{ "allow_lan": true, "proxy_auth_enabled": true,
"proxy_auth_user": "proxy", "proxy_auth_pass": "…" }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"allow_lan":true}' \
http://127.0.0.1:8891/api/v1/settings/network{
"allow_lan": true,
"crl_public_host": "",
"proxy_auth_enabled": true,
"proxy_auth_user": "proxy"
}- 400 “proxy_auth_user and proxy_auth_pass are required to enable proxy auth”:没有用户名与密码就无法开启该验证。
- crl_public_host 无效时返回 400 并附说明;503 “auth store not configured”。请求体上限为 8 KiB。
/api/v1/auth/apikey需要鉴权返回 API 密钥——即在 X-API-Key 头中传输的那一个。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/auth/apikey{
"api_key": "a1b2c3d4e5f6a7b8c9d0"
}- 若不存在可取回的密钥副本,响应为空:仅以哈希形式保存的密钥无法显示。
/api/v1/auth/apikey需要鉴权以自定义的 API 密钥替换自动生成的密钥。旧密钥立即失效。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
api_key | string | 是 | 12–128 个可打印 ASCII 字符且不含空格:该密钥会原样出现在请求头中。 |
{ "api_key": "my-own-api-key-2026" }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"api_key":"my-own-api-key-2026"}' \
http://127.0.0.1:8891/api/v1/auth/apikey{
"api_key": "my-own-api-key-2026"
}- 400 “api key must be 12-128 characters” 或 “api key must be printable ASCII without spaces”。请求体上限为 8 KiB。
/api/v1/settings/integration-key需要鉴权报告是否已保存集成密钥——它用于以集成商身份激活许可。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/settings/integration-key{
"integration_key": "",
"set": false
}/api/v1/settings/integration-key需要鉴权保存或清除集成密钥。无需重启即可生效。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
integration_key | string | 是 | 密钥,最长 512 个字符。空值将清除已保存的密钥。 |
{ "integration_key": "…" }curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"integration_key":""}' \
http://127.0.0.1:8891/api/v1/settings/integration-key{
"ok": true
}- 400 “integration_key must be at most 512 characters”;503 “auth store not configured”。
通过代码激活
激活通常在控制面板中完成,但也可以通过请求完成——例如用脚本部署机器时。凭据会直接发送到 Cabinet;应用不会保存它们,只保存已签名的许可。
/api/v1/license/enroll需要鉴权使用 blanktrail.com 账户开始激活。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
email | string | 是 | 账户邮箱。 |
password | string | 是 | 账户密码。 |
{ "email": "you@example.com", "password": "…" }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"…"}' \
http://127.0.0.1:8891/api/v1/license/enroll{
"choose": false,
"activated": true,
"plan": "pro"
}- 若账户下有多个许可,响应会带 choose=true、许可列表以及一次性票据——由下一个接口完成选择。
- 400 “email and password are required”;若 Cabinet 不可达,返回 502 且状态包含在响应体中;503 “license manager not configured”。
/api/v1/license/enroll/confirm需要鉴权当账户下有多个许可时,选择其中一个。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
ticket | string | 是 | 上一步响应中的一次性票据。 |
license_id | int | 是 | 同一响应中所选许可的标识符。 |
{ "ticket": "…", "license_id": 42 }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"ticket":"…","license_id":42}' \
http://127.0.0.1:8891/api/v1/license/enroll/confirm{
"activated": true,
"plan": "pro"
}- 400 “ticket and license_id are required”;若 Cabinet 不可达,返回 502。
/api/v1/auth/onboard-password需要鉴权在首屏设置控制面板密码——凭 POST /api/v1/auth/onboard-activate 响应中返回的一次性令牌 bootstrap_token,而非旧密码。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bootstrap_token | string | 是 | 首次运行的一次性令牌,来自 POST /api/v1/auth/onboard-activate 的响应;仅可使用一次,有效期 15 分钟。 |
new_password | string | 是 | 新密码,至少 8 个字符。 |
{ "bootstrap_token": "…", "new_password": "new-password" }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"bootstrap_token":"…","new_password":"new-password"}' \
http://127.0.0.1:8891/api/v1/auth/onboard-password{
"status": "ok"
}- 401 “invalid or expired activation token”;若密码短于八个字符,返回 400 并附密码规则;若未配置登录,返回 501。
/api/v1/auth/onboard-activate需要鉴权在同一首屏完成许可激活,无需单独登录控制面板。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
email | string | 是 | 账户邮箱。 |
password | string | 是 | 账户密码。 |
ticket | string | 否 | 存在多个许可时的选择票据。 |
license_id | int | 否 | 所选许可的标识符。 |
{ "email": "you@example.com", "password": "…" }curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"…"}' \
http://127.0.0.1:8891/api/v1/auth/onboard-activate{
"activated": true,
"plan": "pro",
"bootstrap_token": "…"
}- bootstrap_token 仅在此响应中返回,且仅当 activated 为 true;一次性,15 分钟后过期,请保存并传给 POST /api/v1/auth/onboard-password。没有其他来源——安装程序不会签发它。
- 400 “email and password are required”;同一地址多次尝试后返回 429;若 Cabinet 不可达,返回 502;503 “license manager not configured”。