# CertbotX Agent 客户接入协议

本文件供 AI Agent、自动化编排器和开发者读取。CertbotX 同时支持人类客户与 Agent 客户：二者共享组织、套餐、额度、域名、证书、部署目标和审计日志，但使用不同的登录方式。

## 1. 身份模型

- 人类客户使用账号登录网页控制台，负责套餐购买、团队管理、账号安全、退款和 Agent 身份管理。
- Agent 客户使用独立的 `client_id + client_secret` 换取 15 分钟短期 `access_token`。
- 旧版组织 API Key 仍受支持，现有自动化无需立即迁移；新 Agent 推荐使用独立 Agent 客户身份。
- Client Secret 明文只显示一次。服务端只保存 SHA-256 哈希。
- Agent 每次请求都会重新校验身份状态、组织状态、有效期和最新 scopes；撤销会让已签发 Token 立即失效。

支持的 scopes：

| Scope | 能力 |
| --- | --- |
| `read` | 读取组织概览和业务资产，创建时自动包含 |
| `domains:write` | 添加域名、开关托管、创建或验证 DNS 委托 |
| `certificates:write` | 创建 ACME 订单和管理证书 |
| `deployments:write` | 管理云连接、部署目标并执行部署 |
| `feedback:write` | 创建和回复反馈工单 |

支付、退款、团队、账号安全、数据删除、API Key 与 Agent 身份管理不向 Agent Token 开放，必须交由人类用户处理。

## 2. 人类准备 Agent 身份

1. 登录 `https://www.certbotx.cn/customer`。
2. 打开“账号与安全” → “Agent 客户身份” → “创建 Agent 身份”。
3. 填写用途，并按任务分配最小 scopes。只盘点资产时保留 `read` 即可。
4. 可设置最长 365 天的凭据有效期。
5. 立即保存只显示一次的 Client Secret；Client ID 之后仍可在控制台查看。

将长期凭据放入 Agent 的秘密管理器，不要写入提示词、Git、日志、URL 或聊天消息：

```sh
export CERTBOTX_API_BASE="https://www.certbotx.cn/api/v1"
export CERTBOTX_CLIENT_ID="cbx_agent_由控制台生成"
export CERTBOTX_CLIENT_SECRET="cbs_只显示一次"
```

## 3. 换取短期 Token

Agent 启动或 Token 失效时调用：

```sh
curl --fail-with-body -X POST \
  -H "Content-Type: application/json" \
  -d "{\"grant_type\":\"client_credentials\",\"client_id\":\"$CERTBOTX_CLIENT_ID\",\"client_secret\":\"$CERTBOTX_CLIENT_SECRET\"}" \
  "$CERTBOTX_API_BASE/auth/agent/token"
```

响应示例：

```json
{
  "access_token": "cba_短期令牌",
  "token_type": "Bearer",
  "expires_in": 900,
  "scopes": ["read", "domains:write"]
}
```

后续请求使用 `Authorization: Bearer ${CERTBOTX_ACCESS_TOKEN}`。不要把 `client_secret` 当作 Bearer Token 使用。

旧 API Key 兼容方式：将 `cbx_...` 直接作为 Bearer Token；旧权限仍为 `read` / `write`，但不具备 Agent 客户的细粒度隔离。

## 4. 标准状态机

### A. 先读当前状态

```sh
curl --fail-with-body -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" "$CERTBOTX_API_BASE/customer/overview"
curl --fail-with-body -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" "$CERTBOTX_API_BASE/customer/domains"
curl --fail-with-body -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" "$CERTBOTX_API_BASE/customer/certificates"
curl --fail-with-body -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" "$CERTBOTX_API_BASE/customer/deployment-targets"
```

未完成盘点前不得写入；不要提交 `organization_id`，服务端会从身份确定组织边界。

### B. 添加域名

仅当域名不存在时创建。添加域名会自动分配 DNS-01 CNAME 委托。

```sh
curl --fail-with-body -X POST \
  -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain":"example.com","verify_type":"dns-01"}' \
  "$CERTBOTX_API_BASE/customer/domains"
```

保存响应中的 `id`、`delegation.id`、`delegation.source_fqdn` 和 `delegation.delegation_fqdn`。

### C. 完成 DNS 委托

CertbotX 不会擅自修改客户的权威 DNS。Agent 必须暂停请人类配置 CNAME，或调用另一个已经获得人类授权且权限受限的 DNS 工具。不得假装记录已写入。

```sh
curl --fail-with-body -X POST \
  -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" \
  "$CERTBOTX_API_BASE/customer/dns/delegations/DELEGATION_ID/verify"
```

只有 `delegation.status = verified` 才能继续。DNS 传播期间最多每 30 秒验证一次；10 分钟仍未通过时停止并报告预期值与实际值。

### D. 创建 ACME 订单

不要使用 `/customer/certificates` 创建空记录。使用稳定的 `idempotency_key`，网络超时后复用同一个值。

```sh
curl --fail-with-body -X POST \
  -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domain_id": DOMAIN_ID,
    "common_name": "example.com",
    "sans": ["example.com"],
    "email": "ops@example.com",
    "private_key_mode": "platform_managed",
    "idempotency_key": "agent:example.com:initial"
  }' \
  "$CERTBOTX_API_BASE/customer/acme/orders"
```

轮询 `GET /customer/acme/orders`。进行中状态包括 `pending`、`preparing_challenge`、`waiting_dns`；成功为 `issued`；`failed` 时停止并返回 `error_message`，不要无限创建新订单。

### E. 开启托管

域名已验证且至少存在一张活动证书后：

```sh
curl --fail-with-body -X POST \
  -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  "$CERTBOTX_API_BASE/customer/domains/DOMAIN_ID/managed"
```

只有 `managed_enabled = true` 且 `managed_status = active` 才算成功。HTTP 409 通常表示额度或状态冲突；HTTP 422 表示前置验证或证书条件未满足。

### F. 部署并验证公网证书

默认只使用人类已验证的部署目标，不在模型上下文中接收云 SecretKey、服务器密码或证书私钥。

```sh
curl --fail-with-body -X POST \
  -H "Authorization: Bearer $CERTBOTX_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"certificate_id": CERTIFICATE_ID, "force": false}' \
  "$CERTBOTX_API_BASE/customer/deployment-targets/TARGET_ID/deploy"
```

轮询 `GET /customer/deployment-runs/RUN_ID`。只有 `success` 才进入公网验证；`failed`、`rolled_back` 或 `rollback_failed` 都必须报告失败。

公网检查是公开端点，不需要 Agent Token：

```sh
curl --fail-with-body -X POST \
  -H "Content-Type: application/json" \
  -d '{"domain":"example.com"}' \
  "$CERTBOTX_API_BASE/public/tools/tls-check"
```

比较公网证书域名、颁发者、有效期和指纹与目标证书是否一致，然后才能报告完成。

## 5. 错误与人工接管

1. HTTP 401：重新换取一次 Token；仍失败则停止并请人类检查身份是否到期或撤销。
2. HTTP 403：读取错误中的缺失 scope，不要尝试绕过；请人类按最小权限调整或接管。
3. HTTP 409 / 422：重新读取资源状态并报告缺失前置条件。
4. HTTP 429 / 5xx：指数退避，最多重试 3 次；异步状态轮询不算盲目重试。
5. 支付、退款、团队、账号安全、Agent 身份管理或任何未识别写操作：立即交给人类。
6. 证书撤销、冻结、材料回滚、强制部署、删除目标和暂停托管即使 scope 允许，也必须先取得人类当次明确确认。
7. 不回显 Client Secret、access token、API Key、云密钥、服务器密码或证书私钥。
8. 所有写操作后重新读取目标资源；完成报告必须包含可验证的终态。

## 6. 可直接交给 Agent 的系统指令

```text
你是 CertbotX 的 Agent 客户。API 根地址来自 CERTBOTX_API_BASE，长期凭据来自 CERTBOTX_CLIENT_ID 与 CERTBOTX_CLIENT_SECRET。
先通过 POST /auth/agent/token 使用 client_credentials 换取 15 分钟 access_token；不输出、记录或传递任何完整凭据。
永远先读后写，不提交 organization_id。写操作前说明将修改的资源和继续条件。
支付、退款、团队、账号安全与 Agent 身份管理必须交给人类。
撤销、冻结、材料回滚、强制部署、删除目标和暂停托管必须获得人类当次明确确认。
添加域名后读取系统自动分配的 CNAME；没有独立 DNS 授权时暂停并请人类配置，不能假装完成。
ACME 下单使用稳定 idempotency_key。异步操作按状态轮询，出现失败终态立即停止。
只有部署运行 success 且公网 TLS 检查匹配后，才能报告任务完成。
```
