API — 配置文件、预设与路由

列出和导入身份、管理预设和域名路由规则,并注册端口所经过的网关。

配置文件

GET/api/v1/profiles需要鉴权

列出已存储的身份,可选分页和浏览器筛选。

参数类型必填说明
limitint (query)否每页数量:默认 100,最大 1000。超过该值不会报错,而是被静默截断为 1000;实际生效的每页数量见响应中的 limit 字段。若需导出全部数据,请使用 offset 分页,并与 total 对照。
offsetint (query)否分页偏移量(默认 0)。
browserstring (query)否按浏览器筛选,例如 "chrome"。
示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" "http://127.0.0.1:8891/api/v1/profiles?browser=chrome&limit=50"
响应
{
  "profiles": [
    { "id": 8412, "name": "chrome_152_windows", "browser": "chrome",
      "version": "152", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) …",
      "created_at": "2026-08-20T12:00:00Z" }
  ],
  "total": 143900,
  "limit": 50,
  "offset": 0
}

total 表示符合过滤条件的配置文件总数,而不是本页返回的数量。浏览器取值未知时返回 400 “browser must be one of: chrome, firefox, safari, edge”。

GET/api/v1/counts需要鉴权

按 浏览器+版本+操作系统 的组合返回身份数量分布。该接口不按浏览器系列聚合。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/counts
响应
{
  "chrome_152+windows": 41000,
  "chrome_152+macos": 22000,
  "firefox_152+windows": 17400,
  "safari_18+ios": 9800
}

键的形式为 "browser_version+os":浏览器名称为小写(chrome、firefox、safari、edge),随后是下划线、版本号、加号和操作系统(windows、macos、linux、android、ios)。若配置文件未记录操作系统,键形如 "chrome_152+",加号后为空。响应中不会出现 "Chrome" 这样的键:如需按系列汇总,请自行求和。这些计数与 GET /api/v1/status 响应中的 profile_counts 字段相同,其总和等于同一响应中的 profile_count。

端口的身份

POST/api/v1/port/{port}/rotate需要鉴权

在当前筛选条件范围内,将端口轮换为另一个身份。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" -X POST http://127.0.0.1:8891/api/v1/port/20134/rotate
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/rotate
响应
{
  "name": "firefox_152_macos",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) …",
  "browser": "firefox",
  "os": "macos"
}

若引擎无可签发的配置文件(配置库为空或被过滤为零),返回 500 “no profile available”。新身份从下一个连接开始生效——已建立的 keep-alive 连接不会被断开。

GET/api/v1/port/{port}/profile/view需要鉴权

返回端口当前所呈现的完整身份。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/port/20134/profile/view
示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/profile/view
响应
{
  "name": "chrome_152_windows",
  "browser": "chrome",
  "os": "windows",
  "version": 152,
  "user_agent": "Mozilla/5.0 …",
  "tls": {
    "available": true,
    "cipher_suites": ["TLS_AES_128_GCM_SHA256", "…"],
    "extensions": ["server_name", "…"],
    "curves": ["X25519MLKEM768", "…"],
    "alpn": ["h2", "http/1.1"],
    "ja3": "771,4865-4866-…",
    "ja3_hash": "cd08e31494f9531f560d64c695473da9",
    "ja3_note": "…"
  },
  "h2": { "settings": ["HEADER_TABLE_SIZE=65536", "…"] },
  "spec_source": "spec"
}

spec_source 说明该形态来自何处:preset——预置集合;spec——按规格构建;factory——回退构建;unavailable——无法构建,此时 tls.available=false。这正是“为什么端口的表现与我所要求的不同”的答案。

预设

预设是一组端口连同其设置的保存副本,按文件夹归档。用它可以一次请求即恢复现成的工作布局。

GET/api/v1/presets需要鉴权

已保存预设与文件夹的树形结构。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/presets
响应
{
  "name": "",
  "path": "",
  "is_folder": true,
  "children": [
    { "name": "parsing", "path": "parsing", "is_folder": true,
      "children": [ { "name": "marketplaces", "path": "parsing/marketplaces",
                      "is_folder": false } ] },
    { "name": "daily-crawl", "path": "daily-crawl", "is_folder": false }
  ]
}
POST/api/v1/presets需要鉴权

把已打开端口的配置保存为指定路径下的预设。

参数类型必填说明
pathstring是预设在树中的路径,例如 parsing/marketplaces。
portsarray否要保存的端口号。留空表示保存所有已打开的端口。
请求体
{ "path": "parsing/marketplaces", "ports": [20134, 20135] }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"parsing/marketplaces","ports":[20134,20135]}' \
  http://127.0.0.1:8891/api/v1/presets
响应
{
  "status": "saved",
  "path": "parsing/marketplaces"
}
  • 400 “path is required”;若列表中包含未打开的端口,返回 400 “port N is not open”;若路径越出预设存储范围,返回 400 “invalid path …”、“invalid path segment …” 或 “path escapes root”。仅当文件系统本身拒绝权限时才会返回 403。
POST/api/v1/presets/load需要鉴权

从预设中启动端口。

参数类型必填说明
pathstring是预设路径。
modestring是replace 或 merge。其他取值返回 400。
请求体
{ "path": "parsing/marketplaces", "mode": "merge" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"parsing/marketplaces","mode":"merge"}' \
  http://127.0.0.1:8891/api/v1/presets/load
响应
{
  "results": [
    { "port": 20134, "status": "opened" },
    { "port": 20135, "status": "failed", "error": "port 20135 is already in use" }
  ]
}
  • 🔴 mode=replace 会在启动预设端口之前关闭所有已打开的端口——经由它们的流量会被切断。mode=merge 只关闭预设中列出的端口号。
  • 响应为逐端口的结果:预设可能是很久以前保存的,部分端口可能无法启动。若保存的配置把 mode=random 与过滤条件组合在一起,此处会像普通打开时一样被拒绝。
  • 400 “path is required”、400 “mode must be replace or merge”、404 “preset not found”。
DELETE/api/v1/presets需要鉴权

删除预设。

参数类型必填说明
pathstring是预设路径。
请求体
{ "path": "parsing/marketplaces" }
示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"parsing/marketplaces"}' \
  http://127.0.0.1:8891/api/v1/presets
响应
{
  "status": "deleted"
}
  • 400 “path is required”;404 “preset not found”。必须带请求体。

域名路由规则

这些规则按域名拆分单个端口的流量:哪个域名走哪条路径、以何种身份出站。规则是有序的,第一条匹配主机名且已启用的规则生效。

GET/api/v1/domain_rules需要鉴权

返回有序的规则列表。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/domain_rules
响应
{
  "rules": [
    {
      "id": "r1",
      "name": "catalogue",
      "enabled": true,
      "matchers": ["example.com", "=shop.example.net"],
      "upstream": "socks5://203.0.113.10:1080",
      "chain_proxy": "",
      "upstream_gateway": "",
      "chain_gateway": "",
      "spoof": "inherit",
      "spoof_cfg": { "mode": "", "browser": "", "os": "",
                     "spoof_headers": null, "h2_spoofing": null }
    }
  ]
}
  • 不带前缀的匹配项会命中该域名及其所有子域名;以“=”开头的匹配项只命中该域名本身。
PUT/api/v1/domain_rules需要鉴权

整体替换规则列表——需要发送全部规则,而不是其中一条。

参数类型必填说明
rulesarray是按生效顺序排列的规则。
rules[].namestring是规则名称——供人识别。
rules[].enabledbool是已禁用的规则在匹配时会被跳过。
rules[].matchersarray是域名;开头的“=”表示精确匹配。
rules[].upstreamstring否这些域名所使用的出口。
rules[].chain_proxystring否链路首跳。
rules[].upstream_gatewaystring否用已保存网关名称替代出口地址。
rules[].chain_gatewaystring否用于首跳的网关名称。
rules[].spoofstring否inherit 沿用端口的身份;custom 使用 spoof_cfg 中的自有身份;off 不做伪装。
rules[].spoof_cfgobject否spoof=custom 时的自有身份:mode、browser、os、profile、spoof_headers、h2_spoofing。
请求体
{ "rules": [ { "name": "catalogue", "enabled": true,
                "matchers": ["example.com"],
                "upstream": "socks5://203.0.113.10:1080",
                "spoof": "inherit" } ] }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"rules":[{"name":"catalogue","enabled":true,"matchers":["example.com"],"upstream":"socks5://203.0.113.10:1080","spoof":"inherit"}]}' \
  http://127.0.0.1:8891/api/v1/domain_rules
响应
{
  "rules": [ { "id": "r1", "name": "catalogue", "enabled": true,
               "matchers": ["example.com"],
               "upstream": "socks5://203.0.113.10:1080", "spoof": "inherit" } ]
}
  • 若规则格式有误(例如引用了不存在的网关),返回 400 并附说明。响应返回已保存的列表,并附带分配的 id。

网关(OpenVPN、VLESS、VMess、Trojan、Shadowsocks、Hysteria2、WireGuard)

网关是保存下来的隧道配置,它在本机启动并提供本地 SOCKS5。之后可按名称(而非地址)把它指定为端口的出口(upstream_gateway)或链路首跳(chain_gateway)。

GET/api/v1/ovpn需要鉴权

已保存网关的列表、其隧道状态,以及后端是否可用。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/ovpn
响应
{
  "configs": [
    {
      "name": "eu-demo",
      "kind": "openvpn",
      "size": 4821,
      "remote": "203.0.113.77:1194",
      "via": "",
      "uploaded_at": "2026-08-20T12:00:00Z",
      "tunnel": { "config": "eu-demo", "status": "up", "ports": 2, "socks_addr": "127.0.0.1:41675" },
      "ping": { "ms": 38, "at": "2026-09-04T09:41:12Z" }
    }
  ],
  "available": true
}
  • available=false 表示主机上既没有 OpenVPN 也没有 Xray;此时会同时返回 reason。via 字段指明该网关经由哪个网关出网——链路也可以在这里构建。
  • 只有已经启动过的网关才会返回 tunnel 对象,其状态位于 status 字段——up、connecting 或 error。没有 state 字段,该接口也完全不返回隧道的启动时间。同时还会返回 ports(当前占用该隧道的端口数)、socks_addr(该隧道的本地 SOCKS5)和 config(网关名称);当 status=error 时会返回 error 字段,说明隧道未能启动的原因。
POST/api/v1/ovpn需要鉴权

添加网关。配置以文本形式放在 content 字段中传递——完整的 .ovpn 或 WireGuard 配置文件内容,或 vless://、trojan://、ss://、vmess://、hysteria2://(等同 hy2://)链接;该接口没有单独的文件上传。

参数类型必填说明
namestring是端口将据以识别该网关的名称。
contentstring是完整的 .ovpn 或 WireGuard 配置文件文本,或 vless://、trojan://、ss://、vmess://、hysteria2://(hy2://)链接。
kindstring否取值为 openvpn、vless、trojan、shadowsocks、vmess、hysteria2、wireguard 之一。留空则根据内容推断:按链接协议头判断(hy2:// 等同 hysteria2),含 [Interface] 与 [Peer] 段落者判为 wireguard,其余按 openvpn 处理。
viastring否该网关用于出网的另一个网关名称。
请求体
{ "name": "eu-demo", "kind": "vless",
  "content": "vless://…@203.0.113.77:443?…" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d "{\"name\":\"eu-demo\",\"content\":\"$(cat eu-demo.ovpn | sed 's/\"/\\\\"/g')\"}" \
  http://127.0.0.1:8891/api/v1/ovpn
响应
{
  "status": "saved",
  "name": "eu-demo",
  "kind": "vless"
}
  • 400 “name is required”;400 “content is required (the .ovpn text or a vless:// link)”;kind 取值未知时返回 400 “unknown gateway kind …”。
  • 若网关链会形成自环,返回 400 且 code 为 via_cycle——该代码与文本一同返回,便于界面区分此原因与其他原因。
  • 在未包含网关的构建中返回 501 “gateway config manager is not enabled”。
PUT/api/v1/ovpn/{name}需要鉴权

修改已有网关:其内容、via 跳转,或两者。

参数类型必填说明
contentstring否新的配置文本。空字符串表示保留原内容。
viastring | null否null 表示保持不变;空字符串表示清除该跳;否则为网关名称。
请求体
{ "via": "us-demo" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"via":"us-demo"}' \
  http://127.0.0.1:8891/api/v1/ovpn/eu-demo
响应
{
  "status": "updated",
  "name": "eu-demo",
  "kind": "vless"
}
  • 404 “config "…" not found”;若链路形成自环,返回 400 且 code 为 via_cycle。
DELETE/api/v1/ovpn/{name}需要鉴权

删除网关。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/ovpn/eu-demo
响应
{
  "status": "deleted",
  "name": "eu-demo"
}
  • 若该网关已分配给运行中的端口,返回 409 且 code 为 in_use;若有其他网关经由它出网,返回 400 且 code 为 via_referenced;若网关不存在,返回 404。
GET/api/v1/gateway/openvpn-status需要鉴权

本机是否已安装 OpenVPN;若未安装,则说明在当前系统上如何安装。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/gateway/openvpn-status
响应
{
  "os": "windows",
  "available": false,
  "reason": "openvpn executable not found in PATH",
  "install": {
    "title": "Install OpenVPN Community for Windows",
    "download_url": "https://openvpn.net/community-downloads/",
    "steps": ["…"],
    "note": "…"
  }
}
  • install 字段仅在 available=false 时出现。该检查上限为三秒。
  • install 内部:title 为标题,steps 为安装步骤,download_url 为下载链接(字段名是 download_url,不是 url),note 为可选补充说明。在 linux 与 macOS 上还会返回 command,即可直接执行的一行安装命令,例如 brew install openvpn。download_url、command、note 均为可选字段,值为空时不会出现在响应中。
POST/api/v1/ovpn/ping需要鉴权

测量每个已保存网关的响应时间,并返回结果快照。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/ovpn/ping
响应
{
  "results": {
    "eu-demo": { "ms": 38, "at": "2026-09-04T09:41:12Z" },
    "us-demo": { "ms": 0, "at": "2026-09-04T09:41:12Z", "error": "timeout" }
  }
}
  • 测量同时也按计划执行,因此响应中可能包含较早的数值:每个结果都带有采集时间。
  • 501 “gateway ping is not enabled”;许可未激活时返回 403——该接口位于许可之后。
GET/api/v1/gateway/subs需要鉴权

列出订阅:每个订阅产生了多少服务器、包含哪些网关、上次刷新时间,以及上次刷新失败的原因。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/gateway/subs
响应
{
  "subscriptions": [
    {
      "name": "demo-sub",
      "source": "https://example.com/…",
      "enabled": true,
      "interval_min": 60,
      "last_ok": "2026-09-04T08:00:00Z",
      "servers": 3,
      "gateways": ["demo-sub.eu-demo", "demo-sub.us-demo", "demo-sub.asia-demo"],
      "skipped": 0
    }
  ]
}
  • source 返回时已做脱敏:仅保留协议与主机,路径替换为“/…”,查询串替换为“?…”。订阅密钥就在路径中,因此该值并非可用链接,请勿将其保存为订阅地址。
  • 订阅网关名称的形式为“订阅名.服务器名”(例如 demo-sub.DE-Germaniya),后半部分取自服务器备注。名称中不允许出现冒号;控制面板中的“gw:”前缀只是路由行的显示样式,调用 API 时不要带上。
  • skipped 表示订阅中因不受支持而被跳过的服务器数量。
POST/api/v1/gateway/subs需要鉴权

按名称创建订阅或修改已有订阅。订阅中的服务器会以普通网关的形式出现,可指定为出口或首跳。

参数类型必填说明
namestring是订阅名称:拉丁字母、数字、点、连字符与下划线,最长 64 个字符。
sourcestring否订阅链接。创建时必填;修改时省略即可保留原链接。
enabledbool否是否按计划刷新该订阅。
interval_minint否刷新周期(分钟)。
请求体
{ "name": "demo-sub", "source": "https://example.com/sub/demo",
  "enabled": true, "interval_min": 60 }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"demo-sub","source":"https://example.com/sub/demo","interval_min":60}' \
  http://127.0.0.1:8891/api/v1/gateway/subs
响应
{
  "subscription": {
    "name": "demo-sub",
    "source": "https://example.com/…",
    "enabled": true,
    "interval_min": 60,
    "last_ok": "2026-09-04T08:00:00Z",
    "servers": 3,
    "gateways": ["demo-sub.eu-demo", "demo-sub.us-demo", "demo-sub.asia-demo"],
    "skipped": 0
  },
  "result": {
    "added": 3, "updated": 0, "kept": 0,
    "removed": 0, "retained": 0,
    "skipped": 0, "unsupported": []
  }
}
  • 顶层没有 status 与 name 字段:整条记录都在 subscription 中返回,其形状与 GET /api/v1/gateway/subs 列表中的元素相同。
  • 订阅会在本次请求中立即刷新,最长 60 秒:因此其服务器会立刻出现,而不必等待计划中的第一次刷新。响应可能需要稍等。
  • 🔴 刷新失败并不等于保存失败:状态码仍为 200,只是返回 refresh_error(错误文本)而不是 result,记录已写入磁盘并会重试。客户端必须检查 refresh_error:否则会把不可用的订阅当作创建成功。
  • result 为本次刷新的结果:added、updated、kept、removed、retained、skipped 以及 unsupported(形如“协议×数量”的列表)。
  • 订阅链接不会以明文返回:source 返回的是缩略形式——协议与主机,路径和查询参数以省略号代替。
POST/api/v1/gateway/subs/{name}/refresh需要鉴权

立即刷新某个订阅,无需等待计划时间。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/gateway/subs/demo-sub/refresh
响应
{
  "subscription": {
    "name": "demo-sub",
    "source": "https://example.com/…",
    "enabled": true,
    "interval_min": 60,
    "last_ok": "2026-09-04T08:00:00Z",
    "servers": 3,
    "gateways": ["demo-sub.eu-demo", "demo-sub.us-demo", "demo-sub.asia-demo"],
    "skipped": 0
  },
  "result": {
    "added": 1, "updated": 0, "kept": 2,
    "removed": 0, "retained": 0,
    "skipped": 0, "unsupported": []
  }
}
刷新失败时的响应(同样是 200)
{
  "subscription": { "name": "demo-sub", "servers": 3, "…": "…" },
  "refresh_error": "刷新失败的错误文本"
}
  • 响应顶层没有 status 和 name 字段。名称、服务器数量和网关列表都在 subscription 对象里,它与 GET /api/v1/gateway/subs 返回的对象相同,其中 source 已脱敏,只保留协议和主机。
  • result 是本次同步的汇总:added、updated、kept、removed、retained、skipped、unsupported。result 里的 skipped 指本次同步,subscription 里的 skipped 指订阅当前状态。
  • 刷新失败返回 200 并带 refresh_error 字段,而不是 HTTP 错误:订阅记录仍保留在磁盘上,并会按计划继续重试。请以是否存在 result、是否缺少 refresh_error 判断成功,而不要依据状态码。
  • 许可未激活时返回 403;若不存在该名称的订阅,返回 404;若订阅调度器未启用,返回 501 “gateway subscriptions are not enabled”。
DELETE/api/v1/gateway/subs/{name}需要鉴权

删除订阅及其创建的网关——仍被引用的网关除外。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/gateway/subs/demo-sub
响应
{
  "status": "deleted",
  "removed": ["demo-sub.eu-demo", "demo-sub.us-demo"],
  "retained": ["demo-sub.asia-demo"]
}
  • 响应中没有订阅名称,而是两个网关列表:removed 表示已删除的网关,retained 表示保留下来的网关——这是了解哪些网关幸存的唯一途径。
  • 🔴 订阅本身总会被删除;该接口不存在“端口占用”式的拒绝。被运行端口或已启用的域名路由规则引用的网关会进入 retained:它作为普通网关保留下来,但不再归属于任何订阅,也不会再被刷新。若希望网关随订阅一并删除,请在删除之前释放端口。
  • 若不存在该名称的订阅,返回 404;若网关存储未启用,返回 501。

预设文件夹

预设按文件夹归档,而文件夹并非摆设:预设是作为整组端口加载的,把一组放在一起更方便。

POST/api/v1/presets/folder需要鉴权

创建文件夹。

参数类型必填说明
pathstring是文件夹在树中的路径。
请求体
{ "path": "parsing" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"parsing"}' \
  http://127.0.0.1:8891/api/v1/presets/folder
响应
{
  "status": "created",
  "path": "parsing"
}
  • 400 “path is required”;若路径格式有误,返回 400 并附说明。
DELETE/api/v1/presets/folder需要鉴权

删除文件夹及其中的全部内容。

参数类型必填说明
pathstring是文件夹路径。
请求体
{ "path": "parsing" }
示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"parsing"}' \
  http://127.0.0.1:8891/api/v1/presets/folder
响应
{
  "status": "deleted",
  "path": "parsing"
}
  • 400 “path is required”;404 “folder not found”;若路径越出预设存储范围,返回 400 “invalid path …”、“invalid path segment …” 或 “path escapes root”。仅当文件系统本身拒绝权限时才会返回 403。
POST/api/v1/presets/move需要鉴权

把预设或文件夹移动到树中的其他位置。

参数类型必填说明
fromstring是要移动的对象。
tostring是目标位置。
请求体
{ "from": "daily-crawl", "to": "parsing/daily-crawl" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"from":"daily-crawl","to":"parsing/daily-crawl"}' \
  http://127.0.0.1:8891/api/v1/presets/move
响应
{
  "status": "moved",
  "from": "daily-crawl",
  "to": "parsing/daily-crawl"
}
  • 400 “from and to are required”;404 “source not found”;409 “destination already exists”。

配置文件与指纹

从真实浏览器采集到的指纹可以被解析、查看并以名称保存——之后即可像普通配置文件那样选用。

POST/api/v1/fingerprint/parse需要鉴权

解析已采集的指纹并展示其构成,但不保存任何内容。请求体是采集服务原样返回的完整原始 JSON。

请求体
{ "tls": { "ja3": "771,4865-4866-…", "ja4": "t13d1516h2_…" },
  "http2": { "akamai_fingerprint": "1:65536;…" },
  "user_agent": "Mozilla/5.0 …" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  --data-binary @captured.json \
  http://127.0.0.1:8891/api/v1/fingerprint/parse
响应
{
  "custom_tls": { "ja3": "…", "ja4": "…", "ciphers": ["…"], "extensions": [{"name": "server_name (0)"},
                    {"name": "application_layer_protocol_negotiation (16)", "protocols": ["h2", "http/1.1"]}],
                  "alpn": ["h2", "http/1.1"], "userAgent": "Mozilla/5.0 …" },
  "summary": { "ja3_hash": "…", "ja4": "…", "user_agent": "Mozilla/5.0 …",
                "browser": "chrome", "ciphers": 16, "extensions": 15 }
}
  • custom_tls 可直接作为 PUT /api/v1/port/{port}/custom_tls 的请求体:解析、查看、应用。
  • 支持 tls.peet.ws /api/all 与 ChromeApi /tls 两种格式。请求体上限为 1 MiB。若解析失败,返回 400 并附说明。
  • custom_tls.extensions 是对象列表:每个元素必有 name,另有可选的 supported_groups、signature_algorithms、versions、protocols。它与 /profile/view 响应中的 extensions 不是同一个字段——那里的元素是字符串。summary 同样是对象而不是字符串。
POST/api/v1/profiles/import需要鉴权

以某个名称把单个指纹保存到配置文件库中——此后即可通过 mode=specific 按该名称选用它。

参数类型必填说明
namestring是保存所用的名称。
source_jsonstring否以字符串形式提供的已采集指纹,即采集服务返回的原文。
custom_tlsobject否已解析的指纹——即 /fingerprint/parse 的返回结果。
请求体
{ "name": "chrome_152_captured",
  "source_json": "{\"tls\": … }" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"chrome_152_captured","custom_tls":{ … }}' \
  http://127.0.0.1:8891/api/v1/profiles/import
响应
{
  "name": "chrome_152_captured",
  "summary": { "ja3_hash": "…", "ja4": "…", "user_agent": "Mozilla/5.0 …",
                "browser": "chrome", "ciphers": 16, "extensions": 15 }
}
  • source_json 与 custom_tls 必须提供其一:都缺失时返回 400 “custom_tls or source_json required”。未提供名称时返回 400 “name is required”。
  • 若同名配置文件已存在,返回 409。请求体上限为 1 MiB。
GET/api/v1/scraper/tasks/{id}/profile/view需要鉴权

显示端口池任务所使用的配置文件:与实际出站指纹的构成完全一致。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/scraper/tasks/TASK_ID/profile/view
响应
{
  "port": 20134,
  "profile": { "name": "chrome_152_windows", "browser": "chrome",
                "os": "windows", "tls": { "ja3_hash": "…" }, "spec_source": "spec" }
}

port 指明检查的是端口池中的哪个端口:池中端口众多,每个都有自己的配置文件。409 “scraper task has no open ports yet” 与 “scraper task ports are not live”;若端口池不存在,返回 404。