Spaces:
Paused
Paused
| # 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 | |
| ``` | |