# Zenvlp API 助手指南

本文档和 OpenAPI 文档来自同一份接口注册表。不要反向猜测服务、隐藏端点或未声明参数；只使用这里描述的公开 API 行为。

API 基础 URL: `https://mail.scraperadar.app`
Markdown 文档: `https://mail.scraperadar.app/api/docs.md`
OpenAPI JSON: `https://mail.scraperadar.app/api/openapi.json`
OpenAPI YAML: `https://mail.scraperadar.app/api/openapi.yaml`
本文档中的所有 HTTP 端点都使用 `/api/` 前缀。
Zenvlp 是开源且可自部署的项目。复制示例到其他环境时，请把 Base URL 换成用户自己的 Zenvlp 实例地址，不要假设存在固定官方 API 域名。

## 认证

API Key 自动化调用使用请求头：

```http
X-API-Key: YOUR_KEY
```

API 自动化只使用 `X-API-Key`。域名管理、MX 检查、登录、用户管理和 API Key 创建都属于 Web Console 任务。

## 公开 API 边界

API Key 自动化接口刻意保持小而稳定。OpenAPI、Markdown 文档、Skill 文档、健康检查和版本端点属于公开元数据。`POST /api/generate-email` 可以在同一次 API Key 调用中创建带 key 的邮箱分享。分享链接和 Webhook 管理端点标记为 `cookie/session`，它们是 Web Console 会话端点，不属于 API Key 自动化接口。

## 域名发现与选择

在创建邮箱前，除非用户已经明确给出完整邮箱或指定域名，AI 助手和客户端都应先调用 `GET /api/domains/available`。

```bash
curl "https://mail.scraperadar.app/api/domains/available" \
  -H "X-API-Key: YOUR_KEY"
```

`data.public_domains` 是可选公共域名及元数据，`data.private_domains` 是当前 API Key 可访问的私有域名。把两组域名分组展示给用户；如果流程需要多个邮箱或多个域名，可以让用户多选后逐个调用 `POST /api/generate-email`。`data.domains` 是旧客户端兼容字段，只包含公共域名字符串，不应覆盖新字段。

不要在 `data.private_domains` 已有可访问私有域名时要求用户手动输入私有域名。只有目标私有域名不在列表中，才引导用户去 Web Console 完成域名添加和 MX 验证。

## 私有域名流程

如果用户要使用 `example.com` 这样的私有域名，引导他们完成以下流程：

1. 先检查 `GET /api/domains/available` 的 `data.private_domains`。如果目标域名已经在列表中，直接让用户选择它。
2. 如果目标域名不在列表中，让用户在 Web Console 中添加 `example.com` 作为私有域名。
3. 让用户在 DNS 服务商中添加指向平台 MX 目标的 MX 记录。
4. 如果只需要 `user@example.com` 这类地址，根域 MX 记录就够了。
5. 如果需要 `user@abc.example.com` 这类地址，还需要添加通配 MX 记录。
6. DNS 生效后，让用户在 Web Console 中完成 MX 验证。
7. 使用 API Key 调用 `POST /api/generate-email` 并传入私有域名。响应返回该域名时，说明 API 访问已可用。

用户需要添加的 DNS 记录：

```dns
example.com.    MX  10 mail.scraperadar.app.
*.example.com.  MX  10 mail.scraperadar.app.
```

通配记录只在需要 `user@abc.example.com` 这类子域邮箱时才需要。

验证私有域名 API 访问：

```bash
curl -X POST "https://mail.scraperadar.app/api/generate-email" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"prefix":"verify","domain":"example.com"}'
```

如果该调用返回域名或权限错误，常见原因包括 DNS 尚未传播、Web Console 域名配置未完成、API Key 不正确，或该域名属于另一个账号。

## 公共域名流程

公共域名适合快速测试，但部分网站可能会屏蔽临时邮箱域名。如果网站拒绝该地址或验证码邮件没有到达，可以建议换一个公共域名、换一个邮箱前缀、稍等片刻，或绑定私有域名。

列出可用公共域名和当前 API Key 可访问的私有域名：

```bash
curl "https://mail.scraperadar.app/api/domains/available" \
  -H "X-API-Key: YOUR_KEY"
```

`data.domains` 是兼容旧客户端的字段，只包含公共域名字符串。新客户端和 AI 助手应优先使用 `data.public_domains` 和 `data.private_domains`，并把两组结果作为可选择的域名列表展示给用户。

生成随机公共域名邮箱：

```bash
curl -X POST "https://mail.scraperadar.app/api/generate-email" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{}'
```

创建新邮箱记录时返回 HTTP `201`。如果同一个 API Key 拥有者再次生成已有邮箱，API 返回 HTTP `200`，并带有 `data.reuse=true`。

一次调用生成邮箱和分享 URL：

```bash
curl -X POST "https://mail.scraperadar.app/api/generate-email" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"prefix":"verify","domain":"example.com","share":true}'
```

响应包含 `data.share.url` 和 `data.share.access_url`。`access_url` 会带上随机 `key` 查询参数，可直接打开邮箱；移除 `?key=...` 后会进入公开解锁页，需要手动输入 key。完整 token/key 只返回一次，后台只保存 hash，需要再次复制时要重新生成分享链接。

## 管理已生成邮箱

列出 API Key 拥有者创建的邮箱：

```bash
curl "https://mail.scraperadar.app/api/mailboxes?page=1&per_page=20" \
  -H "X-API-Key: YOUR_KEY"
```

传入 `page`、`per_page` 或 `q` 时，`GET /api/mailboxes` 返回带 `items`、`page`、`per_page`、`total`、`total_pages` 的分页元数据。

删除一个邮箱记录及其已存储邮件：

```bash
curl -X DELETE "https://mail.scraperadar.app/api/mailboxes/45" \
  -H "X-API-Key: YOUR_KEY"
```

成功响应中的 data 包含 `deleted=true` 和 `messages_deleted`。

## 读取邮件

邮箱生成后，目标网站会向该地址发送邮件。验证码自动化建议使用简单轮询：每 3 秒调用一次 `GET /api/emails/next?email=MAILBOX`，最多等待 120 秒。没有邮件时返回 `has_email=false`；存在新未读邮件时返回邮件内容，并自动将该邮件标记为已读。拿到 `has_email=true` 后应停止轮询。

```bash
curl "https://mail.scraperadar.app/api/emails/next?email=verify@example.com" \
  -H "X-API-Key: YOUR_KEY"
```

列出邮件且不改变已读状态：

```bash
curl "https://mail.scraperadar.app/api/emails?email=verify@example.com&page=1&per_page=20" \
  -H "X-API-Key: YOUR_KEY"
```

读取一封邮件：

```bash
curl "https://mail.scraperadar.app/api/email/msg-uuid" \
  -H "X-API-Key: YOUR_KEY"
```

将一封邮件标记为已读：

```bash
curl -X PATCH "https://mail.scraperadar.app/api/email/msg-uuid/read" \
  -H "X-API-Key: YOUR_KEY"
```

清空某个邮箱的全部邮件：

```bash
curl -X DELETE "https://mail.scraperadar.app/api/emails/clear?email=verify@example.com" \
  -H "X-API-Key: YOUR_KEY"
```

验证码可从 `subject`、`preview`、`text_content` 或已清洗的 `html_content` 中提取。条件允许时，优先使用来自预期发件人的最新未读邮件。
时间戳为 RFC3339 字符串，可能使用 `Z` 或 `+08:00` 这类明确时区偏移。

## 读取分享邮箱

邮箱分享 URL 是公开端点，由不可猜测 token 加不可猜测访问 key 保护。不要向公开分享端点发送 API Key，也不要使用未文档化的 POST 解锁路径。

```bash
curl "https://mail.scraperadar.app/api/shared/SHARE_TOKEN?key=SHARE_KEY"
curl "https://mail.scraperadar.app/api/shared/SHARE_TOKEN/messages?key=SHARE_KEY&page=1&per_page=20"
curl "https://mail.scraperadar.app/api/shared/SHARE_TOKEN/messages/msg-uuid?key=SHARE_KEY"
```

不带 `key` 时，`GET /api/shared/SHARE_TOKEN` 会返回邮箱分享的锁定元数据。key 错误返回 `401`；分享过期或已撤销返回 `410`。

## API Key 自动化端点

| 方法 | 路径 | 认证 | 用途 |
| --- | --- | --- | --- |
| `GET` | `/api/domains/available` | API Key | 列出可选择的公共域名以及 API Key 拥有者可访问的私有域名。客户端和 AI 助手应把该端点作为生成邮箱前的域名选择入口，优先使用 data.public_domains 与 data.private_domains；data.domains 仅为旧客户端公共域名兼容字段。 |
| `GET` | `/api/email/:id` | API Key | 按 ID 读取一封邮件，包含文本正文、可用时的安全 HTML、邮件头和附件元数据。 |
| `DELETE` | `/api/email/:id` | API Key | 删除 API Key 调用方有权限访问的一封邮件。 |
| `PATCH` | `/api/email/:id/read` | API Key | 将一封邮件标记为已读。 |
| `GET` | `/api/emails` | API Key | 列出某个邮箱的邮件，不改变已读状态。使用 page 和 per_page 获取分页元数据。 |
| `DELETE` | `/api/emails/clear` | API Key | 删除某个邮箱中已存储的全部邮件。 |
| `GET` | `/api/emails/next` | API Key | 返回邮箱中最新的未读邮件，并自动将该邮件标记为已读。没有未读邮件时返回 has_email=false。 |
| `POST` | `/api/generate-email` | API Key | 为 API Key 调用方创建或复用邮箱。传入已验证域名可使用私有域名；省略 domain 会随机使用公共域名。设置 share=true 或 share.enabled=true 可在同一响应中创建邮箱分享；返回的 data.share.url 是分享页 URL，data.share.access_url 会带上 ?key= 访问参数。 |
| `GET` | `/api/mailboxes` | API Key | 列出 API Key 拥有者创建的邮箱。使用 page 和 per_page 获取分页响应。 |
| `DELETE` | `/api/mailboxes/:id` | API Key | 删除指定邮箱记录以及该地址下已存储的邮件。 |
| `GET` | `/api/stats` | API Key | 返回 API Key 拥有者可见的统计数据。 |

## 公开元数据端点

| 方法 | 路径 | 认证 | 用途 |
| --- | --- | --- | --- |
| `GET` | `/api/docs.md` | 公开 | 返回由 API 注册表生成、适合 AI 阅读的 Markdown 指南。 |
| `GET` | `/api/health` | 公开 | 返回服务健康状态元数据。 |
| `GET` | `/api/openapi.json` | 公开 | 返回 JSON 格式的 OpenAPI 文档。 |
| `GET` | `/api/openapi.yaml` | 公开 | 返回 YAML 格式的 OpenAPI 文档。 |
| `GET` | `/api/skill.md` | 公开 | 返回由 API 注册表生成的 AI 助手 Skill 指南。 |
| `GET` | `/api/version` | 公开 | 返回当前服务版本、commit 和构建时间。 |

## 公开分享端点

| 方法 | 路径 | 认证 | 用途 |
| --- | --- | --- | --- |
| `GET` | `/api/shared/:token` | 公开 | 邮箱分享 token 的公开端点。没有 key 时返回锁定元数据，带 key 时返回邮箱元数据。 |
| `GET` | `/api/shared/:token/messages` | 公开 | 列出邮箱分享中的邮件。必须在 key 查询参数中提供分享访问 key。 |
| `GET` | `/api/shared/:token/messages/:message_id` | 公开 | 从邮箱分享中读取一封邮件。必须提供分享访问 key，且只返回属于该分享邮箱的邮件。 |

## Web 会话 API 端点

这些端点需要 Web Console 的 `gptmail_session` cookie/会话，不能通过 API Key 自动化调用。

| 方法 | 路径 | 认证 | 用途 |
| --- | --- | --- | --- |
| `GET` | `/api/share-links` | cookie/会话 | 网页登录会话端点。列出当前登录用户的分享链接。 |
| `POST` | `/api/share-links` | cookie/会话 | 网页登录会话端点。为当前登录用户创建邮箱分享链接。 |
| `GET` | `/api/share-links/:id` | cookie/会话 | 网页登录会话端点。读取一个已管理的分享链接。 |
| `PATCH` | `/api/share-links/:id` | cookie/会话 | 网页登录会话端点。更新一个邮箱分享链接的过期时间。 |
| `DELETE` | `/api/share-links/:id` | cookie/会话 | Session-only endpoint. Deletes one managed share link and its access logs. |
| `GET` | `/api/share-links/:id/access-logs` | cookie/会话 | 网页登录会话端点。列出一个分享链接的访问尝试记录。 |
| `POST` | `/api/share-links/:id/revoke` | cookie/会话 | 网页登录会话端点。撤销一个分享链接。 |
| `POST` | `/api/share-links/:id/rotate-key` | cookie/会话 | 网页登录会话端点。轮换一个邮箱分享的访问 key，并只返回一次新 key。 |
| `POST` | `/api/share-links/:id/rotate-token` | cookie/会话 | 网页登录会话端点。重新生成邮箱分享的公开 token；邮箱分享会同时轮换访问 key，并只在本次响应返回完整 access_url。 |
| `GET` | `/api/webhooks` | cookie/会话 | 网页登录会话端点。列出当前登录用户的 Webhook 端点。 |
| `POST` | `/api/webhooks` | cookie/会话 | 网页登录会话端点。创建一个 Webhook 端点。 |
| `PATCH` | `/api/webhooks/:id` | cookie/会话 | 网页登录会话端点。更新一个 Webhook 端点。 |
| `DELETE` | `/api/webhooks/:id` | cookie/会话 | 网页登录会话端点。删除一个 Webhook 端点。 |
| `GET` | `/api/webhooks/:id/deliveries` | cookie/会话 | 网页登录会话端点。列出一个 Webhook 端点的投递尝试记录。 |
| `POST` | `/api/webhooks/:id/rotate-secret` | cookie/会话 | 网页登录会话端点。轮换一个 Webhook 端点的签名 secret。 |
| `POST` | `/api/webhooks/:id/test` | cookie/会话 | 网页登录会话端点。将一次测试 Webhook 投递加入队列。 |

## 响应信封

成功：

```json
{
  "success": true,
  "data": {},
  "error": null,
  "usage": {
    "used_today": "12",
    "daily_limit": "200000",
    "remaining_today": "199988",
    "daily_unlimited": "false",
    "total_usage": "238",
    "total_limit": "0",
    "remaining_total": "unlimited",
    "total_unlimited": "true"
  }
}
```

失败：

```json
{
  "success": false,
  "data": null,
  "error": "message not found"
}
```

`error` 是给人看的文本，可能会本地化。不要用精确错误文本做分支；控制流程请使用 HTTP 状态码和 `success` 标志，再把 `error` 展示给用户。

`usage` 只会出现在 API Key 请求中，包括认证成功后失败的 API Key 请求。用量数字以字符串返回，方便 JavaScript 客户端安全处理大整数。无限配额会在 remaining 字段中返回 `"unlimited"`，并配有对应的 `*_unlimited` 标志。
