AutoTeam-F / docs /api.md
ZRainbow's picture
fix: reduce rotation probe interference
be34853
|
Raw
History Blame Contribute Delete
13 kB
# HTTP API 文档
启动后访问 `http://localhost:8787/docs` 查看 Swagger 交互式文档。
所有 `/api/*` 端点需要:
```text
Authorization: Bearer <API_KEY>
```
但以下接口例外:
- `/api/auth/check`
- `/api/setup/status`
- `/api/setup/save`
- `/api/version`
- `/api/setup/dns/check`(setup 阶段免鉴权;`API_KEY` 已配置时仍要求 Bearer,只读查询)
- `/api/mail-provider/probe`(setup 阶段免鉴权;`API_KEY` 已配置时仍要求 Bearer,见下文)
## 即时返回接口
这些接口直接返回结果,不创建后台任务。
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/auth/check` | 验证 API Key |
| GET | `/api/setup/status` | 检查配置是否完整(按 `MAIL_PROVIDER` 动态切换 `optional`) |
| POST | `/api/setup/save` | 保存初始配置(provider 互斥写盘) |
| POST | `/api/setup/dns/check` | 只读 DNS 诊断(A/AAAA/CNAME/MX/TXT,不会写 Cloudflare 或 DNS 服务商) |
| POST | `/api/mail-provider/probe` | 邮箱后端 3 步探测(fingerprint / credentials / domain_ownership) |
| GET | `/api/version` | 镜像版本指纹(`git_sha` + `build_time`,免鉴权,用于排查 docker 镜像是否过期) |
| GET | `/api/status` | 账号状态 + 实时额度 |
| GET | `/api/status?fast=true` | 快速状态快照(跳过实时额度探测,适合前端轮询和轮换任务运行时刷新) |
| GET | `/api/accounts` | 所有账号列表 |
| GET | `/api/accounts/active` | 活跃账号 |
| GET | `/api/accounts/standby` | 待命账号 |
| GET | `/api/team/members` | Team 全部成员(含外部成员与邀请) |
| POST | `/api/team/members/remove` | 移出成员 / 取消邀请 |
| GET | `/api/logs` | 最近日志(支持 `?limit=100&since=0`) |
| GET | `/api/cpa/files` | CPA 认证文件列表 |
| GET | `/api/config/auto-check` | 巡检配置 |
| PUT | `/api/config/auto-check` | 修改巡检配置(运行时生效) |
| POST | `/api/sync` | 同步 active 认证文件到 CPA |
| POST | `/api/sync/from-cpa` | 从 CPA 反向同步认证文件到本地(含去重) |
| POST | `/api/sync/accounts` | 从 Team / auths 对账到本地账号池 |
| POST | `/api/accounts/{email}/kick` | 将 active 账号移出 Team |
| DELETE | `/api/accounts/{email}` | 删除本地管理账号及其资源 |
### Team 成员移除
`POST /api/team/members/remove`
请求体:
```json
{
"email": "user@example.com",
"user_id": "123",
"type": "member"
}
```
- `type = member`:从 Team 中移出
- `type = invite`:取消邀请
## 后台任务接口
这些接口返回 `202 Accepted + task_id`。
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/tasks/rotate` | 智能轮转 `{"target": 3}` |
| POST | `/api/tasks/check` | 检查额度,`{"include_standby": false}` 追加探测 standby 池(限速 1.5s/号 + 24h 去重) |
| POST | `/api/tasks/add` | 自动注册并添加新账号 |
| POST | `/api/tasks/fill` | 补满成员 `{"target": 3}` |
| POST | `/api/tasks/multi-master/fill` | 多 Team 母号并行补位 `{"target": 3, "owner_workers": 2, "direct_parallel": 1, "workspace_ids": null, "dry_run": false}` |
| POST | `/api/tasks/cleanup` | 清理成员 `{"max_seats": null}` |
| GET | `/api/tasks` | 任务列表 |
| GET | `/api/tasks/{task_id}` | 任务详情 |
> 同一时间只允许一个 Playwright 操作;如果有任务执行中,新请求可能返回 `409 Conflict`。
### 多 Team 母号并行补位
`POST /api/tasks/multi-master/fill` 在一个全局后台任务内部调度多个已导入的 Team owner。每个 Team 仍保持 `1 owner + 2 managed children = 3 seats`,并行只发生在 owner worker 维度,不会提高单 Team seat cap。
请求体:
```json
{
"target": 3,
"owner_workers": 2,
"direct_parallel": 1,
"workspace_ids": ["ws-..."],
"dry_run": false
}
```
- `target` 会按现有 Team 上限 clamp 到 `1..3`。
- `owner_workers` 会受 `MULTI_MASTER_MAX_OWNER_WORKERS` 和 `MULTI_MASTER_BROWSER_BUDGET` 裁剪。
- `direct_parallel` 是单 owner direct signup race 的预算参数;当前切片先用于预算和任务可观测,直接注册 race 逻辑仍必须在 `manager.py` 中安全接入后才会改变单账号注册行为。
- `workspace_ids` 可填 workspace id、owner account id 或 owner email;为空时使用所有 `parallel=true` 且 `enabled=true` 的 owner,若没有 parallel owner 则回退当前 active workspace。
- `dry_run=true` 不创建后台任务,直接返回 plan,便于确认 owner 列表和预算。
`GET /api/status` 会额外返回 `multi_master` 字段,包含 aggregate summary 与 per-owner diagnostics。该字段不会回显 `session_token`。
## 管理员运维
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/admin/reconcile?dry_run=0` | 对账修复:扫描 workspace 实际成员 vs 本地 `accounts.json`,识别**残废 / 错位 / 耗尽未抛弃 / ghost / over-cap**五类异常并按 `RECONCILE_KICK_ORPHAN` / `RECONCILE_KICK_GHOST` 决定 KICK 或打标记。`dry_run=1` 仅预测不动账户(包含第二轮 over-cap 预测),返回结构化诊断 dict(`kicked` / `orphan_kicked` / `orphan_marked` / `misaligned_fixed` / `exhausted_marked` / `ghost_kicked` / `ghost_seen` / `over_cap_kicked` / `flipped_to_active`) |
## 管理员登录
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/admin/status` | 管理员状态 |
| POST | `/api/admin/login/start` | 开始登录 `{"email": "admin@example.com"}` |
| POST | `/api/admin/login/session` | 手动导入 session_token `{"email": "admin@example.com", "session_token": "..."}` |
| POST | `/api/admin/login/password` | 提交密码 `{"password": "..."}` |
| POST | `/api/admin/login/code` | 提交验证码 `{"code": "123456"}` |
| POST | `/api/admin/login/workspace` | 选择组织 `{"option_id": "0"}` |
| POST | `/api/admin/login/cancel` | 取消登录 |
| POST | `/api/admin/logout` | 清除登录态 |
## 主号 Codex 同步
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/main-codex/status` | 登录/同步状态,包含 `action` |
| POST | `/api/main-codex/start` | 开始登录并同步到已启用的 CPA/Sub2API 目标;未启用目标时返回 `400` |
| POST | `/api/main-codex/login` | 只登录并保存本地主号 Codex 认证文件,不同步远端 |
| POST | `/api/main-codex/password` | 提交密码 |
| POST | `/api/main-codex/code` | 提交验证码 |
| POST | `/api/main-codex/cancel` | 取消同步 |
| POST | `/api/main-codex/delete-remote-files` | 删除已启用远端中的主号 Codex 认证文件 |
| POST | `/api/main-codex/delete-cpa` | 兼容旧接口:同 `/api/main-codex/delete-remote-files` |
## 手动 OAuth 导入
后端先生成 Codex OAuth 链接,并尝试在 `localhost:1455` 自动接收回调;如果自动回调不可用,也可以手动提交回调 URL。
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/manual-account/status` | 当前手动 OAuth 状态 |
| POST | `/api/manual-account/start` | 开始流程,返回 `auth_url` 与状态信息 |
| POST | `/api/manual-account/callback` | 提交回调 URL |
| POST | `/api/manual-account/cancel` | 取消流程 |
### `/api/manual-account/status` 关键字段
| 字段 | 说明 |
|------|------|
| `status` | `idle / pending_callback / completed / error` |
| `auth_url` | 当前 OAuth 链接 |
| `callback_received` | 是否已收到回调 |
| `callback_source` | `auto` 或 `manual` |
| `auto_callback_available` | 本地自动回调服务是否启动成功 |
| `account` | 完成后导入的账号信息 |
## 初始配置 API
### `POST /api/setup/dns/check`
只读 DNS 诊断端点,用于检查邮箱域名、OpenAI 域名验证 TXT、SPF、MX 等记录是否已经在公网 DNS 生效。该端点只通过公共 DNS-over-HTTPS 查询,不会读取 Cloudflare token,不会调用 DNS 服务商写接口,也不会创建、更新或删除记录。
鉴权策略与 `/api/mail-provider/probe` 一致:setup 阶段免 Bearer;一旦 `API_KEY` 已配置,必须带 `Authorization: Bearer <API_KEY>`。
请求体可以使用内置字段,也可以直接传 `records`:
```json
{
"domain": "example.com",
"mail_host": "mail.example.com",
"mail_ip": "203.0.113.10",
"mx_target": "mail.example.com",
"spf_value": "v=spf1 include:_spf.example.com ~all",
"openai_domain_verification": "openai-domain-verification=abc",
"records": [
{
"type": "TXT",
"name": "example.com",
"expected": "openai-domain-verification=abc"
}
]
}
```
响应示例:
```json
{
"ok": false,
"domain": "example.com",
"all_ok": false,
"safe_read_only": true,
"checks": [
{
"type": "TXT",
"name": "example.com",
"expected": "openai-domain-verification=abc",
"observed": [],
"ok": false,
"error": null
}
],
"error_code": null,
"message": null
}
```
### `POST /api/mail-provider/probe`
邮箱后端 3 步探测,SetupPage / Settings 用作切换前置校验。**setup 阶段免 Bearer**(在 `_AUTH_SKIP_PATHS` 白名单);一旦 `API_KEY` 已配置,仍要求 Bearer,且按 IP 限速 60 req/min(超限返 `error_code=RATE_LIMITED` + HTTP 429)。
请求体(共用 schema):
```json
{
"provider": "cf_temp_email | maillab",
"step": "fingerprint | credentials | domain_ownership",
"base_url": "https://example.com/api",
"username": "admin@example.com", // 仅 maillab credentials/domain_ownership
"password": "...", // 仅 maillab credentials/domain_ownership
"admin_password": "...", // 仅 cf_temp_email credentials/domain_ownership
"domain": "example.com" // 仅 domain_ownership
}
```
响应通用字段:
```json
{
"ok": true,
"step": "fingerprint",
"provider": "maillab",
"detected_provider": "maillab",
"domain_list": ["@a.com"],
"warnings": [],
"error_code": null,
"message": null,
"hint": null,
"leaked_probe": null,
"cleaned": null
}
```
`error_code` 取值见下表(失败时 `ok=false`):
| `error_code` | HTTP | 说明 |
|---|---|---|
| `PROVIDER_MISMATCH` | 200 | base_url 指纹与 `provider` 不一致(典型 issue#1) |
| `ROUTE_NOT_FOUND` | 200 | base_url 不是任何已知后端 |
| `EMPTY_DOMAIN_LIST` | 200 | maillab `domainList` 空 |
| `UNAUTHORIZED` | 200 | 凭据校验失败 |
| `CAPTCHA_REQUIRED` | 200 | maillab 启用了登录验证码 |
| `DOMAIN_REJECTED` | 200 | 创建探测邮箱被后端拒绝(`addVerify=1` 等) |
| `NETWORK_ERROR` / `TIMEOUT` | 200 | 网络异常 |
| `RATE_LIMITED` | 429 | 60 req/min 限速触发 |
#### 示例 1:`step=fingerprint`(探测后端归属)
```bash
curl -X POST http://localhost:8787/api/mail-provider/probe \
-H "Content-Type: application/json" \
-d '{"provider":"maillab","step":"fingerprint","base_url":"https://m.example.com"}'
```
成功响应:
```json
{
"ok": true,
"detected_provider": "maillab",
"domain_list": ["@example.com", "@x.example.com"],
"warnings": []
}
```
#### 示例 2:`step=credentials`(凭据校验)
cf_temp_email:
```bash
curl -X POST http://localhost:8787/api/mail-provider/probe \
-H "Content-Type: application/json" \
-d '{"provider":"cf_temp_email","step":"credentials","base_url":"https://mail.example.com/api","admin_password":"..."}'
```
> `cf_temp_email` 的 `base_url` 对应 `CLOUDMAIL_BASE_URL`,必须包含 `/api` 前缀;不要只填域名根路径。
maillab:
```bash
curl -X POST http://localhost:8787/api/mail-provider/probe \
-H "Content-Type: application/json" \
-d '{"provider":"maillab","step":"credentials","base_url":"...","username":"admin@x.com","password":"..."}'
```
#### 示例 3:`step=domain_ownership`(域名归属验证)
```bash
curl -X POST http://localhost:8787/api/mail-provider/probe \
-H "Content-Type: application/json" \
-d '{"provider":"maillab","step":"domain_ownership","base_url":"...","username":"...","password":"...","domain":"example.com"}'
```
成功响应:
```json
{
"ok": true,
"cleaned": true,
"leaked_probe": null
}
```
如果探测邮箱删除失败(`cleaned=false`),`leaked_probe` 含 `{"email":"probe-...","account_id":"..."}`,需到管理后台手动删除。
> 内部使用 `autoteam.mail.probe.probe_domain_ownership` helper,与 `/api/config/register-domain`(注册域名验证)共用同一份逻辑,语义对齐。
## 调用示例
```bash
# 查看账号状态
curl -H "Authorization: Bearer YOUR_KEY" \
http://localhost:8787/api/status
# 快速轮询状态(不触发实时额度探测)
curl -H "Authorization: Bearer YOUR_KEY" \
"http://localhost:8787/api/status?fast=true"
# 触发轮转
curl -X POST -H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"target": 3}' \
http://localhost:8787/api/tasks/rotate
# 从 CPA 拉取认证文件到本地
curl -X POST -H "Authorization: Bearer YOUR_KEY" \
http://localhost:8787/api/sync/from-cpa
# 生成手动 OAuth 链接
curl -X POST -H "Authorization: Bearer YOUR_KEY" \
http://localhost:8787/api/manual-account/start
```