API — 配置文件、预设与路由
列出和导入身份、管理预设和域名路由规则,并注册端口所经过的网关。
配置文件
/api/v1/profiles需要鉴权列出已存储的身份,可选分页和浏览器筛选。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
limit | int (query) | 否 | 每页数量:默认 100,最大 1000。超过该值不会报错,而是被静默截断为 1000;实际生效的每页数量见响应中的 limit 字段。若需导出全部数据,请使用 offset 分页,并与 total 对照。 |
offset | int (query) | 否 | 分页偏移量(默认 0)。 |
browser | string (query) | 否 | 按浏览器筛选,例如 "chrome"。 |
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”。
/api/v1/counts需要鉴权按 浏览器+版本+操作系统 的组合返回身份数量分布。该接口不按浏览器系列聚合。
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。
端口的身份
/api/v1/port/{port}/rotate需要鉴权在当前筛选条件范围内,将端口轮换为另一个身份。
curl -H "X-API-Key: YOUR_API_KEY" -X POST http://127.0.0.1:8891/api/v1/port/20134/rotatecurl -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 连接不会被断开。
/api/v1/port/{port}/profile/view需要鉴权返回端口当前所呈现的完整身份。
curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/port/20134/profile/viewcurl -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。这正是“为什么端口的表现与我所要求的不同”的答案。
预设
预设是一组端口连同其设置的保存副本,按文件夹归档。用它可以一次请求即恢复现成的工作布局。
/api/v1/presets需要鉴权已保存预设与文件夹的树形结构。
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 }
]
}/api/v1/presets需要鉴权把已打开端口的配置保存为指定路径下的预设。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path | string | 是 | 预设在树中的路径,例如 parsing/marketplaces。 |
ports | array | 否 | 要保存的端口号。留空表示保存所有已打开的端口。 |
{ "path": "parsing/marketplaces", "ports": [20134, 20135] }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。
/api/v1/presets/load需要鉴权从预设中启动端口。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path | string | 是 | 预设路径。 |
mode | string | 是 | replace 或 merge。其他取值返回 400。 |
{ "path": "parsing/marketplaces", "mode": "merge" }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”。
/api/v1/presets需要鉴权删除预设。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path | string | 是 | 预设路径。 |
{ "path": "parsing/marketplaces" }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”。必须带请求体。
域名路由规则
这些规则按域名拆分单个端口的流量:哪个域名走哪条路径、以何种身份出站。规则是有序的,第一条匹配主机名且已启用的规则生效。
/api/v1/domain_rules需要鉴权返回有序的规则列表。
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 }
}
]
}- 不带前缀的匹配项会命中该域名及其所有子域名;以“=”开头的匹配项只命中该域名本身。
/api/v1/domain_rules需要鉴权整体替换规则列表——需要发送全部规则,而不是其中一条。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
rules | array | 是 | 按生效顺序排列的规则。 |
rules[].name | string | 是 | 规则名称——供人识别。 |
rules[].enabled | bool | 是 | 已禁用的规则在匹配时会被跳过。 |
rules[].matchers | array | 是 | 域名;开头的“=”表示精确匹配。 |
rules[].upstream | string | 否 | 这些域名所使用的出口。 |
rules[].chain_proxy | string | 否 | 链路首跳。 |
rules[].upstream_gateway | string | 否 | 用已保存网关名称替代出口地址。 |
rules[].chain_gateway | string | 否 | 用于首跳的网关名称。 |
rules[].spoof | string | 否 | inherit 沿用端口的身份;custom 使用 spoof_cfg 中的自有身份;off 不做伪装。 |
rules[].spoof_cfg | object | 否 | 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 -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)。
/api/v1/ovpn需要鉴权已保存网关的列表、其隧道状态,以及后端是否可用。
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 字段,说明隧道未能启动的原因。
/api/v1/ovpn需要鉴权添加网关。配置以文本形式放在 content 字段中传递——完整的 .ovpn 或 WireGuard 配置文件内容,或 vless://、trojan://、ss://、vmess://、hysteria2://(等同 hy2://)链接;该接口没有单独的文件上传。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 端口将据以识别该网关的名称。 |
content | string | 是 | 完整的 .ovpn 或 WireGuard 配置文件文本,或 vless://、trojan://、ss://、vmess://、hysteria2://(hy2://)链接。 |
kind | string | 否 | 取值为 openvpn、vless、trojan、shadowsocks、vmess、hysteria2、wireguard 之一。留空则根据内容推断:按链接协议头判断(hy2:// 等同 hysteria2),含 [Interface] 与 [Peer] 段落者判为 wireguard,其余按 openvpn 处理。 |
via | string | 否 | 该网关用于出网的另一个网关名称。 |
{ "name": "eu-demo", "kind": "vless",
"content": "vless://…@203.0.113.77:443?…" }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”。
/api/v1/ovpn/{name}需要鉴权修改已有网关:其内容、via 跳转,或两者。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
content | string | 否 | 新的配置文本。空字符串表示保留原内容。 |
via | string | null | 否 | null 表示保持不变;空字符串表示清除该跳;否则为网关名称。 |
{ "via": "us-demo" }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。
/api/v1/ovpn/{name}需要鉴权删除网关。
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。
/api/v1/gateway/openvpn-status需要鉴权本机是否已安装 OpenVPN;若未安装,则说明在当前系统上如何安装。
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 均为可选字段,值为空时不会出现在响应中。
/api/v1/ovpn/ping需要鉴权测量每个已保存网关的响应时间,并返回结果快照。
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——该接口位于许可之后。
/api/v1/gateway/subs需要鉴权列出订阅:每个订阅产生了多少服务器、包含哪些网关、上次刷新时间,以及上次刷新失败的原因。
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 表示订阅中因不受支持而被跳过的服务器数量。
/api/v1/gateway/subs需要鉴权按名称创建订阅或修改已有订阅。订阅中的服务器会以普通网关的形式出现,可指定为出口或首跳。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 订阅名称:拉丁字母、数字、点、连字符与下划线,最长 64 个字符。 |
source | string | 否 | 订阅链接。创建时必填;修改时省略即可保留原链接。 |
enabled | bool | 否 | 是否按计划刷新该订阅。 |
interval_min | int | 否 | 刷新周期(分钟)。 |
{ "name": "demo-sub", "source": "https://example.com/sub/demo",
"enabled": true, "interval_min": 60 }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 返回的是缩略形式——协议与主机,路径和查询参数以省略号代替。
/api/v1/gateway/subs/{name}/refresh需要鉴权立即刷新某个订阅,无需等待计划时间。
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": []
}
}{
"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”。
/api/v1/gateway/subs/{name}需要鉴权删除订阅及其创建的网关——仍被引用的网关除外。
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。
预设文件夹
预设按文件夹归档,而文件夹并非摆设:预设是作为整组端口加载的,把一组放在一起更方便。
/api/v1/presets/folder需要鉴权创建文件夹。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path | string | 是 | 文件夹在树中的路径。 |
{ "path": "parsing" }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 并附说明。
/api/v1/presets/folder需要鉴权删除文件夹及其中的全部内容。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path | string | 是 | 文件夹路径。 |
{ "path": "parsing" }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。
/api/v1/presets/move需要鉴权把预设或文件夹移动到树中的其他位置。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
from | string | 是 | 要移动的对象。 |
to | string | 是 | 目标位置。 |
{ "from": "daily-crawl", "to": "parsing/daily-crawl" }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”。
配置文件与指纹
从真实浏览器采集到的指纹可以被解析、查看并以名称保存——之后即可像普通配置文件那样选用。
/api/v1/fingerprint/parse需要鉴权解析已采集的指纹并展示其构成,但不保存任何内容。请求体是采集服务原样返回的完整原始 JSON。
{ "tls": { "ja3": "771,4865-4866-…", "ja4": "t13d1516h2_…" },
"http2": { "akamai_fingerprint": "1:65536;…" },
"user_agent": "Mozilla/5.0 …" }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 同样是对象而不是字符串。
/api/v1/profiles/import需要鉴权以某个名称把单个指纹保存到配置文件库中——此后即可通过 mode=specific 按该名称选用它。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 保存所用的名称。 |
source_json | string | 否 | 以字符串形式提供的已采集指纹,即采集服务返回的原文。 |
custom_tls | object | 否 | 已解析的指纹——即 /fingerprint/parse 的返回结果。 |
{ "name": "chrome_152_captured",
"source_json": "{\"tls\": … }" }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。
/api/v1/scraper/tasks/{id}/profile/view需要鉴权显示端口池任务所使用的配置文件:与实际出站指纹的构成完全一致。
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。