# gocdn API 参考 2.1.1792967583

## 鉴权

请求头带 X-API-Key(在「API 密钥」页开通,密钥只在开通时显示一次);也可用登录得到的 Authorization: Bearer 令牌。

1. 有 X-API-Key 先验密钥(未过期、未删除)
2. 否则验 Authorization: Bearer 访问令牌
3. 再按密钥的授权范围与接口的作用域判断(租户只能操作本租户的资源)

鉴权失败回 401;无权回 403(code 为 insufficient_scope 等)。

## 返回与错误

成功直接回资源 JSON(HTTP 2xx);失败回 application/problem+json(code、detail,校验失败带 errors);列表为 items + total。

## 约定

- 分页参数 page(从 1 起)、page_size;排序 sort=字段 或 -字段。
- 时间一律 RFC 3339(UTC);金额单位为分。
- 写操作成功回 200/201/204;重复提交按资源唯一键回 409。

## 登录认证 (`auth`)

登录、刷新令牌、退出、改口令、动态口令(TOTP)、找回密码、图形验证码与超管代登录。登录接口无需认证。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/auth

### GET `/api/v2/auth/captcha`

获取图形验证码 · 鉴权: 无需鉴权

```sh
curl "https://panel.example.com/api/v2/auth/captcha"
```

### POST `/api/v2/auth/login`

登录 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `captcha_code` | string |  | 图形验证码上显示的字符。 |
| `captcha_id` | string |  | 图形验证码 id,来自 GET /auth/captcha;连续登录失败后必填。 |
| `password` | string | 有 | 登录口令。 |
| `totp_code` | string |  | 动态口令(TOTP)的 6 位当前码,或一个未用过的恢复码(XXXXX-XXXXX,用后作废);账号启用动态口令时必填。 |
| `username` | string | 有 | 用户名 |
| `verify_code` | string |  | 登录二次验证码。账号开了邮件/短信验证码登录(login_verify)时必填,先经 POST /verify-codes(purpose=login)获取。 |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/login"
```

### POST `/api/v2/auth/logout`

退出登录 · 鉴权: 用户

```sh
curl -X POST "https://panel.example.com/api/v2/auth/logout" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/auth/password`

修改口令 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `new_password` | string | 有 | 新口令,8 到 128 个字符。 |
| `old_password` | string | 有 | 原口令。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/auth/password" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/auth/password-reset`

找回密码 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `channel` | string | 有 | 按邮箱还是手机号找回。 可选值: ["email","sms"] |
| `code` | string | 有 | 发到 target 的验证码(POST /verify-codes,purpose=reset_password)。 |
| `new_password` | string | 有 | 新口令,8 到 128 个字符。 |
| `target` | string | 有 | 账号绑定的邮箱或手机号。 |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/password-reset" \
  -H "Content-Type: application/json" \
  -d '{"channel":"email","code":"123456","new_password":"${NEW_PASSWORD}","target":"user@example.com"}'
```

### POST `/api/v2/auth/refresh`

刷新令牌 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `refresh_token` | string | 有 | 刷新令牌,用来换新的一对令牌。 |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/refresh"
```

### POST `/api/v2/auth/sso`

超管代登录 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `sso_ticket` | string | 有 | 超管签发的登录票:licwire 信封(kind sso_ticket)字节的 base64url(无填充)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/sso" \
  -H "Content-Type: application/json" \
  -d '{"sso_ticket":"eyJib2R5Ijp7fX0"}'
```

### POST `/api/v2/auth/switch`

管理员切换到用户 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `user_id` | integer | 有 | 用户 ID |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/switch" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":2}'
```

### POST `/api/v2/auth/switch-login`

凭切换票登录 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `switch_ticket` | string | 有 | 管理员换到的一次性切换票。 |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/switch-login"
```

### POST `/api/v2/auth/switch-ticket`

管理员换一张切换到用户的一次性票 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `user_id` | integer | 有 | 用户 ID |

```sh
curl -X POST "https://panel.example.com/api/v2/auth/switch-ticket" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":2}'
```

### POST `/api/v2/auth/totp`

生成动态口令密钥 · 鉴权: 用户

```sh
curl -X POST "https://panel.example.com/api/v2/auth/totp" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/auth/totp`

启用动态口令 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `code` | string | 有 | 发到 target 的验证码(POST /verify-codes,purpose=reset_password)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/auth/totp" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/auth/totp`

关闭动态口令 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `code` | string | 有 | 发到 target 的验证码(POST /verify-codes,purpose=reset_password)。 |

```sh
curl -X DELETE "https://panel.example.com/api/v2/auth/totp" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

登录认证对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `access_token` | string |  | 访问令牌,放在 Authorization: Bearer 里调用接口。 |
| `captcha_code` | string |  | 图形验证码上显示的字符。 |
| `captcha_id` | string |  | 图形验证码 id,来自 GET /auth/captcha;连续登录失败后必填。 |
| `channel` | string | 有 | 按邮箱还是手机号找回。 可选值: ["email","sms"] |
| `code` | string | 有 | 发到 target 的验证码(POST /verify-codes,purpose=reset_password)。 |
| `expires_in` | integer |  | access token 有效秒数。 |
| `id` | string |  | 登录时作为 captcha_id 回传;一次性,验一次即作废(不论对错)。 |
| `image` | string |  | PNG 的 data URI。 |
| `key` | string |  | base32 密钥(只在这里返回一次)。 |
| `must_change_password` | boolean |  | 只在登录响应里出现;true = 该账号还在用装机生成的初始口令(/root/gocdn-admin.pass),须先改口令(PUT /auth/password)再用,改过后不再出现。 |
| `new_password` | string | 有 | 新口令,8 到 128 个字符。 |
| `old_password` | string | 有 | 原口令。 |
| `otpauth_uri` | string |  | otpauth:// 地址,用认证器 App 扫码添加。 |
| `password` | string | 有 | 登录口令。 |
| `recovery_codes` | string[] |  | 8 个一次性恢复码(XXXXX-XXXXX),只在启用成功时返回这一次。 |
| `refresh_token` | string |  | 刷新令牌,用来换新的一对令牌。 |
| `sso_ticket` | string | 有 | 超管签发的登录票:licwire 信封(kind sso_ticket)字节的 base64url(无填充)。 |
| `switch_ticket` | string | 有 | 管理员换到的一次性切换票。 |
| `target` | string | 有 | 账号绑定的邮箱或手机号。 |
| `token_type` | string |  | 令牌类型,固定为 Bearer。 |
| `totp_code` | string |  | 动态口令(TOTP)的 6 位当前码,或一个未用过的恢复码(XXXXX-XXXXX,用后作废);账号启用动态口令时必填。 |
| `user_id` | integer | 有 | 用户 ID |
| `username` | string | 有 | 用户名 |
| `verify_code` | string |  | 登录二次验证码。账号开了邮件/短信验证码登录(login_verify)时必填,先经 POST /verify-codes(purpose=login)获取。 |

## 用户管理 (`users`)

管理员管理平台账号:增删改查、启停、重设口令、关闭动态口令。删除前须先停用。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/users

### GET `/api/v2/users`

列出用户 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `ids` | string |  | 只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。 |
| `email` | string |  | 邮箱 |
| `phone` | string |  | 手机号 |
| `username` | string |  | 用户名 |

```sh
curl "https://panel.example.com/api/v2/users" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/users`

创建用户 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `password` | string |  | 创建时必填;修改时给了即重设口令并吊销该用户全部会话。 |
| `phone` | string |  | 手机号 |
| `role` | string |  | 账号角色:admin 管理员,tenant 租户。 可选值: ["admin","tenant"] |
| `totp_enabled` | boolean |  | 是否已启用动态口令。 |
| `username` | string | 有 | 用户名 |

```sh
curl -X POST "https://panel.example.com/api/v2/users" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/users/batch`

批量启停或删除用户 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | enable 启用、disable 停用、delete 删除。 可选值: ["enable","disable","delete"] |
| `ids` | integer[] | 有 | 要操作的用户 id,一次 1~100 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/users/batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/users/{id}`

获取用户 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/users/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/users/{id}`

修改用户 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `password` | string |  | 创建时必填;修改时给了即重设口令并吊销该用户全部会话。 |
| `phone` | string |  | 手机号 |
| `role` | string |  | 账号角色:admin 管理员,tenant 租户。 可选值: ["admin","tenant"] |
| `totp_enabled` | boolean |  | 是否已启用动态口令。 |
| `username` | string | 有 | 用户名 |

```sh
curl -X PUT "https://panel.example.com/api/v2/users/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/users/{id}`

删除用户 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/users/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/users/{user_id}/account`

查看用户账户 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/users/{user_id}/account" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/users/{user_id}/account`

冻结或解冻用户账户 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `freeze_reason` | string |  | 冻结原因;未冻结为空。 |
| `frozen` | boolean | 有 | 是否已冻结;冻结后扣款一律被拒。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/users/{user_id}/account" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"freeze_reason":"风控核查","frozen":true}'
```

### GET `/api/v2/users/{user_id}/api-keys`

列出指定用户的 API Key · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/users/{user_id}/api-keys" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/users/{user_id}/api-keys`

为指定用户开通 API Key · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `expires_at` | string |  | 过期时间 |
| `name` | string | 有 | 名称 |
| `scopes` | string[] | 有 | 授权范围,取值同创建时的 scopes。 |

```sh
curl -X POST "https://panel.example.com/api/v2/users/{user_id}/api-keys" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/users/{user_id}/api-keys/{id}`

改指定用户 API Key 的 IP 白名单或重置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `reset` | boolean |  | 为 true 时换新 key,旧 key 立即失效。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/users/{user_id}/api-keys/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reset":true}'
```

### DELETE `/api/v2/users/{user_id}/api-keys/{id}`

删除指定用户的 API Key · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/users/{user_id}/api-keys/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/users/{user_id}/recharges`

给用户充值或扣款 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | integer | 有 | 金额(分),须为正整数。 |
| `direction` | string |  | credit 充值(缺省)、debit 扣款。 可选值: ["credit","debit"] 默认: "credit" |
| `remark` | string |  | 备注 |

```sh
curl -X POST "https://panel.example.com/api/v2/users/{user_id}/recharges" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount_cents":10000,"direction":"credit","remark":"线下转账"}'
```

用户管理对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | enable 启用、disable 停用、delete 删除。 可选值: ["enable","disable","delete"] |
| `affected` | integer |  | 处理的用户数。 |
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `amount_cents` | integer | 有 | 金额(分),须为正整数。 |
| `archived` | boolean |  | 已被归档任务搬进档案表(只读)。 |
| `balance_cents` | integer |  | 账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。 (只读) |
| `certified` | boolean |  | 是否已通过实名认证。 |
| `client_ip` | string |  | 本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `data` | object |  | 附加数据(如套餐购买明细)。 |
| `delegated_session` | boolean |  | 当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。 (只读) |
| `des` | string |  | 备注说明 |
| `direction` | string |  | credit 充值(缺省)、debit 扣款。 可选值: ["credit","debit"] 默认: "credit" |
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `expires_at` | string |  | 过期时间 |
| `freeze_reason` | string |  | 冻结原因;未冻结为空。 |
| `frozen` | boolean |  | 是否已冻结;冻结后扣款一律被拒。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 要操作的用户 id,一次 1~100 个。 |
| `last_used_at` | string |  | 最近一次使用时间;从未使用为空。 |
| `ledger_id` | integer |  | 关联的账户流水 ID;没有则为空。 |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `mch_order_no` | string |  | 商户订单号(网关侧订单号);非在线支付为空。 |
| `name` | string |  | 名称 |
| `paid_at` | string |  | 付款时间;未付款为空。 |
| `password` | string |  | 创建时必填;修改时给了即重设口令并吊销该用户全部会话。 |
| `pay_type` | string |  | admin/balance/alipay/wxpay 等;空 = 未付款。 |
| `phone` | string |  | 手机号 |
| `prefix` | string |  | 明文的前几位,便于辨认。 |
| `remark` | string |  | 备注 |
| `reset` | boolean |  | 为 true 时换新 key,旧 key 立即失效。 |
| `role` | string |  | 账号角色:admin 管理员,tenant 租户。 可选值: ["admin","tenant"] |
| `scopes` | string[] |  | 授权范围,取值同创建时的 scopes。 |
| `secret` | string |  | 明文 key(X-API-Key 的值),只在创建时返回一次;库里只存哈希。 |
| `status` | string |  | 订单状态:unpaid 待付款、paid 已付款。 可选值: ["unpaid","paid"] |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `totp_enabled` | boolean |  | 是否已启用动态口令。 |
| `totp_recovery_left` | integer |  | 未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。 (只读) |
| `transaction_id` | string |  | 网关侧交易号;未付款为空。 |
| `type` | string |  | recharge(管理员充值)/deduct(管理员扣款)/payment(在线支付)/package(套餐)等。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `user_id` | integer |  | 用户 ID |
| `username` | string |  | 用户名 |

## 当前用户 (`me`)

当前登录用户查看或修改自己的资料、实名认证与界面偏好。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/me

### GET `/api/v2/me`

当前用户 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/me" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/me`

修改个人资料 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `email` | string |  | 邮箱 |
| `email_code` | string |  | 发到新邮箱的验证码(POST /verify-codes,purpose=bind);改邮箱时必填。 |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `phone` | string |  | 手机号 |
| `phone_code` | string |  | 发到新手机号的验证码(POST /verify-codes,purpose=bind);改手机号时必填。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/me" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/me/certification`

实名认证状态 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/me/certification" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/me/certification`

提交实名认证 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id_number` | string | 有 | 打码后的证件号。 |
| `real_name` | string | 有 | 打码后的姓名。 |

```sh
curl -X POST "https://panel.example.com/api/v2/me/certification" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id_number":"11010519491231002X","real_name":"张三"}'
```

### GET `/api/v2/me/preferences`

用户偏好 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/me/preferences" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/me/preferences`

修改用户偏好 · 鉴权: 用户

```sh
curl -X PUT "https://panel.example.com/api/v2/me/preferences" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

当前用户对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `balance_cents` | integer |  | 账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。 (只读) |
| `certified` | boolean |  | 是否已通过实名认证。 |
| `client_ip` | string |  | 本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `delegated_session` | boolean |  | 当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。 (只读) |
| `email` | string |  | 邮箱 |
| `email_code` | string |  | 发到新邮箱的验证码(POST /verify-codes,purpose=bind);改邮箱时必填。 |
| `enabled` | boolean |  | 是否启用 |
| `id` | integer |  | 记录 ID (只读) |
| `id_number` | string |  | 打码后的证件号。 |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `phone` | string |  | 手机号 |
| `phone_code` | string |  | 发到新手机号的验证码(POST /verify-codes,purpose=bind);改手机号时必填。 |
| `provider` | string |  | 实名认证通道。 |
| `real_name` | string |  | 打码后的姓名。 |
| `reason` | string |  | 未通过的原因。 |
| `role` | string |  | 账号角色:admin 管理员,tenant 租户。 可选值: ["admin","tenant"] |
| `status` | string |  | 实名状态:none 未认证,pending 待认证,verified 已通过,failed 未通过。 可选值: ["none","pending","verified","failed"] |
| `totp_enabled` | boolean |  | 是否已启用动态口令。 |
| `totp_recovery_left` | integer |  | 未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |
| `url` | string |  | 待认证时用户要去的认证地址(仅提交时返回)。 |
| `username` | string |  | 用户名 |

## API 密钥 (`api-keys`)

当前用户的 API 密钥。密钥明文只在创建时返回一次,可按领域限定授权范围。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/api-keys

### GET `/api/v2/api-keys`

列出 API Key · 鉴权: 用户

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/api-keys" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/api-keys`

创建 API Key · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `expires_at` | string |  | 过期时间 |
| `name` | string | 有 | 名称 |
| `scopes` | string[] | 有 | 授权范围,取值同创建时的 scopes。 |

```sh
curl -X POST "https://panel.example.com/api/v2/api-keys" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/api-keys/{id}`

修改 API Key 的 IP 白名单或重置 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `reset` | boolean |  | 为 true 时换新 key,旧 key 立即失效。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/api-keys/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reset":true}'
```

### DELETE `/api/v2/api-keys/{id}`

删除 API Key · 鉴权: 用户

```sh
curl -X DELETE "https://panel.example.com/api/v2/api-keys/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

API 密钥对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `allow_ips` | ApiKeyAllowIps |  | 调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。 |
| `created_at` | string |  | 创建时间 (只读) |
| `expires_at` | string |  | 过期时间 |
| `id` | integer |  | 记录 ID (只读) |
| `last_used_at` | string |  | 最近一次使用时间;从未使用为空。 |
| `name` | string |  | 名称 |
| `prefix` | string |  | 明文的前几位,便于辨认。 |
| `reset` | boolean |  | 为 true 时换新 key,旧 key 立即失效。 |
| `scopes` | string[] |  | 授权范围,取值同创建时的 scopes。 |
| `secret` | string |  | 明文 key(X-API-Key 的值),只在创建时返回一次;库里只存哈希。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 注册须知 (`registration-info`)

无需认证。返回注册是否开放、各字段是否必填或需验证、用户协议。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/registration-info

### GET `/api/v2/registration-info`

注册须知 · 鉴权: 无需鉴权

```sh
curl "https://panel.example.com/api/v2/registration-info"
```

注册须知对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `agreement_body` | string |  | 用户协议正文。 |
| `agreement_title` | string |  | 用户协议标题。 |
| `allow_register` | boolean |  | 是否开放注册。 |
| `fields` | object |  | 注册表单各字段的要求(是否必填、是否要验证码)。 |
| `login_verify_allowed` | LoginVerify[] |  | 平台允许用户开启的登录二次验证方式。 |

## 注册 (`registrations`)

无需认证。提交注册信息建出租户账号;须同意用户协议,要验证的邮箱或手机须带验证码。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/registrations

### POST `/api/v2/registrations`

注册 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `accept_agreement` | boolean | 有 | 须为 true。 |
| `email` | string |  | 邮箱 |
| `email_code` | string |  | 发到该邮箱的验证码(POST /verify-codes,purpose=bind);邮箱要验证时必填。 |
| `password` | string | 有 | 登录口令,8 到 128 个字符。 |
| `phone` | string |  | 手机号 |
| `phone_code` | string |  | 发到该手机号的验证码(POST /verify-codes,purpose=bind);手机号要验证时必填。 |
| `username` | string |  | 须注册须知要求时必填;不填则自动生成。不能像手机号(纯数字)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/registrations" \
  -H "Content-Type: application/json" \
  -d '{"accept_agreement":true,"email":"alice@example.com","email_code":"123456","password":"${PASSWORD}","username":"alice"}'
```

注册对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `accept_agreement` | boolean | 有 | 须为 true。 |
| `balance_cents` | integer |  | 账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。 (只读) |
| `certified` | boolean |  | 是否已通过实名认证。 |
| `client_ip` | string |  | 本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `delegated_session` | boolean |  | 当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。 (只读) |
| `email` | string |  | 邮箱 |
| `email_code` | string |  | 发到该邮箱的验证码(POST /verify-codes,purpose=bind);邮箱要验证时必填。 |
| `enabled` | boolean |  | 是否启用 |
| `id` | integer |  | 记录 ID (只读) |
| `login_ip_allow` | string[] |  | 登录 IP 白名单(IP 或 CIDR);空 = 不限。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `password` | string | 有 | 登录口令,8 到 128 个字符。 |
| `phone` | string |  | 手机号 |
| `phone_code` | string |  | 发到该手机号的验证码(POST /verify-codes,purpose=bind);手机号要验证时必填。 |
| `role` | string |  | 账号角色:admin 管理员,tenant 租户。 可选值: ["admin","tenant"] |
| `totp_enabled` | boolean |  | 是否已启用动态口令。 |
| `totp_recovery_left` | integer |  | 未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |
| `username` | string |  | 须注册须知要求时必填;不填则自动生成。不能像手机号(纯数字)。 |

## 验证码 (`verify-codes`)

无需认证。发送邮件或短信验证码,用于注册绑定、找回密码和登录二次验证;短信须带图形验证码。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/verify-codes

### POST `/api/v2/verify-codes`

发邮件/短信验证码 · 鉴权: 无需鉴权

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `account` | string |  | 登录名(login 必填)。 |
| `captcha_code` | string |  | 图形验证码上显示的字符(发短信必填)。 |
| `captcha_id` | string |  | 图形验证码 id(发短信必填)。 |
| `channel` | string | 有 | 发送通道:email 邮件,sms 短信。 可选值: ["email","sms"] |
| `purpose` | string | 有 | 用途:bind 注册或改绑,reset_password 找回密码,login 登录二次验证。 可选值: ["bind","reset_password","login"] |
| `target` | string |  | 邮箱或手机号(bind、reset_password 必填)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/verify-codes" \
  -H "Content-Type: application/json" \
  -d '{"channel":"email","purpose":"bind","target":"alice@example.com"}'
```

验证码对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `account` | string |  | 登录名(login 必填)。 |
| `captcha_code` | string |  | 图形验证码上显示的字符(发短信必填)。 |
| `captcha_id` | string |  | 图形验证码 id(发短信必填)。 |
| `channel` | string | 有 | 发送通道:email 邮件,sms 短信。 可选值: ["email","sms"] |
| `expires_in` | integer |  | 有效期,秒。 |
| `purpose` | string | 有 | 用途:bind 注册或改绑,reset_password 找回密码,login 登录二次验证。 可选值: ["bind","reset_password","login"] |
| `resend_in` | integer |  | 多少秒后可以重发。 |
| `target` | string |  | 邮箱或手机号(bind、reset_password 必填)。 |
| `to` | string |  | 打码后的收件地址。 |

## 登录策略 (`login-policy`)

无需认证。按账号查询是否要邮件或短信验证码登录,以及打码后的收码目标。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/login-policy

### GET `/api/v2/login-policy`

登录策略 · 鉴权: 无需鉴权

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `account` | string | 有 | 登录名(用户名、邮箱或手机号)。 |

```sh
curl "https://panel.example.com/api/v2/login-policy"
```

登录策略对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `email` | string |  | 打码后的邮箱。 |
| `login_verify` | LoginVerify |  | 登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。 可选值: ["none","email","sms"] |
| `phone` | string |  | 打码后的手机号。 |

## 实名通道 (`certify-channels`)

仅管理员:支付宝身份验证与腾讯云慧眼(微信人脸核身)的商户凭据;用哪个通道在账号设置 certify_provider 里选。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/certify-channels

### GET `/api/v2/certify-channels`

实名通道设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/certify-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/certify-channels`

修改实名通道 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `alipay` | CertifyAlipay |  | 支付宝身份验证(alipay.user.certify.open.*)的商户参数。 |
| `wechat` | CertifyWechat |  | 腾讯云慧眼(微信人脸核身,faceid DetectAuth)的参数。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/certify-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

实名通道对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `alipay` | CertifyAlipay |  | 支付宝身份验证(alipay.user.certify.open.*)的商户参数。 |
| `wechat` | CertifyWechat |  | 腾讯云慧眼(微信人脸核身,faceid DetectAuth)的参数。 |

## 我的账户 (`account`)

当前用户自己的余额与冻结状态;管理员改用户账户走用户管理下的账户接口。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/account

### GET `/api/v2/account`

我的账户 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/account" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

我的账户对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `balance_cents` | integer |  | 账户余额(分)。 |
| `freeze_reason` | string |  | 冻结原因;未冻结为空。 |
| `frozen` | boolean |  | 是否已冻结;冻结后扣款一律被拒。 |
| `updated_at` | string |  | 更新时间 |
| `user_id` | integer |  | 用户 ID |

## 订单 (`orders`)

充值、扣款、在线支付与套餐购买产生的订单;租户只见本租户,管理员可跨租户,订单只许改备注。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/orders

### GET `/api/v2/orders`

列出订单 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `type` | string |  | 按订单类型过滤(recharge/deduct/payment/package 等)。 |
| `status` | string |  | 按状态过滤。 可选值: ["unpaid","paid"] |
| `start` | string |  | 下单时间起(含),RFC 3339。 |
| `end` | string |  | 下单时间止(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/orders" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/orders/stats`

订单金额统计 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `type` | string |  | 按订单类型过滤(recharge/deduct/payment/package 等)。 |
| `status` | string |  | 按状态过滤。 可选值: ["unpaid","paid"] |
| `start` | string |  | 下单时间起(含),RFC 3339。 |
| `end` | string |  | 下单时间止(不含),RFC 3339。 |
| `group_by` | string |  | 汇总粒度,缺省 day。 可选值: ["day","month","year"] |
| `utc_offset_minutes` | integer |  | 已废弃,仅为兼容旧调用方保留(仍校验取值范围)。日/月/年恒按平台时区(Asia/Shanghai)切分,与今日流量同一日界,不再随此参数平移。 |

```sh
curl "https://panel.example.com/api/v2/orders/stats" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/orders/{id}`

获取订单 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/orders/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/orders/{id}`

改订单备注 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string | 有 | 备注说明 |

```sh
curl -X PUT "https://panel.example.com/api/v2/orders/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"des":"线下转账已核对"}'
```

订单对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | integer |  | 金额(分),扣款单为负。 |
| `archived` | boolean |  | 已被归档任务搬进档案表(只读)。 |
| `created_at` | string |  | 创建时间 (只读) |
| `data` | object |  | 附加数据(如套餐购买明细)。 |
| `des` | string |  | 备注说明 |
| `group_by` | string |  | 汇总粒度:day、month 或 year。 可选值: ["day","month","year"] |
| `id` | integer |  | 记录 ID (只读) |
| `items` | OrderStatsItem[] |  | 本页条目 |
| `ledger_id` | integer |  | 关联的账户流水 ID;没有则为空。 |
| `mch_order_no` | string |  | 商户订单号(网关侧订单号);非在线支付为空。 |
| `paid_at` | string |  | 付款时间;未付款为空。 |
| `pay_type` | string |  | admin/balance/alipay/wxpay 等;空 = 未付款。 |
| `status` | string |  | 订单状态:unpaid 待付款、paid 已付款。 可选值: ["unpaid","paid"] |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `transaction_id` | string |  | 网关侧交易号;未付款为空。 |
| `type` | string |  | recharge(管理员充值)/deduct(管理员扣款)/payment(在线支付)/package(套餐)等。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 账户流水 (`ledger-entries`)

账户余额的每一笔变动,每条带记账后的余额快照。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/ledger-entries

### GET `/api/v2/ledger-entries`

列出账户流水 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `kind` | string |  | 按流水类别过滤。 |
| `start` | string |  | 记账时间起(含),RFC 3339。 |
| `end` | string |  | 记账时间止(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/ledger-entries" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

账户流水对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | integer |  | 带符号:正为入账,负为扣款。 |
| `balance_after_cents` | integer |  | 记这一笔后的余额快照。 |
| `created_at` | string |  | 创建时间 |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID |
| `kind` | string |  | 流水类型,如充值、扣款。 |
| `order_id` | integer |  | 关联订单 ID;没有为空。 |
| `tenant_id` | integer |  | 所属租户(用户)ID |

## 在线支付 (`payments`)

发起在线充值:建一张待支付订单并向支付网关预下单,返回付款地址。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/payments

### POST `/api/v2/payments/{provider}/orders`

发起在线支付 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | integer | 有 | 充值金额(分)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/payments/{provider}/orders" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

在线支付对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount_cents` | integer | 有 | 充值金额(分)。 |
| `gateway` | string |  | 实际下单的支付网关。 可选值: ["alipay","wxpay","codepay","epay"] |
| `mch_order_no` | string |  | 商户订单号(网关侧的订单号)。 |
| `order_id` | integer |  | 待支付订单 ID。 |
| `pay_url` | string |  | 付款地址:跳转网址,或微信 weixin:// 与支付宝当面付的二维码串。 |

## 充值方式 (`payment-methods`)

当前可用的在线支付方式、默认方式与转账说明,充值页据此渲染。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/payment-methods

### GET `/api/v2/payment-methods`

可用的充值方式 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/payment-methods" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

充值方式对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_method` | string |  | 默认选中的支付方式;空表示未指定。 |
| `methods` | string[] |  | 已开启的在线支付方式。 |
| `transfer` | PaymentTransfer |  | 线下转账设置。 |

## 支付通道 (`payment-channels`)

管理员配置支付方式走哪家网关及各网关商户参数;密钥只写不回显。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/payment-channels

### GET `/api/v2/payment-channels`

支付通道设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/payment-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/payment-channels`

修改支付通道 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `alipay` | AlipayGateway |  | 支付宝网关的商户参数。 |
| `codepay` | CodepayGateway |  | 码支付网关的商户参数。 |
| `default_method` | string |  | 充值页默认选中的方式;transfer = 转账汇款(须已开启转账)。 可选值: ["","alipay","wxpay","transfer"] |
| `epay` | EpayGateway |  | 易支付网关的商户参数。 |
| `methods` | PaymentMethodSet |  | 各在线支付方式的开关与所走网关。 |
| `notify_base` | string |  | 面板对网关可达的根地址(如 https://panel.example.com);回调地址由它拼出,空 = 不能下单。 |
| `return_url` | string |  | 付款后跳回的页面(支付宝电脑网站支付、易支付用);空 = 不跳。 |
| `transfer` | PaymentTransfer |  | 线下转账设置。 |
| `wxpay` | WxpayGateway |  | 微信支付网关的商户参数。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/payment-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

支付通道对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `alipay` | AlipayGateway |  | 支付宝网关的商户参数。 |
| `codepay` | CodepayGateway |  | 码支付网关的商户参数。 |
| `default_method` | string |  | 充值页默认选中的方式;transfer = 转账汇款(须已开启转账)。 可选值: ["","alipay","wxpay","transfer"] |
| `epay` | EpayGateway |  | 易支付网关的商户参数。 |
| `methods` | PaymentMethodSet |  | 各在线支付方式的开关与所走网关。 |
| `notify_base` | string |  | 面板对网关可达的根地址(如 https://panel.example.com);回调地址由它拼出,空 = 不能下单。 |
| `return_url` | string |  | 付款后跳回的页面(支付宝电脑网站支付、易支付用);空 = 不跳。 |
| `transfer` | PaymentTransfer |  | 线下转账设置。 |
| `wxpay` | WxpayGateway |  | 微信支付网关的商户参数。 |

## 支付回调 (`payment-notifications`)

支付网关调用的结果通知入口,无需认证,按网关规则验签后入账,重复通知只入账一次。

鉴权: 无需鉴权 · 文档: https://www-demo.kuxitong.com/zh/docs/api/payment-notifications

### GET `/api/v2/payment-notifications/{gateway}`

支付结果回调(GET) · 鉴权: 无需鉴权

```sh
curl "https://panel.example.com/api/v2/payment-notifications/{gateway}"
```

### POST `/api/v2/payment-notifications/{gateway}`

支付结果回调 · 鉴权: 无需鉴权

```sh
curl -X POST "https://panel.example.com/api/v2/payment-notifications/{gateway}"
```

## DNS 服务商 (`dns-providers`)

仅管理员。保存 DNS 服务商账号(阿里云、Cloudflare 等);保存前在线校验凭据,凭据只回末 4 位提示。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/dns-providers

### GET `/api/v2/dns-providers`

列出DNS 服务商 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `type` | string |  | 只列该服务商类型(如 aliyun)。 |

```sh
curl "https://panel.example.com/api/v2/dns-providers" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/dns-providers`

创建DNS 服务商 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth_id` | string |  | 凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。 |
| `auth_key` | string |  | 凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `gateway` | string |  | 自建 API 网关地址(只有 dnsdun 用)。 |
| `name` | string | 有 | 名称 |
| `remark` | string |  | 备注 |
| `ttl` | integer |  | 本账号下记录的默认 TTL(秒)。 |
| `type` | string | 有 | 服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。 |

```sh
curl -X POST "https://panel.example.com/api/v2/dns-providers" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auth_id":"LTAI-example","auth_key":"${DNS_AUTH_KEY}","name":"main-aliyun","ttl":120,"type":"aliyun"}'
```

### GET `/api/v2/dns-providers/{id}`

获取DNS 服务商 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/dns-providers/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/dns-providers/{id}`

修改DNS 服务商 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth_id` | string |  | 凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。 |
| `auth_key` | string |  | 凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `gateway` | string |  | 自建 API 网关地址(只有 dnsdun 用)。 |
| `name` | string | 有 | 名称 |
| `remark` | string |  | 备注 |
| `ttl` | integer |  | 本账号下记录的默认 TTL(秒)。 |
| `type` | string | 有 | 服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/dns-providers/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auth_id":"LTAI-example","auth_key":"${DNS_AUTH_KEY}","name":"main-aliyun","ttl":120,"type":"aliyun"}'
```

### DELETE `/api/v2/dns-providers/{id}`

删除DNS 服务商 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/dns-providers/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/dns-providers/{id}/lines`

拉取DNS 服务商线路 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `domain` | string | 有 | 根域,如 example.com。 |

```sh
curl "https://panel.example.com/api/v2/dns-providers/{id}/lines" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

DNS 服务商对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth_id` | string |  | 凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。 |
| `auth_key` | string |  | 凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。 |
| `auth_key_hint` | string |  | 凭据末 4 位(前面以 * 补齐),不回原文。 |
| `created_at` | string |  | 创建时间 (只读) |
| `default_line` | string |  | 该服务商默认线路的 id。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `gateway` | string |  | 自建 API 网关地址(只有 dnsdun 用)。 |
| `id` | integer |  | 记录 ID (只读) |
| `items` | DnsLine[] |  | 本页条目 |
| `lines` | DnsLine[] |  | 最近一次拉取的线路树缓存(GET /dns-providers/{id}/lines 刷新);未拉取为空数组。 |
| `name` | string |  | 名称 |
| `remark` | string |  | 备注 |
| `ttl` | integer |  | 本账号下记录的默认 TTL(秒)。 |
| `type` | string |  | 服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。 |
| `updated_at` | string |  | 更新时间 (只读) |

## CNAME 接入域名 (`cname-domains`)

仅管理员。用于生成 CNAME 接入名的根域,归属某个 DNS 服务商账号;支持整体更换到新根域并核对客户是否已改解析。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/cname-domains

### GET `/api/v2/cname-domains`

列出CNAME 接入域名 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `domain` | string |  | 只列根域包含该串的(部分匹配,不分大小写,首尾空格与结尾的点忽略)。 |
| `type` | string |  | 只列归属该服务商类型(如 aliyun)的。 |
| `dns_provider_id` | integer |  | 只列归属该账号的。 |
| `status` | CnameDomainStatus |  | 只列该状态的。 可选值: ["active","retiring"] |

```sh
curl "https://panel.example.com/api/v2/cname-domains" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cname-domains`

创建CNAME 接入域名 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dns_provider_id` | integer | 有 | 托管该根域的服务商账号 id。 |
| `domain` | string | 有 | 小写根域,如 cdn.example.com。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `expire_at` | string |  | 管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。 |
| `remark` | string |  | 备注 |
| `status` | CnameDomainStatus |  | active 使用中;retiring 停用中(已更换走,不再给套餐选)。 可选值: ["active","retiring"] |

```sh
curl -X POST "https://panel.example.com/api/v2/cname-domains" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dns_provider_id":1,"domain":"cdn.example.com","expire_at":"2027-01-31","remark":"主接入域名"}'
```

### PUT `/api/v2/cname-domains/status`

批量设置CNAME 接入域名状态 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | integer[] | 有 | 要设置状态的接入域名 id 列表。 |
| `status` | CnameDomainStatus | 有 | active 使用中;retiring 停用中(已更换走,不再给套餐选)。 可选值: ["active","retiring"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/cname-domains/status" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids":[1],"status":"retiring"}'
```

### GET `/api/v2/cname-domains/{id}`

获取CNAME 接入域名 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/cname-domains/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cname-domains/{id}`

修改CNAME 接入域名 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dns_provider_id` | integer | 有 | 托管该根域的服务商账号 id。 |
| `domain` | string | 有 | 小写根域,如 cdn.example.com。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `expire_at` | string |  | 管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。 |
| `remark` | string |  | 备注 |
| `status` | CnameDomainStatus |  | active 使用中;retiring 停用中(已更换走,不再给套餐选)。 可选值: ["active","retiring"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/cname-domains/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dns_provider_id":1,"domain":"cdn.example.com","expire_at":"2027-01-31","remark":"主接入域名"}'
```

### DELETE `/api/v2/cname-domains/{id}`

删除CNAME 接入域名 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `local_only` | boolean |  | 为 true 时只删本平台记录,不去服务商侧清该根域下的旧解析(面板「仅删除本地记录」)。 |

```sh
curl -X DELETE "https://panel.example.com/api/v2/cname-domains/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cname-domains/{id}/migrate`

整体更换CNAME 接入域名 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `notify` | boolean |  | 是否给受影响客户发站内信。 默认: true |
| `retire` | boolean |  | 是否把旧域名置为停用中。 默认: true |
| `target_id` | integer | 有 | 目标根域 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cname-domains/{id}/migrate" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/cname-domains/{id}/refs`

查CNAME 接入域名的引用 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/cname-domains/{id}/refs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/cname-domains/{id}/switch-check`

查更换后的切换核对 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `state` | CnameSwitchState |  | 只列该核对状态的。 可选值: ["changed","unchanged","not_cname","failed","pending"] |
| `q` | string |  | 模糊匹配客户名、网站域名或实际解析。 |

```sh
curl "https://panel.example.com/api/v2/cname-domains/{id}/switch-check" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/cname-domains/{id}/switch-check/export`

导出切换核对对照表 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `state` | CnameSwitchState |  | 只列该核对状态的。 可选值: ["changed","unchanged","not_cname","failed","pending"] |
| `q` | string |  | 模糊匹配客户名、网站域名或实际解析。 |

```sh
curl "https://panel.example.com/api/v2/cname-domains/{id}/switch-check/export" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cname-domains/{id}/switch-check/remind`

提醒未改的客户 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/cname-domains/{id}/switch-check/remind" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cname-domains/{id}/switch-check/run`

立即核对 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/cname-domains/{id}/switch-check/run" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

CNAME 接入域名对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `actual` | string |  | 实际解析到的(CNAME 目标或 IP);查询失败时为原因(NXDOMAIN、Timeout…)。 |
| `changed` | integer |  | 重查后已改的行数。 |
| `check_rows` | integer |  | 新建的核对行数(每个网站域名一行)。 |
| `checked` | integer |  | 本次重查的行数。 |
| `checked_at` | string |  | 最近一次解析检查时间。 |
| `created_at` | string |  | 创建时间 (只读) |
| `dns_provider_id` | integer |  | 托管该根域的服务商账号 id。 |
| `domain` | string |  | 小写根域,如 cdn.example.com。 |
| `example_hostname` | string |  | 一个现有接入名(不含根域),向导里拼新旧接入地址示例用。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `expire_at` | string |  | 管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。 |
| `failed` | integer |  | 查询失败的行数。 |
| `from` | string |  | 原根域。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 要设置状态的接入域名 id 列表。 |
| `messaged` | integer |  | 发了站内信的客户数。 |
| `new_target` | string |  | 切换后的 CNAME 目标。 |
| `not_cname` | integer |  | 非 CNAME 接入的行数。 |
| `notified_at` | string |  | 通知客户的时间。 |
| `notify` | boolean |  | 是否给受影响客户发站内信。 默认: true |
| `old_target` | string |  | 切换前的 CNAME 目标。 |
| `package` | integer |  | 切走的套餐接入名数。 |
| `package_list` | string[] |  | 前 20 个引用本根域的用户套餐。 |
| `provider_name` | string |  | 归属账号名称。 |
| `provider_type` | string |  | 归属账号的服务商类型。 |
| `remark` | string |  | 备注 |
| `retire` | boolean |  | 是否把旧域名置为停用中。 默认: true |
| `site` | integer |  | 切走的站点接入名数。 |
| `site_id` | integer |  | 网站 ID |
| `site_list` | string[] |  | 切走的站点接入名清单。 |
| `skipped` | object[] |  | 被跳过的接入域名及原因。 |
| `state` | CnameSwitchState |  | changed 已改;unchanged 未改;not_cname 非 CNAME 接入(指向别处或只有 A 记录);failed 查询失败;pending 待核对。 可选值: ["changed","unchanged","not_cname","failed","pending"] |
| `status` | CnameDomainStatus |  | active 使用中;retiring 停用中(已更换走,不再给套餐选)。 可选值: ["active","retiring"] |
| `stream` | integer |  | 切走的四层转发接入名数。 |
| `stream_list` | string[] |  | 前 20 个四层转发(id:<id> <接入名>)。 |
| `switched_at` | string |  | 整体更换发生的时间;未更换为空。 |
| `switched_to` | integer |  | 整体更换到的根域 id。 |
| `switched_to_domain` | string |  | 更换到的根域名称;未更换为空。 |
| `target_id` | integer | 有 | 目标根域 id。 |
| `tenant_id` | integer |  | 所属租户(用户)ID |
| `to` | string |  | 目标根域。 |
| `unchanged` | integer |  | 仍未改的行数。 |
| `updated` | integer |  | 实际更新的个数。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `user_list` | string[] |  | 受影响的客户清单。 |
| `user_name` | string |  | 客户(租户)名;租户已删为空。 |
| `users` | integer |  | 受影响客户数(站点所属租户去重)。 |

## 解析同步 (`dns-sync`)

仅管理员。让调度器立刻按期望解析全量对账一次(面板「记录修复」)。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/dns-sync

### POST `/api/v2/dns-sync`

立即同步解析 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/dns-sync" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

## 区域 (`regions`)

节点所属的地理区域,用于给节点和节点组归类。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/regions

### GET `/api/v2/regions`

列出区域 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/regions" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/regions`

创建区域 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |

```sh
curl -X POST "https://panel.example.com/api/v2/regions" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/regions/{id}`

获取区域 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/regions/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/regions/{id}`

修改区域 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string |  | 名称 |

```sh
curl -X PUT "https://panel.example.com/api/v2/regions/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"des":"east"}'
```

### DELETE `/api/v2/regions/{id}`

删除区域 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/regions/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

区域对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `updated_at` | string |  | 更新时间 (只读) |

## 节点 (`nodes`)

已审核的边缘节点与子 IP;主节点经注册令牌自助注册,子 IP 由管理员手工添加。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/nodes

### GET `/api/v2/nodes`

列出节点 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/nodes" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/nodes`

创建节点 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `area` | string |  | 地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。 |
| `bandwidth_mbps` | integer |  | 节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `ip` | string |  | 节点 IP 地址(IPv4 或 IPv6)。 |
| `monitor` | NodeMonitor |  | 节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。 |
| `name` | string | 有 | 名称 |
| `parent_id` | integer |  | 子 IP 所属主节点;null = 主节点。 |
| `region_id` | integer |  | 区域 ID |
| `service_expire` | string |  | 服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。 |
| `service_start` | string |  | 服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。 |

```sh
curl -X POST "https://panel.example.com/api/v2/nodes" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ip":"192.0.2.20","name":"edge-1-ip2","parent_id":1}'
```

### GET `/api/v2/nodes/{id}`

获取节点 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `capacity` | boolean |  | 为 true 时附带 capacity(主节点才有;没有系统信息时为 null)。 |

```sh
curl "https://panel.example.com/api/v2/nodes/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/nodes/{id}`

修改节点 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `area` | string |  | 地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。 |
| `bandwidth_mbps` | integer |  | 节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `ip` | string |  | 节点 IP 地址(IPv4 或 IPv6)。 |
| `monitor` | NodeMonitor |  | 节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。 |
| `name` | string |  | 名称 |
| `parent_id` | integer |  | 子 IP 所属主节点;null = 主节点。 |
| `region_id` | integer |  | 区域 ID |
| `service_expire` | string |  | 服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。 |
| `service_start` | string |  | 服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/nodes/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"bandwidth_mbps":30}'
```

### DELETE `/api/v2/nodes/{id}`

删除节点 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/nodes/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/nodes/{id}/config-readmit`

重新下发被节点回滚的配置 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/nodes/{id}/config-readmit" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/nodes/{id}/local-addrs`

节点网卡地址 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/nodes/{id}/local-addrs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/nodes/{id}/to-pending`

节点移回待初始化 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/nodes/{id}/to-pending" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

节点对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `area` | string |  | 地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。 |
| `bandwidth_mbps` | integer |  | 节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。 |
| `capacity` | NodeCapacity |  | 节点内存容量(只读,只在 GET /nodes/{id}?capacity=true 给出):单站常驻 = location 数 × 28.1KB + https 占比 × 25.5KB,预算 = 内存 MiB × 0.25 / 2 − 28MiB,上限 = 预算 / 单站。null = 没有该节点的系统信息或缺内存总量。 (只读) |
| `cert_expiry` | string |  | 最近一次签发证书的到期时刻;null = 还没领过证(或子 IP)。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `disable_by` | string |  | 停用来源(manual = 管理员;monitor = 节点监控自动停用,探测恢复后自动启用;bandwidth = 出站带宽超过 monitor.bw_limit_mbps 自动停用,回落后自动启用);启用时为空。 |
| `enabled` | boolean |  | 是否启用 |
| `enrolled_at` | string |  | 节点注册时刻;手工添加的子 IP 为 null。 |
| `hints` | string[] |  | 提示(如取不到网卡地址)。 |
| `hostname` | string |  | 节点主机名,注册时上报。 |
| `id` | integer |  | 记录 ID (只读) |
| `ip` | string |  | 节点 IP 地址(IPv4 或 IPv6)。 |
| `monitor` | NodeMonitor |  | 节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。 |
| `name` | string |  | 名称 |
| `ops` | NodeOps |  | 节点运维状态(只读,来自心跳):在线、配置是否落后于最新已发布版本、时钟是否同步。子 IP 跟随主节点。 (只读) |
| `parent_id` | integer |  | 子 IP 所属主节点;null = 主节点。 |
| `region_id` | integer |  | 区域 ID |
| `role` | string |  | 节点角色:edge 边缘节点;l2 二级缓存节点。 可选值: ["edge","l2"] |
| `service_expire` | string |  | 服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。 |
| `service_start` | string |  | 服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。 |
| `status` | string |  | ok = 有结果;pending = 已排指令,稍后再取;unknown = 节点不在线。 可选值: ["ok","pending","unknown"] |
| `updated_at` | string |  | 更新时间 (只读) |
| `v4` | string[] |  | 节点网卡上的 IPv4 地址。 |
| `v6` | string[] |  | 节点网卡上的 IPv6 地址。 |

## 待接入节点 (`pending-nodes`)

已用令牌注册、等待管理员审核的节点;审核通过后成为正式节点。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/pending-nodes

### GET `/api/v2/pending-nodes`

列出待接入节点 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/pending-nodes" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/pending-nodes/{id}`

删除待接入节点 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/pending-nodes/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/pending-nodes/{id}/approve`

审核通过待接入节点 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `ip` | string |  | 注册连接的来源地址。 |
| `name` | string |  | 名称 |
| `region_id` | integer |  | 区域 ID |
| `replace_node_id` | integer |  | 替换已有主节点(新机顶替旧机):新节点继承旧节点的线路、IP 池里的 IP、区域(没给 region_id 时)、监控设置、服务期与地区/带宽,旧节点停用并从解析摘除,与审核同一事务。旧节点的子 IP 默认一并改挂新节点(线路、池内 IP、监控设置不变),地址与不迁见 replace_sub_ips。旧节点须是已审主节点、角色相同;池内 IP 被 IP 站点绑定且 IP 变了时 409 ip_in_use。 |
| `replace_sub_ips` | ReplaceSubIp[] |  | 替换时逐条指定旧节点子 IP 的去向(只在给了 replace_node_id 时有效);没列出的子 IP 沿用原地址改挂新节点。ip 给了就改用新地址(已被别的节点用 422 conflict),skip 为 true 的不迁:该子 IP 及其线路随旧节点停用。 |

```sh
curl -X POST "https://panel.example.com/api/v2/pending-nodes/{id}/approve" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

待接入节点对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `area` | string |  | 地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。 |
| `bandwidth_mbps` | integer |  | 节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。 |
| `capacity` | NodeCapacity |  | 节点内存容量(只读,只在 GET /nodes/{id}?capacity=true 给出):单站常驻 = location 数 × 28.1KB + https 占比 × 25.5KB,预算 = 内存 MiB × 0.25 / 2 − 28MiB,上限 = 预算 / 单站。null = 没有该节点的系统信息或缺内存总量。 (只读) |
| `cert_expiry` | string |  | 最近一次签发证书的到期时刻;null = 还没领过证(或子 IP)。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `disable_by` | string |  | 停用来源(manual = 管理员;monitor = 节点监控自动停用,探测恢复后自动启用;bandwidth = 出站带宽超过 monitor.bw_limit_mbps 自动停用,回落后自动启用);启用时为空。 |
| `enabled` | boolean |  | 是否启用 |
| `enrolled_at` | string |  | 节点注册时间。 |
| `hostname` | string |  | 节点上报的主机名。 |
| `id` | integer |  | 记录 ID (只读) |
| `ip` | string |  | 注册连接的来源地址。 |
| `monitor` | NodeMonitor |  | 节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。 |
| `name` | string |  | 名称 |
| `ops` | NodeOps |  | 节点运维状态(只读,来自心跳):在线、配置是否落后于最新已发布版本、时钟是否同步。子 IP 跟随主节点。 (只读) |
| `parent_id` | integer |  | 子 IP 所属主节点;null = 主节点。 |
| `region_id` | integer |  | 区域 ID |
| `replace_node_id` | integer |  | 替换已有主节点(新机顶替旧机):新节点继承旧节点的线路、IP 池里的 IP、区域(没给 region_id 时)、监控设置、服务期与地区/带宽,旧节点停用并从解析摘除,与审核同一事务。旧节点的子 IP 默认一并改挂新节点(线路、池内 IP、监控设置不变),地址与不迁见 replace_sub_ips。旧节点须是已审主节点、角色相同;池内 IP 被 IP 站点绑定且 IP 变了时 409 ip_in_use。 |
| `replace_sub_ips` | ReplaceSubIp[] |  | 替换时逐条指定旧节点子 IP 的去向(只在给了 replace_node_id 时有效);没列出的子 IP 沿用原地址改挂新节点。ip 给了就改用新地址(已被别的节点用 422 conflict),skip 为 true 的不迁:该子 IP 及其线路随旧节点停用。 |
| `role` | string |  | 节点角色:edge 边缘;l2 二级。 可选值: ["edge","l2"] |
| `service_expire` | string |  | 服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。 |
| `service_start` | string |  | 服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 节点接入令牌 (`node-enroll-tokens`)

生成一次性注册令牌与节点一行安装命令;令牌原文只在生成时返回一次。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/node-enroll-tokens

### POST `/api/v2/node-enroll-tokens`

生成节点接入令牌 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/node-enroll-tokens" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

节点接入令牌对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `command` | string |  | 节点一行安装命令;没配物料站或主控钥未初始化时为一句说明。 |
| `expires_at` | string |  | 过期时间 |
| `token` | string |  | 一次性注册令牌原文,只在本次响应里出现。 |

## 节点分组 (`node-groups`)

把线路编成组并对应一个接入名;可设置备用阈值,可用线路不足时自动切到备用组。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/node-groups

### GET `/api/v2/node-groups`

列出节点分组 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `ids` | string |  | 只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。 |

```sh
curl "https://panel.example.com/api/v2/node-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/node-groups`

创建节点分组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_interval_s` | integer |  | interval 方式的轮换间隔(秒)。 |
| `backup_ip_num` | integer |  | interval 方式每轮在用的备用 IP 数。 |
| `backup_min_online` | integer |  | 组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。 |
| `backup_switch_order` | BackupSwitchOrder |  | interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。 可选值: ["seq","rand"] |
| `backup_switch_type` | BackupSwitchType |  | 备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。 可选值: ["master_down","gt_online_ip","interval"] |
| `cname_hostname` | string |  | 接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。 |
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `region_id` | integer |  | 区域 ID |

```sh
curl -X POST "https://panel.example.com/api/v2/node-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/node-groups/{id}`

获取节点分组 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/node-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/node-groups/{id}`

修改节点分组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_interval_s` | integer |  | interval 方式的轮换间隔(秒)。 |
| `backup_ip_num` | integer |  | interval 方式每轮在用的备用 IP 数。 |
| `backup_min_online` | integer |  | 组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。 |
| `backup_switch_order` | BackupSwitchOrder |  | interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。 可选值: ["seq","rand"] |
| `backup_switch_type` | BackupSwitchType |  | 备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。 可选值: ["master_down","gt_online_ip","interval"] |
| `cname_hostname` | string |  | 接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。 |
| `des` | string |  | 备注说明 |
| `name` | string |  | 名称 |
| `region_id` | integer |  | 区域 ID |

```sh
curl -X PUT "https://panel.example.com/api/v2/node-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"backup_min_online":2}'
```

### DELETE `/api/v2/node-groups/{id}`

删除节点分组 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/node-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

节点分组对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_active` | boolean |  | 已被监控自动切到备用组(可用线路回到阈值后自动切回)。 (只读) |
| `backup_interval_s` | integer |  | interval 方式的轮换间隔(秒)。 |
| `backup_ip_num` | integer |  | interval 方式每轮在用的备用 IP 数。 |
| `backup_min_online` | integer |  | 组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。 |
| `backup_switch_order` | BackupSwitchOrder |  | interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。 可选值: ["seq","rand"] |
| `backup_switch_type` | BackupSwitchType |  | 备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。 可选值: ["master_down","gt_online_ip","interval"] |
| `backup_switched` | string |  | 最近一次自动切换/切回的时刻。 (只读) |
| `cname_domains` | string[] |  | 指向本组的接入名(主机记录.根域),按字母序;没有被引用为空数组。 (只读) |
| `cname_hostname` | string |  | 接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `node_count` | integer |  | 组里线路引用的不同节点 IP 数。 (只读) |
| `region_id` | integer |  | 区域 ID |
| `site_count` | integer |  | 接入名指向本组的网站数。 (只读) |
| `stream_count` | integer |  | 接入名指向本组的四层转发数。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## 线路 (`lines`)

节点组里的一条解析记录:节点按哪条 DNS 解析线路、多少权重出现在组里;删除前须先停用。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/lines

### GET `/api/v2/lines`

列出线路 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/lines" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/lines`

创建线路 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dns_line` | string |  | DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。 |
| `enabled` | boolean |  | 是否启用 |
| `force` | boolean |  | 强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。 |
| `is_backup` | boolean |  | 备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。 |
| `is_backup_default` | boolean |  | 备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。 |
| `node_group_id` | integer | 有 | 所属节点组的 id。 |
| `node_id` | integer | 有 | 节点 ID |
| `weight` | integer |  | 权重,1 到 100,越大分到的解析越多。 |

```sh
curl -X POST "https://panel.example.com/api/v2/lines" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dns_line":"default","node_group_id":1,"node_id":1,"weight":1}'
```

### GET `/api/v2/lines/{id}`

获取线路 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/lines/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/lines/{id}`

修改线路 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dns_line` | string |  | DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。 |
| `enabled` | boolean |  | 是否启用 |
| `force` | boolean |  | 强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。 |
| `is_backup` | boolean |  | 备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。 |
| `is_backup_default` | boolean |  | 备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。 |
| `node_group_id` | integer |  | 所属节点组的 id。 |
| `node_id` | integer |  | 节点 ID |
| `weight` | integer |  | 权重,1 到 100,越大分到的解析越多。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/lines/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'
```

### DELETE `/api/v2/lines/{id}`

删除线路 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/lines/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

线路对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_default_on` | boolean |  | 备用默认解析当前已启用、正按默认线路解析(只读,由定时任务维护)。 (只读) |
| `backup_on` | boolean |  | 备用 IP 当前已启用进解析(只读,由定时任务维护)。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `disable_by` | string |  | 停用来源(manual 管理员手工、monitor 节点监控、bandwidth 带宽超限等);启用时为空。 |
| `dns_line` | string |  | DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。 |
| `enabled` | boolean |  | 是否启用 |
| `force` | boolean |  | 强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。 |
| `id` | integer |  | 记录 ID (只读) |
| `is_backup` | boolean |  | 备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。 |
| `is_backup_default` | boolean |  | 备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。 |
| `node_group_id` | integer |  | 所属节点组的 id。 |
| `node_id` | integer |  | 节点 ID |
| `updated_at` | string |  | 更新时间 (只读) |
| `weight` | integer |  | 权重,1 到 100,越大分到的解析越多。 |

## 告警规则 (`alert-rules`)

主控内置的统一告警规则及其当前设置与状态;阈值通过系统设置修改。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/alert-rules

### GET `/api/v2/alert-rules`

列出告警规则与当前状态 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/alert-rules" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

告警规则对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | AlertRule[] |  | 本页条目 |

## 告警记录 (`alerts`)

最近的告警与恢复记录,保留 30 天。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/alerts

### GET `/api/v2/alerts`

列出最近告警与恢复记录 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `rule` | string |  | 按规则名过滤。 |
| `kind` | AlertKind |  | 按种类过滤:fire 告警;resolve 恢复。 可选值: ["fire","resolve"] |

```sh
curl "https://panel.example.com/api/v2/alerts" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

告警记录对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 |
| `detail` | string |  | 补充说明。 |
| `id` | integer |  | 记录 ID |
| `kind` | AlertKind |  | fire 告警;resolve 恢复。 可选值: ["fire","resolve"] |
| `msg_id` | integer |  | 发出的通知(站内信 id)。 |
| `rule` | string |  | 告警规则标识。 |
| `subject` | string |  | 告警针对的对象,如节点或站点。 |
| `threshold` | number |  | 规则的阈值。 |
| `title` | string |  | 规则中文名(规则已不在表里时同 rule)。 |
| `unit` | string |  | 数值与阈值的单位。 |
| `value` | number |  | 触发告警的当前值。 |

## 节点监控日志 (`monitor-logs`)

主控对开启监控的节点 IP 每轮探测的结果记录。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/monitor-logs

### GET `/api/v2/monitor-logs`

列出节点监控探测日志 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `node_id` | integer |  | 按节点过滤。 |
| `ip` | string |  | 按 IP 过滤(精确匹配)。 |
| `result` | integer |  | 按结果过滤:1 通;0 不通;-1 判不了。 可选值: [-1,0,1] |
| `type` | string |  | 按类型过滤:aval 可用性探测;bw 带宽采样。不给 = 全部。 可选值: ["aval","bw"] |
| `probe_group` | string |  | 按监控组过滤(外部探测服务回的监控组,精确匹配);空串 = 主控内建探测的行。不给 = 全部。 |
| `since` | string |  | 起始时间(含),RFC 3339。 |
| `until` | string |  | 截止时间(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/monitor-logs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

节点监控日志对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 |
| `detail` | string |  | 不通/判不了的原因。 |
| `id` | integer |  | 记录 ID |
| `ip` | string |  | 被探测的 IP。 |
| `node_id` | integer |  | 节点 ID |
| `result` | integer |  | 1 通;0 不通;-1 判不了(http 5xx、整轮全不通等,不参与判定)。 可选值: [-1,0,1] |
| `round_id` | integer |  | 探测轮次(同一轮同值)。 |
| `type` | string |  | aval 可用性探测(主控或外部探测服务);bw 带宽采样(每分钟一条,出站不低于上限记 0)。 可选值: ["aval","bw"] |

## IP 池 (`ip-pools`)

管理员维护的 IP 池及池内 IP;池按区域归属,名称全平台唯一。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/ip-pools

### GET `/api/v2/ip-pools`

列出 IP 池 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `region_id` | integer |  | 按区域过滤。 |

```sh
curl "https://panel.example.com/api/v2/ip-pools" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/ip-pools`

创建 IP 池 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `region_id` | integer | 有 | 区域 ID |

```sh
curl -X POST "https://panel.example.com/api/v2/ip-pools" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-pools/candidates`

IP 池候选节点 IP · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `region_id` | integer | 有 | 区域 ID。 |

```sh
curl "https://panel.example.com/api/v2/ip-pools/candidates" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-pools/{id}`

获取 IP 池 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/ip-pools/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/ip-pools/{id}`

修改 IP 池 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `region_id` | integer | 有 | 区域 ID |

```sh
curl -X PUT "https://panel.example.com/api/v2/ip-pools/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/ip-pools/{id}`

删除 IP 池 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/ip-pools/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-pools/{id}/refs`

IP 池引用站点 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ip_id` | integer |  | 只看这个池内 IP。 |
| `limit` | integer |  | 每个 IP 最多列几个站点。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/ip-pools/{id}/refs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-pools/{pool_id}/ips`

列出池内 IP · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/ip-pools/{pool_id}/ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/ip-pools/{pool_id}/ips`

IP 入池 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `bind_addr` | string |  | 节点上实际监听的本机地址(NAT 场景);null = 用 ip。 |
| `node_id` | integer | 有 | 节点 ID |

```sh
curl -X POST "https://panel.example.com/api/v2/ip-pools/{pool_id}/ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/ip-pools/{pool_id}/ips/{id}`

修改池内 IP · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `bind_addr` | string |  | 节点上实际监听的本机地址(NAT 场景);null = 用 ip。 |
| `enabled` | boolean |  | 是否启用 |

```sh
curl -X PUT "https://panel.example.com/api/v2/ip-pools/{pool_id}/ips/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/ip-pools/{pool_id}/ips/{id}`

IP 出池 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/ip-pools/{pool_id}/ips/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/ip-pools/{pool_id}/ips/{id}/issue-cert`

签发池内 IP 的平台证书 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `confirm` | boolean |  | 已有有效证书时确认重签。 |

```sh
curl -X POST "https://panel.example.com/api/v2/ip-pools/{pool_id}/ips/{id}/issue-cert" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

IP 池对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `bind_addr` | string |  | 节点上实际监听的本机地址(NAT 场景);null = 用 ip。 |
| `cert` | IpCertState |  | 平台 IP 证书状态。 |
| `confirm` | boolean |  | 已有有效证书时确认重签。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `hints` | string[] |  | 提示(如节点没上报网卡地址,入池未核对)。 (只读) |
| `id` | integer |  | 记录 ID (只读) |
| `ip` | string |  | IP 地址。 (只读) |
| `ip_count` | integer |  | 池内 IP 数。 (只读) |
| `ips` | object[] |  | 有引用的池内 IP 及其引用站点。 |
| `items` | IpCandidate[] |  | 本页条目 |
| `name` | string |  | 名称 |
| `node_id` | integer |  | 节点 ID |
| `node_name` | string |  | 所属节点名称。 (只读) |
| `node_state` | IpNodeState |  | 持有主节点状态:停用 disabled;否则最近 2 分钟有心跳 online,没有 offline。 可选值: ["online","offline","disabled"] |
| `pool_id` | integer |  | 所属 IP 池 ID。 (只读) |
| `region_id` | integer |  | 区域 ID |
| `region_name` | string |  | 区域名称。 (只读) |
| `site_count` | integer |  | 引用池内 IP 的 IP 站点数(按站点去重)。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## IP 站点 (`ip-sites`)

用 IP 加自定义端口对外提供加速的站点;须先在用户套餐里选好 IP。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/ip-sites

### GET `/api/v2/ip-sites`

列出 IP 站点 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `upid` | integer |  | 按用户套餐过滤。 |

```sh
curl "https://panel.example.com/api/v2/ip-sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/ip-sites`

创建 IP 站点 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `config` | object |  | 节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。 |
| `enabled` | boolean |  | 是否启用 |
| `ip_ids` | integer[] |  | 绑定的池内 IP id(按次序)。 |
| `name` | string |  | 名称 |
| `origins` | IpSiteOrigin[] |  | 源站列表。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `upid` | integer |  | 用户套餐 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/ip-sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-sites/available-ips`

IP 站点可选 IP · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `upid` | integer | 有 | 用户套餐 ID。 |
| `scope` | string |  | pool 整池;mine 只列已选。 可选值: ["pool","mine"] 默认: "pool" |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/ip-sites/available-ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/ip-sites/port-check`

IP 站点端口预检 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `http_ports` | integer[] |  | 要检查的 HTTP 端口列表;超出 1~65535 的不拒,结果里标 range。 |
| `https_ports` | integer[] |  | 要检查的 HTTPS 端口列表;超出 1~65535 的不拒,结果里标 range。 |
| `ip_ids` | integer[] | 有 | 绑定的池内 IP id(按次序)。 |
| `site_id` | integer |  | 改站时给:本站自己占的不算占用。 |
| `upid` | integer | 有 | 用户套餐 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/ip-sites/port-check" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/ip-sites/{id}`

获取 IP 站点 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/ip-sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/ip-sites/{id}`

修改 IP 站点 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `config` | object |  | 节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。 |
| `enabled` | boolean |  | 是否启用 |
| `ip_ids` | integer[] |  | 绑定的池内 IP id(按次序)。 |
| `name` | string |  | 名称 |
| `origins` | IpSiteOrigin[] |  | 源站列表。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `upid` | integer |  | 用户套餐 id。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/ip-sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/ip-sites/{id}`

删除 IP 站点 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/ip-sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

IP 站点对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `access_addrs` | string[] |  | 访问地址 ip:端口。 (只读) |
| `config` | object |  | 节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。 |
| `created_at` | string |  | 创建时间 (只读) |
| `enabled` | boolean |  | 是否启用 |
| `hints` | string[] |  | 提示(如节点没上报在听端口,跳过了该项检查)。 (只读) |
| `http_ports` | integer[] |  | 要检查的 HTTP 端口列表;超出 1~65535 的不拒,结果里标 range。 |
| `https_ports` | integer[] |  | 要检查的 HTTPS 端口列表;超出 1~65535 的不拒,结果里标 range。 |
| `id` | integer |  | 记录 ID (只读) |
| `ip_ids` | integer[] |  | 绑定的池内 IP id(按次序)。 |
| `ips` | IpSiteIp[] |  | 绑定的池内 IP 详情。 (只读) |
| `items` | AvailableIp[] |  | 本页条目 |
| `name` | string |  | 名称 |
| `origins` | IpSiteOrigin[] |  | 源站列表。 |
| `ports` | object[] |  | 逐端口检查结果。 |
| `site_id` | integer |  | 改站时给:本站自己占的不算占用。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `updated_at` | string |  | 更新时间 (只读) |
| `upid` | integer |  | 用户套餐 id。 |

## 证书 (`certs`)

上传或自动签发的 HTTPS 证书。可绑定到站点;有站点在用时不能删除或停用。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/certs

### GET `/api/v2/certs`

列出证书 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `name` | string |  | 名称包含。 |
| `domain` | string |  | SAN 包含(域名或 IP 的一部分)。 |
| `scope` | string |  | site = 站点证书;ip = 平台 IP 证书;panel = 面板证书(主控 HTTPS 监听用)。 可选值: ["site","ip","panel"] |
| `enabled` | boolean |  | 是否启用 |
| `expire_days` | integer |  | 只列 N 天内到期(含已过期)的证书。 |
| `id` | integer |  | 证书 id 精确匹配。 |
| `ids` | string |  | 多个证书 id 逗号分隔(至多 200 个),命中其中任一个。 |
| `des` | string |  | 备注包含。 |
| `type` | string |  | 证书类型。 可选值: ["custom","lets","zerossl","zerossl_api"] |
| `dns_api_id` | integer |  | 用此 DNS API 凭据的证书。 |
| `domains` | string |  | 多个域名或 IP,逗号分隔,证书 SAN 里含其中任一个(精确匹配)。 |
| `issue_state` | string |  | ACME 签发状态(上传的证书没有)。 可选值: ["pending","running","issued","failed"] |
| `kind` | string |  | domain = SAN 含域名;ip = SAN 全是 IP。 可选值: ["domain","ip"] |

```sh
curl "https://panel.example.com/api/v2/certs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs`

创建证书 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | 签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。 |
| `cert` | string |  | 证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `key` | string |  | 私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。 |
| `name` | string | 有 | 名称 |
| `scope` | string |  | 证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。 可选值: ["site","ip","panel"] |
| `type` | string |  | custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。 |

```sh
curl -X POST "https://panel.example.com/api/v2/certs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/acme-states`

批量查 ACME 签发状态 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | string | 有 | 证书 id,逗号分隔,至多 200 个。 |

```sh
curl "https://panel.example.com/api/v2/certs/acme-states" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs/batch`

批量申请 ACME 证书 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acme_account_id` | integer |  | 指定签发账号(同 POST /certs 的 acme.acme_account_id);不给按类型先取本租户启用的、再取平台启用的。 |
| `auto_renew` | boolean |  | 不给为 true。 |
| `des` | string |  | 备注说明 |
| `dns_api_id` | integer |  | DNS-01 验证用的 DNS API 凭据(ACME 证书用)。 |
| `items` | CertAcme[] | 有 | 签发状态。 |
| `type` | string |  | custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。 |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/batch" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"domains":["a.example.com"]},{"domains":["b.example.com","www.b.example.com"]}],"type":"lets"}'
```

### POST `/api/v2/certs/batch-issue`

批量重签或续签 ACME 证书 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | integer[] | 有 | 证书 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/batch-issue" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids":[1]}'
```

### GET `/api/v2/certs/zerossl-ips`

列出可签 ZeroSSL 证书的 IP · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/certs/zerossl-ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/{id}`

获取证书 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/certs/{id}`

修改证书 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | 签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。 |
| `cert` | string |  | 证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `key` | string |  | 私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。 |
| `name` | string | 有 | 名称 |
| `scope` | string |  | 证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。 可选值: ["site","ip","panel"] |
| `type` | string |  | custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/certs/{id}`

删除证书 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/{id}/acme`

获取证书的 ACME 签发状态 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/certs/{id}/acme" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/certs/{id}/acme`

修改证书的自动续签开关 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_renew` | boolean | 有 | 不给为 true。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/certs/{id}/acme" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auto_renew":false}'
```

### POST `/api/v2/certs/{id}/bind`

证书绑定到站点 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_ids` | integer[] | 有 | 在用此证书的站点。 |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/bind" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site_ids":[1]}'
```

### POST `/api/v2/certs/{id}/issue`

重新签发 ACME 证书 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/issue" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs/{id}/private-key`

导出证书私钥 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `password` | string |  | 当前登录口令。 |
| `totp_code` | string |  | 动态口令(TOTP)的 6 位当前码;账号须已启用动态口令。 |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/private-key" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

证书对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | 签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。 (只读) |
| `acme_account_id` | integer |  | 指定签发账号(同 POST /certs 的 acme.acme_account_id);不给按类型先取本租户启用的、再取平台启用的。 |
| `ari_end` | string |  | CA 经 ARI 建议的续签窗口结束时间。 |
| `ari_start` | string |  | CA 经 ARI 建议的续签窗口;null = CA 没给,按到期前 cert.acme.renew_before_days 天续签。 |
| `auto_renew` | boolean |  | 不给为 true。 |
| `cert` | string |  | 证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。 (只读) |
| `cert_id` | integer |  | 证书 id。 |
| `challenge` | string |  | 验证方式:http-01、dns-01,或 http-file(zerossl_api 的 ZeroSSL 文件验证)。 可选值: ["http-01","dns-01","http-file"] |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `dns_api_id` | integer |  | DNS-01 验证用的 DNS API 凭据(ACME 证书用)。 |
| `enabled` | boolean |  | 是否启用 |
| `err_times` | integer |  | 这一轮已失败次数。 |
| `failed` | integer |  | 失败的条数。 |
| `fingerprint` | string |  | 叶证书 SHA-256 指纹(小写十六进制)。 (只读) |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 证书 id。 |
| `issued_at` | string |  | 最近一次签发成功的时间。 |
| `issuer` | string |  | 证书颁发者。 (只读) |
| `items` | CertAcme[] |  | 签发状态。 |
| `key` | string |  | 私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。 |
| `last_error` | string |  | 最近一次错误 |
| `name` | string |  | 名称 |
| `names` | string[] |  | SAN(域名、通配域名或 IP);无 SAN 时取 CN。 (只读) |
| `next_try_at` | string |  | 续签失败终态后,续签扫描最早再试的时刻。 |
| `not_after` | string |  | 证书到期时间。 (只读) |
| `not_before` | string |  | 证书生效时间。 (只读) |
| `ocsp` | boolean |  | 叶证书带 OCSP 地址(节点可装订)。 (只读) |
| `ok` | integer |  | 已排队签发的条数。 |
| `password` | string |  | 当前登录口令。 |
| `renewing` | boolean |  | 当前这轮是续签(失败时旧证书照用)。 |
| `scope` | string |  | 证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。 可选值: ["site","ip","panel"] |
| `site_ids` | integer[] |  | 在用此证书的站点。 (只读) |
| `state` | string |  | pending 排队或等重试;running 签发中;issued 已签出;failed 重试用完(已发提醒)。 可选值: ["pending","running","issued","failed"] |
| `tenant_id` | integer |  | 所属租户;null = 平台 IP 证书。 (只读) |
| `totp_code` | string |  | 动态口令(TOTP)的 6 位当前码;账号须已启用动态口令。 |
| `type` | string |  | custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `version` | integer |  | 证书内容版本,换证 +1。 (只读) |
| `zerossl_order_id` | string |  | zerossl_api 证书当前的 ZeroSSL 订单号;空 = 还没下单。 |
| `zerossl_order_state` | string |  | ZeroSSL 订单状态(draft、pending_validation、issued、cancelled 等);空 = 还没下单。 |

## ACME 账号 (`acme-accounts`)

自动签发证书用的 CA 账号(Let's Encrypt、ZeroSSL)。第一次签发时才向 CA 注册。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/acme-accounts

### GET `/api/v2/acme-accounts`

列出ACME 账号 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ca` | string |  | 只列这家 CA 的账号。 可选值: ["lets","zerossl"] |

```sh
curl "https://panel.example.com/api/v2/acme-accounts" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/acme-accounts`

创建ACME 账号 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `api_key` | string |  | ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。 |
| `ca` | string | 有 | 签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。 可选值: ["lets","zerossl"] |
| `directory` | string |  | ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。 |
| `eab_hmac` | string |  | 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `eab_kid` | string |  | EAB 密钥 id(ZeroSSL 用)。 |
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `name` | string | 有 | 名称 |
| `recheck` | boolean |  | 为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。 |

```sh
curl -X POST "https://panel.example.com/api/v2/acme-accounts" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ca":"zerossl","eab_hmac":"${EAB_HMAC}","eab_kid":"kid-example","name":"zerossl-main"}'
```

### GET `/api/v2/acme-accounts/{id}`

获取ACME 账号 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/acme-accounts/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/acme-accounts/{id}`

修改ACME 账号 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `api_key` | string |  | ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。 |
| `ca` | string | 有 | 签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。 可选值: ["lets","zerossl"] |
| `directory` | string |  | ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。 |
| `eab_hmac` | string |  | 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `eab_kid` | string |  | EAB 密钥 id(ZeroSSL 用)。 |
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `name` | string | 有 | 名称 |
| `recheck` | boolean |  | 为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/acme-accounts/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ca":"zerossl","eab_hmac":"${EAB_HMAC}","eab_kid":"kid-example","name":"zerossl-main"}'
```

### DELETE `/api/v2/acme-accounts/{id}`

删除ACME 账号 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/acme-accounts/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

ACME 账号对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `api_checked_at` | string |  | 最近一次检测 API Key 的时间。 (只读) |
| `api_error` | string |  | API Key 最近一次检测或签发遇到的账号级错误。 (只读) |
| `api_key` | string |  | ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。 (只读) |
| `api_state` | string |  | API Key 状态:none 没配;ok 可用;blocked 账号级错误(额度满、欠费、Key 被拒,6 小时后或重新检测通过再签);error Key 解不开须重填。 可选值: ["none","ok","blocked","error"] (只读) |
| `ca` | string |  | 签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。 可选值: ["lets","zerossl"] |
| `created_at` | string |  | 创建时间 (只读) |
| `directory` | string |  | ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。 |
| `eab_hmac` | string |  | 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `eab_kid` | string |  | EAB 密钥 id(ZeroSSL 用)。 |
| `email` | string |  | 邮箱 |
| `enabled` | boolean |  | 是否启用 |
| `id` | integer |  | 记录 ID (只读) |
| `last_error` | string |  | 最近一次错误 (只读) |
| `name` | string |  | 名称 |
| `recheck` | boolean |  | 为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。 |
| `status` | string |  | new = 还没注册;registered = 已在 CA 注册;error = 注册失败(原因见 last_error)。 可选值: ["new","registered","error"] (只读) |
| `tenant_id` | integer |  | 所属租户;null = 平台账号。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## DNS API(证书验证) (`dns-apis`)

DNS 服务商的 API 凭据,用于 DNS-01 验证与签发通配证书。凭据只写,响应只回掩码。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/dns-apis

### GET `/api/v2/dns-apis`

列出DNS API 凭据 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/dns-apis" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/dns-apis`

创建DNS API 凭据 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth` | object |  | 凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `type` | string | 有 | DNS 服务商。 |

```sh
curl -X POST "https://panel.example.com/api/v2/dns-apis" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auth":{"DP_Id":"12345","DP_Key":"${DP_KEY}"},"name":"my-dns","type":"dnspod_cn"}'
```

### GET `/api/v2/dns-apis/{id}`

获取DNS API 凭据 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/dns-apis/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/dns-apis/{id}`

修改DNS API 凭据 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth` | object |  | 凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `type` | string | 有 | DNS 服务商。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/dns-apis/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auth":{"DP_Id":"12345","DP_Key":"${DP_KEY}"},"name":"my-dns","type":"dnspod_cn"}'
```

### DELETE `/api/v2/dns-apis/{id}`

删除DNS API 凭据 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/dns-apis/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

DNS API(证书验证)对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auth` | object |  | 凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `type` | string |  | DNS 服务商。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 证书设置 (`cert-settings`)

当前用户新建证书时的默认类型;留空则跟随平台。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/cert-settings

### GET `/api/v2/cert-settings`

获取证书设置 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/cert-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cert-settings`

修改证书设置 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_type` | string | 有 | 本人设的默认类型(custom/lets/zerossl);null = 跟随平台。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cert-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"default_type":"custom"}'
```

证书设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_type` | string |  | 本人设的默认类型(custom/lets/zerossl);null = 跟随平台。 |
| `effective_type` | string |  | 实际生效的默认类型。 (只读) |

## 面板证书 (`panel-cert`)

仅管理员。面板自己用的 HTTPS 证书状态;一键用面板域名自动申请 Let's Encrypt 证书,续签随证书管理。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/panel-cert

### GET `/api/v2/panel-cert`

查看面板证书状态 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/panel-cert" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/panel-cert/issue`

一键申请面板证书 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/panel-cert/issue" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

面板证书对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acme` | CertAcme |  | 自动签发状态(状态、验证方式、续签与最近一次失败原因)。 |
| `cert` | Cert |  | 证书(响应带证书链、域名、到期时间与状态,不带私钥;私钥只能经导出接口取回)。 |
| `cert_id` | integer |  | panel.tls.cert_id;0 = 没配面板证书。 |
| `domain` | string |  | 面板域名(panel.access.domain);空 = 没填。 |
| `https` | string |  | 面板 HTTPS 的现状。on = 面板证书可用且主控开了 HTTPS 监听;no_domain = 没填面板域名(不申请证书);no_cert = 填了域名但没有可用的面板证书;issuing = 证书正在签发;failed = 证书签发失败(原因见 acme.last_error,自动申请的会按间隔重试);no_listen = 证书已有,但主控配置文件没开 HTTPS 监听(listen_tls);expired = 面板证书已过期(not_after 已过,续签没成功)。 可选值: ["on","no_domain","no_cert","issuing","failed","no_listen","expired"] |

## 文件验证 (`pki-validations`)

仅管理员。为 CA 的文件验证提供内容,由节点转主控代答,到期后不再应答。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/pki-validations

### GET `/api/v2/pki-validations`

列出文件验证内容 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/pki-validations" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/pki-validations`

新建文件验证内容 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string | 有 | 验证文件内容。 |
| `name` | string | 有 | 名称 |
| `ttl_s` | integer |  | 多少秒后不再代答;0 或不给 = 不过期。 |

```sh
curl -X POST "https://panel.example.com/api/v2/pki-validations" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"example-validation-content","name":"0123456789ABCDEF0123456789ABCDEF.txt","ttl_s":86400}'
```

### DELETE `/api/v2/pki-validations/{id}`

删除文件验证内容 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/pki-validations/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

文件验证对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string |  | 验证文件内容。 |
| `created_at` | string |  | 创建时间 (只读) |
| `expires_at` | string |  | 过期时间 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `ttl_s` | integer |  | 多少秒后不再代答;0 或不给 = 不过期。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 访问控制(ACL) (`acls`)

按 IP/CIDR 等条件放行或拦截请求的规则集;平台提供内置规则,租户可自建。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/acls

### GET `/api/v2/acls`

列出ACL · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `enabled` | boolean |  | 按启用状态过滤。 |
| `name` | string |  | 按名称包含过滤。 |
| `owner` | string |  | platform = 只看平台对象;tenant = 只看租户对象。 可选值: ["platform","tenant"] |

```sh
curl "https://panel.example.com/api/v2/acls" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/acls`

创建ACL · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_action` | string | 有 | 都不命中时的动作。 可选值: ["allow","deny"] |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `name` | string | 有 | 名称 |
| `rules` | AclRule[] | 有 | 按序匹配;条数受配置 protect.acl_rules_max 约束。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/acls" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"default_action":"deny","name":"office","rules":[{"action":"allow","when":{"f":"ip","op":"cidr","v":["192.0.2.0/24"]}}]}'
```

### POST `/api/v2/acls/batch-enable`

批量启用或禁用ACL · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `enabled` | boolean | 有 | 是否启用 默认: true |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/acls/batch-enable" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false,"ids":[1,2]}'
```

### GET `/api/v2/acls/{id}`

获取ACL · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/acls/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/acls/{id}`

修改ACL · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_action` | string | 有 | 都不命中时的动作。 可选值: ["allow","deny"] |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `name` | string | 有 | 名称 |
| `rules` | AclRule[] | 有 | 按序匹配;条数受配置 protect.acl_rules_max 约束。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/acls/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"default_action":"deny","name":"office","rules":[{"action":"allow","when":{"f":"ip","op":"cidr","v":["192.0.2.0/24"]}}]}'
```

### DELETE `/api/v2/acls/{id}`

删除ACL · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/acls/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

访问控制(ACL)对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `builtin` | boolean |  | 内置对象,不可删。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `default_action` | string |  | 都不命中时的动作。 可选值: ["allow","deny"] |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `errors` | FieldError[] |  | 没改的逐条原因;field 为 /ids/<下标>,code 同单条修改接口(not_found、readonly 等)。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |
| `name` | string |  | 名称 |
| `rules` | AclRule[] |  | 按序匹配;条数受配置 protect.acl_rules_max 约束。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 (只读) |
| `updated` | integer[] |  | 已改好的 id(含本来就是目标状态的),按请求顺序。 |
| `updated_at` | string |  | 更新时间 (只读) |

## CC 匹配器 (`cc-matches`)

CC 防护里用来识别请求的条件;可复用到多个规则组。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cc-matches

### GET `/api/v2/cc-matches`

列出CC 匹配器 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `name` | string |  | 按名称包含过滤。 |
| `owner` | string |  | platform = 只看平台对象;tenant = 只看租户对象。 可选值: ["platform","tenant"] |

```sh
curl "https://panel.example.com/api/v2/cc-matches" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cc-matches`

创建CC 匹配器 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `name` | string | 有 | 名称 |
| `when` | object |  | 规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-matches" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"static","when":{"f":"req_uri","op":"contains","v":[".js",".css"]}}'
```

### POST `/api/v2/cc-matches/replay`

回放CC 匹配器草稿 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_id` | integer |  | 只算这个网站的流量;不给 = 当前身份可见的全部网站。 |
| `when` | object |  | 规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-matches/replay" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"when":{"f":"ja4","op":"eq","v":["t13d1516h2_8daaf6152771_e5627efa2ab1"]}}'
```

### GET `/api/v2/cc-matches/{id}`

获取CC 匹配器 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cc-matches/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cc-matches/{id}`

修改CC 匹配器 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `name` | string | 有 | 名称 |
| `when` | object |  | 规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cc-matches/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"static","when":{"f":"req_uri","op":"contains","v":[".js",".css"]}}'
```

### DELETE `/api/v2/cc-matches/{id}`

删除CC 匹配器 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/cc-matches/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

CC 匹配器对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `builtin` | boolean |  | 内置对象,不可删。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `hits` | integer |  | 窗口内命中的请求数(按 sample_weight 还原)。 |
| `id` | integer |  | 记录 ID (只读) |
| `ips` | integer |  | 命中请求涉及的不同客户端 IP 数(去重计数,不按采样还原)。 |
| `name` | string |  | 名称 |
| `reason` | string |  | supported=false 时的说明。 |
| `sampled` | boolean |  | 窗口内有被采样的行(sample_weight > 1);此时 hits、total 是估计值。 |
| `site_id` | integer |  | 只算这个网站的流量;不给 = 当前身份可见的全部网站。 |
| `sites` | integer |  | 命中请求涉及的不同网站数(去重计数,不按采样还原)。 |
| `supported` | boolean |  | false = 条件里有访问日志没有的字段(请求头、accept_language、命名集合),没有回放;原因见 reason。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 (只读) |
| `top_ips` | CcMatchReplayIp[] |  | 命中请求最多的客户端 IP,最多 20 条,按请求数降序;supported=false 或没有命中时为空。 |
| `top_urls` | CcMatchReplayUrl[] |  | 命中请求最多的 URL(不含查询串),最多 5 条,按请求数降序;supported=false 或没有命中时为空。 |
| `total` | integer |  | 窗口内的请求总数(同样还原)。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `when` | object |  | 规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。 |
| `window_hours` | integer |  | 回放窗口小时数(固定 24)。 |

## CC 过滤器 (`cc-filters`)

对命中的请求限频或发起挑战(JS、滑块、验证码等)的处理方式。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cc-filters

### GET `/api/v2/cc-filters`

列出CC 过滤器 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `name` | string |  | 按名称包含过滤。 |
| `owner` | string |  | platform = 只看平台对象;tenant = 只看租户对象。 可选值: ["platform","tenant"] |

```sh
curl "https://panel.example.com/api/v2/cc-filters" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cc-filters`

创建CC 过滤器 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `count_key` | string |  | 按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。 可选值: ["ip","ja4","ip_ja4"] |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `kind` | string |  | 挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。 |
| `max` | integer | 有 | 窗口内允许的请求数。 |
| `mode` | string |  | url_auth 必填:鉴权方式。a = ?<sign_arg>=md5(密钥+路径+时间戳)&<time_arg>=时间戳;b = ?<sign_arg>=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。 可选值: ["a","b"] |
| `name` | string | 有 | 名称 |
| `per_uri_max` | integer |  | rate:单 URI 上限;0 = 不限。 |
| `sign_arg` | string |  | url_auth 必填:签名参数名(字母、数字、下划线、连字符)。 |
| `sign_use_max` | integer |  | url_auth:同一签名最多用几次;0 = 不限。 |
| `time_arg` | string |  | url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。 |
| `ttl_s` | integer |  | url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。 |
| `type` | string | 有 | rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。 可选值: ["rate","challenge","url_auth"] |
| `window_s` | integer | 有 | 统计窗口秒数。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-filters" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"max":20,"name":"rate-5-20","per_uri_max":10,"type":"rate","window_s":5}'
```

### GET `/api/v2/cc-filters/{id}`

获取CC 过滤器 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cc-filters/{id}`

修改CC 过滤器 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `count_key` | string |  | 按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。 可选值: ["ip","ja4","ip_ja4"] |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `kind` | string |  | 挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。 |
| `max` | integer | 有 | 窗口内允许的请求数。 |
| `mode` | string |  | url_auth 必填:鉴权方式。a = ?<sign_arg>=md5(密钥+路径+时间戳)&<time_arg>=时间戳;b = ?<sign_arg>=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。 可选值: ["a","b"] |
| `name` | string | 有 | 名称 |
| `per_uri_max` | integer |  | rate:单 URI 上限;0 = 不限。 |
| `sign_arg` | string |  | url_auth 必填:签名参数名(字母、数字、下划线、连字符)。 |
| `sign_use_max` | integer |  | url_auth:同一签名最多用几次;0 = 不限。 |
| `time_arg` | string |  | url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。 |
| `ttl_s` | integer |  | url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。 |
| `type` | string | 有 | rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。 可选值: ["rate","challenge","url_auth"] |
| `window_s` | integer | 有 | 统计窗口秒数。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"max":20,"name":"rate-5-20","per_uri_max":10,"type":"rate","window_s":5}'
```

### DELETE `/api/v2/cc-filters/{id}`

删除CC 过滤器 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

CC 过滤器对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `builtin` | boolean |  | 内置对象,不可删。 (只读) |
| `count_key` | string |  | 按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。 可选值: ["ip","ja4","ip_ja4"] |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `id` | integer |  | 记录 ID (只读) |
| `kind` | string |  | 挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。 |
| `max` | integer |  | 窗口内允许的请求数。 |
| `mode` | string |  | url_auth 必填:鉴权方式。a = ?<sign_arg>=md5(密钥+路径+时间戳)&<time_arg>=时间戳;b = ?<sign_arg>=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。 可选值: ["a","b"] |
| `name` | string |  | 名称 |
| `per_uri_max` | integer |  | rate:单 URI 上限;0 = 不限。 |
| `sign_arg` | string |  | url_auth 必填:签名参数名(字母、数字、下划线、连字符)。 |
| `sign_use_max` | integer |  | url_auth:同一签名最多用几次;0 = 不限。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 (只读) |
| `time_arg` | string |  | url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。 |
| `ttl_s` | integer |  | url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。 |
| `type` | string |  | rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。 可选值: ["rate","challenge","url_auth"] |
| `updated_at` | string |  | 更新时间 (只读) |
| `window_s` | integer |  | 统计窗口秒数。 |

## CC 规则 (`cc-rules`)

把匹配器与过滤器按序组合成的 CC 规则组,站点可选用其中一组。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cc-rules

### GET `/api/v2/cc-rules`

列出CC 规则组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `enabled` | boolean |  | 按启用状态过滤。 |
| `name` | string |  | 按名称包含过滤。 |
| `owner` | string |  | platform = 只看平台对象;tenant = 只看租户对象。 可选值: ["platform","tenant"] |

```sh
curl "https://panel.example.com/api/v2/cc-rules" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cc-rules`

创建CC 规则组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `items` | CcRuleItem[] | 有 | 规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。 |
| `name` | string | 有 | 名称 |
| `show_to` | integer[] |  | 平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。 |
| `sort` | integer |  | 面板排序(小的在前)。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 |
| `visible` | boolean |  | 在站点的规则组下拉里展示。 默认: true |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-rules" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"action":"ban","filter_ids":[8],"match_id":3}],"name":"js"}'
```

### POST `/api/v2/cc-rules/batch-enable`

批量启用或禁用CC规则组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `enabled` | boolean | 有 | 是否启用 默认: true |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-rules/batch-enable" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false,"ids":[1,2]}'
```

### GET `/api/v2/cc-rules/{id}`

获取CC 规则组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cc-rules/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cc-rules/{id}`

修改CC 规则组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `items` | CcRuleItem[] | 有 | 规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。 |
| `name` | string | 有 | 名称 |
| `show_to` | integer[] |  | 平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。 |
| `sort` | integer |  | 面板排序(小的在前)。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 |
| `visible` | boolean |  | 在站点的规则组下拉里展示。 默认: true |

```sh
curl -X PUT "https://panel.example.com/api/v2/cc-rules/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"action":"ban","filter_ids":[8],"match_id":3}],"name":"js"}'
```

### DELETE `/api/v2/cc-rules/{id}`

删除CC 规则组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/cc-rules/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

CC 规则对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `builtin` | boolean |  | 内置对象,不可删。 (只读) |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注;不给则为空(修改时不给也清空,整体替换)。 |
| `enabled` | boolean |  | 是否启用 默认: true |
| `errors` | FieldError[] |  | 没改的逐条原因;field 为 /ids/<下标>,code 同单条修改接口(not_found、readonly 等)。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |
| `items` | CcRuleItem[] |  | 规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。 |
| `name` | string |  | 名称 |
| `ruleset_id` | string |  | 编译成的规则集 id:平台 cc.level.<名>(站点 cc_level、guard.default_cc_level 引用它);租户 cc.user.r<id>(本租户站点的 cc_level 可选它,带套餐的站点须套餐有 custom_cc_rule)。 (只读) |
| `show_to` | integer[] |  | 平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。 |
| `sort` | integer |  | 面板排序(小的在前)。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 (只读) |
| `updated` | integer[] |  | 已改好的 id(含本来就是目标状态的),按请求顺序。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `visible` | boolean |  | 在站点的规则组下拉里展示。 默认: true |

## 封禁 (`bans`)

被拉黑的 IP 记录,可手动封禁、按 IP 或整站解封并查解封记录,也包含节点上报的自动封禁。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/bans

### GET `/api/v2/bans`

列出封禁 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ip` | string |  | 给单个地址精确匹配;给 CIDR 网段则返回落入该网段的全部封禁(单地址条目,及前缀不短于该网段的网段条目)。 |
| `site_id` | integer |  | 按站点过滤。 |
| `active` | boolean |  | true = 只看未到期的。 |
| `level` | string |  | 按作用范围过滤(global = 全局黑名单)。 可选值: ["site","tenant","global"] |
| `source` | string |  | 按来源过滤:manual = 面板下的(人工);node = 节点自动封的(挑战超限、规则 ban、握手洪水等)。 可选值: ["manual","node"] |
| `source_type` | string |  | 按来源细类过滤(manual / cc / waf / scan / status / tls / intel);可逗号分隔多个(如 status,tls,重复的去重),每项都须是这七个值之一,否则 422;不带为全部。 |
| `created_from` | string |  | 只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。 |

```sh
curl "https://panel.example.com/api/v2/bans" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/bans`

创建封禁 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:封禁所属租户。租户级必填;站点级可省(按站主),带了须与站主一致。租户凭据调用时忽略。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `expires_at` | string |  | 到期时刻;null = 永久。 |
| `ip` | string | 有 | IP 或 CIDR。 |
| `level` | string | 有 | 作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。 可选值: ["site","tenant","global"] |
| `reason` | string |  | 原因:人工封禁默认 manual;节点自动封的是触发规则(规则集/规则 id,如 cc.level.r5/r1)或模块名(ssl_handshake = 握手洪水),无规则的记 auto。 |
| `site_id` | integer |  | level=site 时必填的站点 id;其余为 0。 |

```sh
curl -X POST "https://panel.example.com/api/v2/bans" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ip":"198.51.100.7","level":"tenant"}'
```

### GET `/api/v2/bans/site-counts`

按站点统计封禁 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `source_type` | string |  | 按来源细类过滤(manual / cc / waf / scan / status / tls / intel);可逗号分隔多个(如 status,tls,重复的去重),每项都须是这七个值之一,否则 422;不带为全部。 |
| `created_from` | string |  | 只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。 |

```sh
curl "https://panel.example.com/api/v2/bans/site-counts" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/bans/source-counts`

按来源细类统计封禁 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `created_from` | string |  | 只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。 |

```sh
curl "https://panel.example.com/api/v2/bans/source-counts" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/bans/unban`

按 IP 解封 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `all` | boolean |  | true = 全站解封:清空 site_id 这个站的全部封禁,只用于 level=site,计 1 次每天解封次数。 |
| `ips` | string[] |  | 要解封的 IP/CIDR(all=true 时不带,否则必填);一次条数受 protect.unban_batch_max 约束,租户每天次数受 protect.unban_daily_max 约束。 |
| `level` | string | 有 | 作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。 可选值: ["site","tenant","global"] |
| `site_id` | integer |  | level=site 时必填的站点 id;其余为 0。 |

```sh
curl -X POST "https://panel.example.com/api/v2/bans/unban" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ips":["198.51.100.7"],"level":"tenant"}'
```

### GET `/api/v2/bans/unban-quota`

解封配额与今日已用 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/bans/unban-quota" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/bans/unbans`

列出解封记录 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 按站点过滤(只含站点级解封)。 |
| `since` | string |  | 只列这个时刻及之后的(如数今天用了几次)。 |
| `by_admin` | boolean |  | 按是否管理员代站主解封过滤;数站主今天用掉的次数传 false(代解不占站主次数)。 |

```sh
curl "https://panel.example.com/api/v2/bans/unbans" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/bans/{id}`

删除封禁 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/bans/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

封禁对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `all` | boolean |  | true = 全站解封:清空 site_id 这个站的全部封禁,只用于 level=site,计 1 次每天解封次数。 |
| `batch_max` | integer |  | 一次最多解封几个 IP(配置 protect.unban_batch_max)。 |
| `by_admin` | boolean |  | true = 管理员代站主解封(记在站主名下、站主可见,不占站主每天次数)。 |
| `count` | integer |  | 未到期封禁条数。 |
| `created_at` | string |  | 创建时间 (只读) |
| `daily_max` | integer |  | 租户每天最多解封几次(配置 protect.unban_daily_max)。 |
| `expires_at` | string |  | 到期时刻;null = 永久。 |
| `filter_id` | string |  | 触发的过滤器(规则集或模块),由 reason 拆出,如 cc.level.r5、waf、scan.builtin、ssl_handshake;手工封禁与无规则的 auto 不给。 (只读) |
| `id` | integer |  | 记录 ID (只读) |
| `intel` | BanIntel |  | 封禁 IP 在平台高危 IP 库里的现状(列表时按当前库现查;库没在下发、已出库或库没给的字段不返回)。 |
| `intel_hit` | boolean |  | 该 IP 是否在平台高危 IP 库;null = 尚未判定(高危 IP 库上线前恒为 null)。 |
| `ip` | string |  | IP 或 CIDR。 |
| `ip_count` | integer |  | 解封的 IP/CIDR 条数(全站解封为 0)。 |
| `ips` | string[] |  | 要解封的 IP/CIDR(all=true 时不带,否则必填);一次条数受 protect.unban_batch_max 约束,租户每天次数受 protect.unban_daily_max 约束。 |
| `items` | BanSourceCount[] |  | 本页条目 |
| `level` | string |  | 作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。 可选值: ["site","tenant","global"] |
| `reason` | string |  | 原因:人工封禁默认 manual;节点自动封的是触发规则(规则集/规则 id,如 cc.level.r5/r1)或模块名(ssl_handshake = 握手洪水),无规则的记 auto。 |
| `removed` | integer |  | 同时从封禁表删除的条数。 |
| `rule_id` | string |  | 触发的规则号,由 reason 拆出(cc.level.r5/r1 的 r1、waf:941100 的 941100);没有规则号的不给。 (只读) |
| `site_id` | integer |  | level=site 时必填的站点 id;其余为 0。 |
| `source` | string |  | manual = 面板下的;node = 节点自动封后上报的(同一对象未到期时只留一行,再封续期)。解封两者一样:删除或 /bans/unban。 可选值: ["manual","node"] (只读) |
| `source_type` | BanSourceType |  | 来源细类:manual = 面板下的;cc = CC 规则组(含 cc.level.*、cc.user.*、auto 及其余规则集);waf = WAF 规则连续命中;scan = 扫描器内置集;status = 状态码内置集;tls = 握手洪水;intel = 平台高危 IP 库。节点自动封的永不是 manual。 可选值: ["manual","cc","waf","scan","status","tls","intel"] |
| `status` | string |  | 下发任务状态 pending/running/done/failed;任务已被清理为 null。 |
| `task_id` | integer |  | 下发节点的后台任务 id(GET /tasks/{id} 查进度)。 |
| `tenant_id` | integer |  | 所属租户;null = 平台对象(内置或管理员建,租户只读)。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |
| `used` | integer |  | 本租户今天(UTC 零点起)自己解封的次数;管理员代解不计,管理员调用时为 0。 |

## 站点黑白名单 (`site-ip-lists`)

单个站点的永久 IP 黑名单与白名单;黑名单命中即断开,白名单命中跳过 CC 等防护。也可清空站点在各节点上的临时白名单。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/site-ip-lists

### GET `/api/v2/site-ip-lists/{site_id}`

获取站点黑白名单 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/site-ip-lists/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/site-ip-lists/{site_id}`

设置站点黑白名单 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `black` | string[] |  | 永久黑名单(命中 = 断开);条数受 protect.black_ip_max 约束。 |
| `black_items` | IpListItem[] |  | 黑名单条目(含到期时间、原因、来源);已到期的不返回。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `white` | string[] |  | 永久白名单(命中 = 跳过 CC 等防护);条数受 protect.white_ip_max 约束。 |
| `white_items` | IpListItem[] |  | 白名单条目(含到期时间、原因、来源);已到期的不返回。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/site-ip-lists/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"black":["198.51.100.0/24"],"white":["203.0.113.9"]}'
```

### GET `/api/v2/site-ip-lists/{site_id}/export`

导出站点黑白名单 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `list` | string | 有 | 导出哪张名单。 可选值: ["black","white"] |
| `source` | IpListSource |  | 只导出该来源的条目;不带为全部。 可选值: ["manual","import","ip_detail","api"] |
| `format` | string |  | txt(缺省,纯文本每行一条)或 csv(带表头与来源列、UTF-8 BOM)。 可选值: ["txt","csv"] 默认: "txt" |

```sh
curl "https://panel.example.com/api/v2/site-ip-lists/{site_id}/export" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/site-ip-lists/{site_id}/import`

批量导入站点黑白名单 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dry_run` | boolean |  | true 只预检,不保存。 默认: false |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `list` | string | 有 | 导入到哪张名单。 可选值: ["black","white"] |
| `mode` | string |  | merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。 可选值: ["merge","replace"] 默认: "merge" |
| `text` | string | 有 | 文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。 |

```sh
curl -X POST "https://panel.example.com/api/v2/site-ip-lists/{site_id}/import" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dry_run":true,"list":"black","mode":"merge","text":"198.51.100.0/24,2030-01-01T00:00:00Z,scanner\n"}'
```

### GET `/api/v2/site-ip-lists/{site_id}/ip-detail`

IP 详情 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ip` | string | 有 | IPv4 或 IPv6 地址。 |

```sh
curl "https://panel.example.com/api/v2/site-ip-lists/{site_id}/ip-detail" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/site-ip-lists/{site_id}/ip-detail`

从 IP 详情拉黑或加白 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `expires_at` | string |  | 到期时间;空 = 永久。须晚于当前时刻。 |
| `ip` | string | 有 | 规范化后的地址(IPv4 映射地址还原成 IPv4)。 |
| `list` | string | 有 | 导入到哪张名单。 可选值: ["black","white"] |
| `reason` | string |  | 原因(备注),最长 200 个字符。 |
| `scope` | string | 有 | site 本站名单;global 全局名单(仅管理员)。 可选值: ["site","global"] |

```sh
curl -X POST "https://panel.example.com/api/v2/site-ip-lists/{site_id}/ip-detail" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/site-ip-lists/{site_id}/tmp-white-clear`

清空站点临时白名单 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X POST "https://panel.example.com/api/v2/site-ip-lists/{site_id}/tmp-white-clear" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

站点黑白名单对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `added` | integer |  | 新增条数。 |
| `applied` | boolean |  | 是否已保存(dry_run 或有挡导入的问题时为 false)。 |
| `black` | string[] |  | 永久黑名单(命中 = 断开);条数受 protect.black_ip_max 约束。 |
| `black_items` | IpListItem[] |  | 黑名单条目(含到期时间、原因、来源);已到期的不返回。 |
| `block_denied` | string |  | 不能拉黑的原因:private 内网/回环/链路本地、node 节点 IP(只回管理员)、self 调用者自己的 IP、other 其他原因(租户遇到节点 IP 回这个,不暴露节点地址);能拉黑不回。 可选值: ["private","node","self","other"] |
| `dry_run` | boolean |  | true 只预检,不保存。 默认: false |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `expires_at` | string |  | 到期时间;空 = 永久。须晚于当前时刻。 |
| `geo` | GeoipLookup |  | IP 归属地查询结果。 |
| `global_black` | IpListItem |  | IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。 |
| `global_white` | IpListItem |  | IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。 |
| `ip` | string |  | 规范化后的地址(IPv4 映射地址还原成 IPv4)。 |
| `issues` | IpListImportIssue[] |  | 逐行问题(最多 1000 条,按行号升序)。 |
| `lines` | integer |  | 有效条目数(去重后)。 |
| `list` | string | 有 | 导入到哪张名单。 可选值: ["black","white"] |
| `mode` | string |  | merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。 可选值: ["merge","replace"] 默认: "merge" |
| `reason` | string |  | 原因(备注),最长 200 个字符。 |
| `removed` | integer |  | replace 模式下原有、新名单里没有的条数(同 IP 的算「更新」,不算在内)。 |
| `scope` | string | 有 | site 本站名单;global 全局名单(仅管理员)。 可选值: ["site","global"] |
| `site_black` | IpListItem |  | IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。 |
| `site_id` | integer |  | 网站 ID (只读) |
| `site_white` | IpListItem |  | IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。 |
| `task_id` | integer |  | 下发节点的后台任务 id(GET /tasks/{id} 查进度)。 |
| `text` | string | 有 | 文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。 |
| `updated` | integer |  | 已在名单里、被导入行更新的条数。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `white` | string[] |  | 永久白名单(命中 = 跳过 CC 等防护);条数受 protect.white_ip_max 约束。 |
| `white_items` | IpListItem[] |  | 白名单条目(含到期时间、原因、来源);已到期的不返回。 |

## 全局黑白名单 (`global-ip-lists`)

平台级 IP 黑名单与白名单(全网生效),条目可带到期时间、原因与来源,支持批量导入导出;仅管理员可改。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/global-ip-lists

### GET `/api/v2/global-ip-lists`

获取全局黑白名单 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/global-ip-lists" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/global-ip-lists`

设置全局黑白名单 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `black` | string[] |  | 黑名单的 IP/CIDR(未过期的全部条目)。 |
| `black_items` | IpListItem[] |  | 黑名单条目(含到期时间、原因、来源)。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `white` | string[] |  | 白名单的 IP/CIDR(未过期的全部条目)。 |
| `white_items` | IpListItem[] |  | 白名单条目(含到期时间、原因、来源)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/global-ip-lists" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"black_items":[{"expires_at":"2030-01-01T00:00:00Z","ip":"198.51.100.0/24","reason":"scanner"}]}'
```

### GET `/api/v2/global-ip-lists/export`

导出全局黑白名单 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `list` | string | 有 | 导出哪张名单。 可选值: ["black","white"] |
| `source` | IpListSource |  | 只导出该来源的条目;不带为全部。 可选值: ["manual","import","ip_detail","api"] |
| `format` | string |  | txt(缺省,纯文本每行一条)或 csv(带表头与来源列、UTF-8 BOM)。 可选值: ["txt","csv"] 默认: "txt" |

```sh
curl "https://panel.example.com/api/v2/global-ip-lists/export" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/global-ip-lists/import`

批量导入全局黑白名单 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dry_run` | boolean |  | true 只预检,不保存。 默认: false |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `list` | string | 有 | 导入到哪张名单。 可选值: ["black","white"] |
| `mode` | string |  | merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。 可选值: ["merge","replace"] 默认: "merge" |
| `text` | string | 有 | 文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。 |

```sh
curl -X POST "https://panel.example.com/api/v2/global-ip-lists/import" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dry_run":true,"list":"black","mode":"merge","text":"198.51.100.0/24,2030-01-01T00:00:00Z,scanner\n"}'
```

全局黑白名单对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `added` | integer |  | 新增条数。 |
| `applied` | boolean |  | 是否已保存(dry_run 或有挡导入的问题时为 false)。 |
| `black` | string[] |  | 黑名单的 IP/CIDR(未过期的全部条目)。 |
| `black_items` | IpListItem[] |  | 黑名单条目(含到期时间、原因、来源)。 |
| `dry_run` | boolean |  | true 只预检,不保存。 默认: false |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `issues` | IpListImportIssue[] |  | 逐行问题(最多 1000 条,按行号升序)。 |
| `lines` | integer |  | 有效条目数(去重后)。 |
| `list` | string | 有 | 导入到哪张名单。 可选值: ["black","white"] |
| `mode` | string |  | merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。 可选值: ["merge","replace"] 默认: "merge" |
| `removed` | integer |  | replace 模式下原有、新名单里没有的条数(同 IP 的算「更新」,不算在内)。 |
| `text` | string | 有 | 文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。 |
| `updated` | integer |  | 已在名单里、被导入行更新的条数。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `white` | string[] |  | 白名单的 IP/CIDR(未过期的全部条目)。 |
| `white_items` | IpListItem[] |  | 白名单条目(含到期时间、原因、来源)。 |

## CC 设置 (`cc-settings`)

平台级 CC 默认规则组与自动切换设置,仅管理员可改。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/cc-settings

### GET `/api/v2/cc-settings`

获取 CC 设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/cc-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cc-settings`

修改 CC 设置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_switch` | CcAutoSwitch | 有 | CC 防护自动升级设置:攻击时自动切换到更严的规则组。 |
| `default_page_rule_id` | integer |  | 默认页(未绑定域名)用的平台 CC 规则组 id;null 或不带 = 不防护。 |
| `default_rule_id` | integer | 有 | 站点未选规则组时用的平台 CC 规则组 id;null = 节点缺省。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cc-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auto_switch":{"enabled":false,"hold_s":300,"qps_50x":10,"qps_total":500,"rule_id":2},"default_rule_id":10002}'
```

CC 设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_switch` | CcAutoSwitch |  | CC 防护自动升级设置:攻击时自动切换到更严的规则组。 |
| `default_page_rule_id` | integer |  | 默认页(未绑定域名)用的平台 CC 规则组 id;null 或不带 = 不防护。 |
| `default_rule_id` | integer |  | 站点未选规则组时用的平台 CC 规则组 id;null = 节点缺省。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。 (只读) |

## Bot 设置 (`bot-settings`)

平台级 Bot 管理:按五类(搜索引擎 / 监控·工具 / 自动化工具 / 无头浏览器 / 恶意 Bot)与伪造爬虫设处置方式、验证方式、行为评分分段、保护接口与例外,仅管理员可改;无头浏览器、恶意 Bot、伪造爬虫处置与行为评分属付费功能 WAF 增强。站点在站点配置 bot 里逐类覆盖。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/bot-settings

### GET `/api/v2/bot-settings`

获取 Bot 设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/bot-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/bot-settings`

修改 Bot 设置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `actions` | object |  | 按类处置;缺省搜索引擎、监控·工具放行,自动化工具只记录,无头浏览器验证,恶意 Bot 与伪造爬虫拦截。headless、malicious、fake 属 WAF 增强。 |
| `challenge` | string |  | 处置为 challenge 时的验证方式:js 无感、slide 滑块、rotate 旋转图片、click 点选、captcha 字符(缺省 js)。 可选值: ["js","slide","rotate","click","captcha"] |
| `enabled` | boolean |  | 总开关;false = 所有站点都不做 Bot 判定。 |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(无头浏览器、恶意 Bot、伪造爬虫按普通访客,不打分,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] |
| `exceptions` | object[] |  | 例外:命中的请求不做 Bot 判定(path、cidr、ja4 至少一项,同一条里多项须同时满足)。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `protect` | string[] |  | 保护接口(路径前缀,如 /login,WAF 增强):没看过页面直接请求它们加分。 |
| `score` | object |  | 行为评分分段(WAF 增强,0–100):低于 js 放行;js 到 slide 无感验证;slide 到 block 按 kind 验证;达到 block 按恶意 Bot 处置。须 js < slide < block。通过验证的访客 30 分钟内分数清零。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/bot-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"actions":{"automation":"log","fake":"block","headless":"challenge","malicious":"block","monitor":"allow","search":"allow"},"challenge":"js","enabled":true,"exceptions":[{"cidr":"198.51.100.0/24","site_ids":[]}],"protect":["/login"],"score":{"block":85,"js":30,"kind":"slide","slide":60}}'
```

Bot 设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `actions` | object |  | 按类处置;缺省搜索引擎、监控·工具放行,自动化工具只记录,无头浏览器验证,恶意 Bot 与伪造爬虫拦截。headless、malicious、fake 属 WAF 增强。 |
| `challenge` | string |  | 处置为 challenge 时的验证方式:js 无感、slide 滑块、rotate 旋转图片、click 点选、captcha 字符(缺省 js)。 可选值: ["js","slide","rotate","click","captcha"] |
| `enabled` | boolean |  | 总开关;false = 所有站点都不做 Bot 判定。 |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(无头浏览器、恶意 Bot、伪造爬虫按普通访客,不打分,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] (只读) |
| `exceptions` | object[] |  | 例外:命中的请求不做 Bot 判定(path、cidr、ja4 至少一项,同一条里多项须同时满足)。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `protect` | string[] |  | 保护接口(路径前缀,如 /login,WAF 增强):没看过页面直接请求它们加分。 |
| `score` | object |  | 行为评分分段(WAF 增强,0–100):低于 js 放行;js 到 slide 无感验证;slide 到 block 按 kind 验证;达到 block 按恶意 Bot 处置。须 js < slide < block。通过验证的访客 30 分钟内分数清零。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。 (只读) |

## Bot 统计 (`bot-stats`)

Bot 管理页顶部统计与分类表「今日请求」列:今日请求数、按 Bot 分类的请求与处置分项、防重放启用网站数、节点升级进度;租户只看自己网站。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/bot-stats

### GET `/api/v2/bot-stats`

获取 Bot 统计 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_id` | integer |  | 只统计该网站;不带为全部网站。 |

```sh
curl "https://panel.example.com/api/v2/bot-stats" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

Bot 统计对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `classes` | BotClassStat[] |  | 今日出现过的 Bot 分类及处置分项,按分类固定次序(search、monitor、automation、headless、malicious、fake);今日没出现的分类不列;日志库不可用为空数组。 |
| `node_upgrade` | BotNodeUpgrade |  | 节点升级进度:上报版本与本主控一致的节点占已通过审核的节点;仅管理员能看到,租户的响应不带此字段。 |
| `replay_sites` | BotReplaySites |  | 防重放启用情况。 |
| `today_requests` | integer |  | 今日全部请求数;日志库不可用为 null。 |

## WAF 设置 (`waf-settings`)

平台级 WAF 全网总开关、缺省拦截阈值与请求体检查上限,仅管理员可改;站点各自的观察/拦截与例外在站点配置 waf 里。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/waf-settings

### GET `/api/v2/waf-settings`

获取 WAF 设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/waf-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/waf-settings`

修改 WAF 设置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `body_max_kb` | integer | 有 | 请求体只查前多少 KiB;0 = 不查请求体。 |
| `enabled` | boolean | 有 | 全网总开关;false = 所有站点都不查。 |
| `engine_unavailable_nodes` | integer |  | 在线主节点里报 WAF 引擎(libinjection)不可用的台数(缺库时 sqli/xss 规则不生效);修改时忽略。 |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;标准/严格等级与语义检测照常生效但只读)、basic 未开通或缓冲已过(不生效,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `intel_share` | boolean |  | 威胁情报共享:把自动封禁的高危 IP、上传扫描命中/误报与新出现的文件指纹匿名上报服务商(记录见 GET /intel-reports)。不带 = 保持原值,没设过为开(默认开启,可随时关闭,关闭后立即停止上报)。 |
| `level` | string |  | 全网缺省防护等级(站点没单独选时用它);standard/strict 属 WAF 增强,改动过增强门(到期只读期与未开通只许调低,调高拒)。不带 = 保持原值,没设过为 basic。 可选值: ["basic","standard","strict"] |
| `observe_days` | integer |  | 新规则/新等级的观察天数(只记录不拦);0 = 不观察。不带 = 保持原值,没设过为 3。 |
| `rule_lib` | WafRuleLib |  | 规则库对照表(只读,修改时忽略):付费项 rules_update 是否开通、规则包版本与各类条数、节点对齐;没开通时用节点内置 23 条。明细见 GET /waf-protections。 |
| `scanner` | WafScanner |  | 扫描器防护(内置防护 protect.builtin_guard 的 scan 段):总开关、处置与封禁时长,以及「判定(满足任一)」五项各自的勾选与阈值/自定义名单。任一项关掉即不判该项;自定义路径保存在主控,换规则版本不受影响。 |
| `semantic` | WafSemantic |  | 语义检测(WAF 增强):在规则打分之外再按语义判攻击;节点按观察期只记不拦、过期后拦截。 |
| `threshold` | integer | 有 | 缺省拦截阈值(命中规则的异常分累计);站点 waf.threshold 非 0 时以站点为准。 |
| `trunc_action` | string |  | 请求内容有一部分没查到时的处置(规则号 920901):参数超 1024 个、请求头超 256 个、JSON/XML 条目超上限、表单字段超预算、非二进制请求体超 body_max_kb;能补查的先补查,仍有漏的才按此处置。log 只记录(事件标 body_trunc)不拦;strict_block 严格档拦、基础与标准档只记录;block 各档都拦。缺省 strict_block,即严格档下超过 body_max_kb(缺省 64KB)的非二进制请求体(如大 JSON)会被 920901 拦,可调大 body_max_kb、改为 log 或在站点 WAF 例外放行 920901。注意 920901 计入连续命中封禁(站点 waf.ban_on_repeat),网站开了它时经常发大 JSON 的客户端 IP 会被封。观察模式的站点只记不拦。不带 = 保持原值,没设过为 strict_block。 可选值: ["log","strict_block","block"] |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/waf-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body_max_kb":64,"enabled":true,"intel_share":true,"level":"basic","observe_days":3,"scanner":{"action":"ban","ban_s":1800,"by_app_enabled":true,"decoys":{"enabled":true,"paths":[]},"enabled":true,"not_found":{"enabled":true,"max":30,"window_s":60},"sensitive":{"enabled":true,"extra_paths":[],"max":3},"ua_enabled":true},"semantic":{"enabled":false,"items":["sqli","xss"],"observe_days":3,"relation":"rules_first","sensitivity":"mid"},"threshold":5,"trunc_action":"strict_block"}'
```

WAF 设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `body_max_kb` | integer |  | 请求体只查前多少 KiB;0 = 不查请求体。 |
| `enabled` | boolean |  | 全网总开关;false = 所有站点都不查。 |
| `engine_unavailable_nodes` | integer |  | 在线主节点里报 WAF 引擎(libinjection)不可用的台数(缺库时 sqli/xss 规则不生效);修改时忽略。 (只读) |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;标准/严格等级与语义检测照常生效但只读)、basic 未开通或缓冲已过(不生效,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] (只读) |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `intel_share` | boolean |  | 威胁情报共享:把自动封禁的高危 IP、上传扫描命中/误报与新出现的文件指纹匿名上报服务商(记录见 GET /intel-reports)。不带 = 保持原值,没设过为开(默认开启,可随时关闭,关闭后立即停止上报)。 |
| `level` | string |  | 全网缺省防护等级(站点没单独选时用它);standard/strict 属 WAF 增强,改动过增强门(到期只读期与未开通只许调低,调高拒)。不带 = 保持原值,没设过为 basic。 可选值: ["basic","standard","strict"] |
| `observe_days` | integer |  | 新规则/新等级的观察天数(只记录不拦);0 = 不观察。不带 = 保持原值,没设过为 3。 |
| `rule_lib` | WafRuleLib |  | 规则库对照表(只读,修改时忽略):付费项 rules_update 是否开通、规则包版本与各类条数、节点对齐;没开通时用节点内置 23 条。明细见 GET /waf-protections。 (只读) |
| `scanner` | WafScanner |  | 扫描器防护(内置防护 protect.builtin_guard 的 scan 段):总开关、处置与封禁时长,以及「判定(满足任一)」五项各自的勾选与阈值/自定义名单。任一项关掉即不判该项;自定义路径保存在主控,换规则版本不受影响。 |
| `semantic` | WafSemantic |  | 语义检测(WAF 增强):在规则打分之外再按语义判攻击;节点按观察期只记不拦、过期后拦截。 |
| `threshold` | integer |  | 缺省拦截阈值(命中规则的异常分累计);站点 waf.threshold 非 0 时以站点为准。 |
| `trunc_action` | string |  | 请求内容有一部分没查到时的处置(规则号 920901):参数超 1024 个、请求头超 256 个、JSON/XML 条目超上限、表单字段超预算、非二进制请求体超 body_max_kb;能补查的先补查,仍有漏的才按此处置。log 只记录(事件标 body_trunc)不拦;strict_block 严格档拦、基础与标准档只记录;block 各档都拦。缺省 strict_block,即严格档下超过 body_max_kb(缺省 64KB)的非二进制请求体(如大 JSON)会被 920901 拦,可调大 body_max_kb、改为 log 或在站点 WAF 例外放行 920901。注意 920901 计入连续命中封禁(站点 waf.ban_on_repeat),网站开了它时经常发大 JSON 的客户端 IP 会被封。观察模式的站点只记不拦。不带 = 保持原值,没设过为 strict_block。 可选值: ["log","strict_block","block"] |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。 (只读) |

## 上传防护设置 (`upload-scan-settings`)

平台级上传文件扫描(只查 multipart 表单上传的文件):总开关、危险扩展名、双扩展名、伪装文件、木马特征、病毒库、单文件上限、扫描超时、处置与例外,仅管理员可改;木马特征、病毒库与 sha256 黑名单属付费功能 WAF 增强。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/upload-scan-settings

### GET `/api/v2/upload-scan-settings`

获取上传防护设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/upload-scan-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/upload-scan-settings`

修改上传防护设置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 命中后:block 拦截、log 只记录、observe 先观察 3 天(期间只记录,之后拦截);危险文件不设观察期。 可选值: ["block","log","observe"] |
| `disguise` | boolean |  | 伪装文件检测(扩展名为图片、文件头魔数为脚本或可执行程序)。 |
| `double_ext` | boolean |  | 双扩展名检测(如 a.php.jpg、a.asp;.jpg)。 |
| `enabled` | boolean |  | 总开关;false = 所有站点都不扫描。 |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(增强项不生效,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] |
| `exceptions` | UploadScanException[] |  | 例外:网站与路径前缀命中时跳过该特征(sig 空 = 该路径不扫描)。租户标记误报加的条目(source=false_positive)整体替换时请原样带回,否则被覆盖。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `exts` | string[] |  | 危险扩展名(小写、不带点);没带回缺省 php phtml jsp jspx asp aspx ashx cer war sh cgi。站点 waf.upload_exts 可覆盖。 |
| `max_file_mb` | integer |  | 单个文件扫描上限(MB,缺省 20);超出的只查扩展名,按 oversize 处置。 |
| `observe_until` | string |  | 观察期截止(action 为 observe 时有值);修改时忽略,由服务端写。 |
| `on_parse_error` | string |  | multipart 解析出错(定界符不对、头过大、体被截断、段数超限等)时:block 拦截、allow 放行并记录(缺省 block)。 可选值: ["allow","block"] |
| `on_timeout` | string |  | 扫描超时(或读请求体失败)时:allow 放行并记录、block 拦截(缺省 allow)。 可选值: ["allow","block"] |
| `oversize` | string |  | 超过单文件上限:allow 放行并记录、block 拦截。 可选值: ["allow","block"] |
| `sha256` | object[] |  | 本主控 sha256 黑名单(WAF 增强)。 |
| `sig` | boolean |  | 木马 / Webshell 特征(WAF 增强)。 |
| `timeout_s` | integer |  | 每个请求的扫描超时(秒,缺省 2)。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。 |
| `virus` | string |  | 病毒库(ClamAV,WAF 增强):off 关、mem4g 内存 ≥4GB 的节点、all 所有节点。 可选值: ["off","mem4g","all"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/upload-scan-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"block","disguise":true,"double_ext":true,"enabled":true,"exceptions":[{"path":"/upload/avatar/","sig":"","site_id":0}],"exts":["php","jsp"],"max_file_mb":20,"on_parse_error":"block","on_timeout":"allow","oversize":"allow","sig":true,"timeout_s":2,"virus":"mem4g"}'
```

上传防护设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 命中后:block 拦截、log 只记录、observe 先观察 3 天(期间只记录,之后拦截);危险文件不设观察期。 可选值: ["block","log","observe"] |
| `disguise` | boolean |  | 伪装文件检测(扩展名为图片、文件头魔数为脚本或可执行程序)。 |
| `double_ext` | boolean |  | 双扩展名检测(如 a.php.jpg、a.asp;.jpg)。 |
| `enabled` | boolean |  | 总开关;false = 所有站点都不扫描。 |
| `enhanced` | string |  | WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(增强项不生效,设置保留);修改时忽略。 可选值: ["full","readonly","basic"] (只读) |
| `exceptions` | UploadScanException[] |  | 例外:网站与路径前缀命中时跳过该特征(sig 空 = 该路径不扫描)。租户标记误报加的条目(source=false_positive)整体替换时请原样带回,否则被覆盖。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `exts` | string[] |  | 危险扩展名(小写、不带点);没带回缺省 php phtml jsp jspx asp aspx ashx cer war sh cgi。站点 waf.upload_exts 可覆盖。 |
| `max_file_mb` | integer |  | 单个文件扫描上限(MB,缺省 20);超出的只查扩展名,按 oversize 处置。 |
| `observe_until` | string |  | 观察期截止(action 为 observe 时有值);修改时忽略,由服务端写。 (只读) |
| `on_parse_error` | string |  | multipart 解析出错(定界符不对、头过大、体被截断、段数超限等)时:block 拦截、allow 放行并记录(缺省 block)。 可选值: ["allow","block"] |
| `on_timeout` | string |  | 扫描超时(或读请求体失败)时:allow 放行并记录、block 拦截(缺省 allow)。 可选值: ["allow","block"] |
| `oversize` | string |  | 超过单文件上限:allow 放行并记录、block 拦截。 可选值: ["allow","block"] |
| `sha256` | object[] |  | 本主控 sha256 黑名单(WAF 增强)。 |
| `sig` | boolean |  | 木马 / Webshell 特征(WAF 增强)。 |
| `timeout_s` | integer |  | 每个请求的扫描超时(秒,缺省 2)。 |
| `updated_at` | string |  | 响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。 (只读) |
| `virus` | string |  | 病毒库(ClamAV,WAF 增强):off 关、mem4g 内存 ≥4GB 的节点、all 所有节点。 可选值: ["off","mem4g","all"] |

## 上传扫描统计 (`upload-scan-stats`)

上传防护页顶部统计:今日扫描、拦截、超上限未扫的次数,以及扫不了的网站列表;仅管理员可看。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/upload-scan-stats

### GET `/api/v2/upload-scan-stats`

获取上传扫描统计 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/upload-scan-stats" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

上传扫描统计对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `today_blocked` | integer |  | 今日被上传扫描命中并拦下的次数(不含超上限、超时、出错的拦截);日志库不可用为 null。 |
| `today_scanned` | integer |  | 今日扫描的上传请求数(一请求多文件计 1);日志库不可用为 null。 |
| `today_unscanned` | integer |  | 今日因超过单文件上限而未扫描的次数;日志库不可用为 null。 |
| `unscanned_sites` | UploadScanStatsSite[] |  | 扫不了的网站,按网站 id 升序,最多 200 条;全局未开时只回一条 reason=global_off 的汇总(site_id 为 0)。其后另附 WAF 被节点本机带外总开关关停的在线节点(reason=node_kill,site_id 为 0、name 为节点名,最多 200 条,不计入 unscanned_total);全局未开时不附。 |
| `unscanned_total` | integer |  | 扫不了的网站总数(不受 200 条上限影响);全局未开时为全部启用网站数。 |

## 高危 IP 库 (`intel`)

平台下发的高危 IP 库(付费项 WAF 规则更新,每小时同步)的状态、全局处置策略、条目查询、单条加白与今日来访命中;租户只读。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/intel

### GET `/api/v2/intel`

获取高危 IP 库状态 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/intel" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/intel/allow`

高危 IP 单条加白 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ip` | string | 有 | 地址或网段。 |
| `reason` | string |  | 加白原因(记在白名单条目上);不带记「高危 IP 库加白」。 |

```sh
curl -X POST "https://panel.example.com/api/v2/intel/allow" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ip":"192.0.2.10"}'
```

### GET `/api/v2/intel/ips`

查询高危 IP 库条目 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `ip` | string |  | 单个地址 = 查覆盖它的条目;其余按 CIDR 文本包含过滤(仅管理员,租户必须给单个地址)。 |
| `level` | IntelLevel |  | 按等级过滤。 可选值: ["high","medium"] |
| `reason` | IntelReason |  | 按类型过滤。 可选值: ["scanner","exploit","cc"] |

```sh
curl "https://panel.example.com/api/v2/intel/ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/intel/policy`

修改高危 IP 库处置策略 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | IntelAction | 有 | 处置方式:challenge 验证(JS 验证通过才放行);block 拦截(封本站并回 403);log 观察(只记录)。 可选值: ["challenge","block","log"] |
| `level` | IntelLevel | 有 | 等级:high 高危(漏洞利用类或分数 ≥ 80);medium 中危。 可选值: ["high","medium"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/intel/policy" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"challenge","level":"high"}'
```

### GET `/api/v2/intel/visitors`

今日访问过我的高危 IP · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 按站点过滤。 |

```sh
curl "https://panel.example.com/api/v2/intel/visitors" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

高危 IP 库对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | IntelAction | 有 | 处置方式:challenge 验证(JS 验证通过才放行);block 拦截(封本站并回 403);log 观察(只记录)。 可选值: ["challenge","block","log"] |
| `actions` | IntelAction[] |  | 今日对它用过的处置方式。 |
| `added_at` | string |  | 加入名单的时间(同一 IP 再次写入时保持原值)。 (只读) |
| `cidr` | string |  | 地址或网段(规范写法)。 |
| `count` | integer |  | 条目数。 |
| `entry` | IntelEntry |  | 高危 IP 库里一条。 |
| `error` | string |  | 最近一次同步失败的原因(在用的一版保留);成功为空串。 |
| `expires_at` | string |  | 到期时间;空 = 永久。到期后自动失效(节点按本机时钟判,不依赖主控),主控随后清理并随下次配置下发。写入时须晚于当前时刻。 |
| `first_seen_at` | string |  | 首次入库的时刻;库没给时不返回。 |
| `generated_at` | string |  | 库的生成时刻(超管侧)。 |
| `halt` | string |  | 授权已过期、停用或超管长时间不可达而停止更新的原因(只给管理员;不是故障,与 error 分开;没有停更时不出现)。 |
| `high` | integer |  | 高危条目数。 |
| `hits` | integer |  | 今日命中次数。 |
| `ip` | string | 有 | 地址或网段。 |
| `last_at` | string |  | 最近一次命中时刻。 |
| `level` | IntelLevel |  | 等级:high 高危(漏洞利用类或分数 ≥ 80);medium 中危。 可选值: ["high","medium"] |
| `masters` | integer |  | 24 小时内报告该条的主控数;库没给时不返回。 |
| `medium` | integer |  | 中危条目数。 |
| `policy` | IntelPolicy |  | 高危 IP 库全局处置策略;站点配置 intel.action 可单独改或关闭。 |
| `reason` | string |  | 加白原因(记在白名单条目上);不带记「高危 IP 库加白」。 |
| `reported_at` | string |  | 最近一次被报告的时刻。 |
| `score` | integer |  | 风险分(1–100)。 |
| `serving` | boolean |  | 是否在向节点下发(拉成过且没过期)。 |
| `sites` | integer |  | 涉及网站数。 |
| `source` | IpListSource |  | 条目来源:manual 手工添加;import 批量导入;ip_detail 在 IP 详情里拉黑/加白;api 经接口写入。 可选值: ["manual","import","ip_detail","api"] |
| `stale` | boolean |  | 授权不再带库(停更)且最后一版已过 24 小时,不再下发。 |
| `sub` | string |  | 子类(如 WAF 连续命中);库没给时不返回。 |
| `synced_at` | string |  | 最近一次同步时刻。 |
| `version` | string |  | 在下发的库版本;没有为空串。 |

## 增值防护方案 (`protect-schemes`)

防重放、防泄露、防篡改各一份方案(租户各自一份,管理员编辑平台方案);保存时一并改「按方案」的站点,单独设置的不动;属 WAF 增强。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/protect-schemes

### GET `/api/v2/protect-schemes/leak`

获取防泄露方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/leak" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/leak`

保存防泄露方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `custom` | SiteLeakGuardCustom[] | 有 | 自定义正则,最多 16 条。 |
| `detect` | SiteLeakGuardDetect | 有 | 内置识别各类的处置;不写 = 不查这一类。 |
| `exclude` | string[] | 有 | 不检测的路径前缀(末尾 * 可省),最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `observe_days` | integer | 有 | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/leak" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/replay`

获取防重放方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/replay" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/replay`

保存防重放方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/replay" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/tamper`

获取防篡改方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/tamper" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/tamper`

保存防篡改方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction | 有 | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `mode` | string | 有 | 检查范围:structure 仅结构变化;full 整页任意变化。 可选值: ["structure","full"] |
| `observe_days` | integer | 有 | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |
| `scopes` | SiteTamperScope[] | 有 | 保护范围,最多 50 条。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/tamper" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/protect-schemes/{kind}/apply`

把方案批量应用到网站 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_join` | object |  | 「以后新加入范围的网站自动加入方案」的规则;没开时不返回。 |
| `dry_run` | boolean |  | 为 true 只返回会发生什么的计数,不写任何东西。 默认: false |
| `override_custom` | boolean |  | 为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。 默认: false |
| `selection` | ProtectSchemeSelection | 有 | 要应用的网站范围。 |

```sh
curl -X POST "https://panel.example.com/api/v2/protect-schemes/{kind}/apply" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/{kind}/sites`

列出已设置这项防护的网站 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `q` | string |  | 按网站域名或站点名模糊搜索(不区分大小写)。 |
| `status` | ProtectSchemeSiteStatus |  | 按状态过滤。 可选值: ["enabled","disabled","pending","capture_failed"] |
| `source` | ProtectSiteSource |  | 按来源过滤:scheme 按方案;custom 单独设置(含单独关闭)。 可选值: ["scheme","custom"] (只读) |

```sh
curl "https://panel.example.com/api/v2/protect-schemes/{kind}/sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/protect-schemes/{kind}/sites/bulk`

批量重设或关闭网站的这项防护 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction | 有 | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `filter` | ProtectSchemeSiteFilter |  | 与列表同样的过滤条件,服务端展开成网站集合。 |
| `ids` | integer[] |  | 网站 id 列表。 |

```sh
curl -X POST "https://panel.example.com/api/v2/protect-schemes/{kind}/sites/bulk" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

增值防护方案对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `applied` | integer |  | 写入(dry_run 时为将写入)的网站数。 |
| `auto_join` | object |  | 「以后新加入范围的网站自动加入方案」的规则;没开时不返回。 (只读) |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `counts` | ProtectSchemeCounts |  | 站点计数:调用方看得到的站点里,开着的、按方案的、单独设置的各几个。 (只读) |
| `custom` | SiteLeakGuardCustom[] |  | 自定义正则,最多 16 条。 |
| `demoted_sites` | integer |  | 本次保存因属主没开通 WAF 增强、改为单独设置并保留原值的站点数(只在保存的回包里有)。 (只读) |
| `detect` | SiteLeakGuardDetect |  | 内置识别各类的处置;不写 = 不查这一类。 |
| `domain` | string |  | 网站主域名(没有域名时为站点名)。 |
| `dry_run` | boolean |  | 为 true 只返回会发生什么的计数,不写任何东西。 默认: false |
| `enabled` | boolean |  | 是否开着。 |
| `exclude` | string[] |  | 不检测的路径前缀(末尾 * 可省),最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `failed` | ProtectSchemeFailure[] |  | 没能处理的网站及原因,最多 100 条。 |
| `failed_total` | integer |  | 没能处理的网站总数(failed 被截断时大于其长度)。 |
| `filter` | ProtectSchemeSiteFilter |  | 与列表同样的过滤条件,服务端展开成网站集合。 |
| `gate` | ProtectSchemeGate |  | 方案属主(租户本人或平台)的 WAF 增强判定档:full 可改;readonly、basic 只许减不许增。 可选值: ["full","readonly","basic"] (只读) |
| `ids` | integer[] |  | 网站 id 列表。 |
| `matched` | integer |  | 范围内调用方看得到的网站数。 |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `mode` | string |  | 检查范围:structure 仅结构变化;full 整页任意变化。 可选值: ["structure","full"] |
| `observe_days` | integer |  | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |
| `observe_until` | integer |  | 观察期截止(Unix 毫秒时间戳);只有防泄露开着且仍在观察期内才有值,已过期、没有观察期、关着或其余方案为空。 |
| `override_custom` | boolean |  | 为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。 默认: false |
| `owner` | string |  | 属主用户名。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `scopes` | SiteTamperScope[] |  | 保护范围,最多 50 条。 |
| `selection` | ProtectSchemeSelection | 有 | 要应用的网站范围。 |
| `site_id` | integer |  | 网站 id。 |
| `skipped_custom` | integer |  | 因单独设置而没覆盖的网站数(override_custom 为 false)。 |
| `skipped_gate` | integer |  | 因属主 WAF 增强不是 full 而没写的网站数。 |
| `source` | ProtectSiteSource |  | 站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。 可选值: ["scheme","custom"] (只读) |
| `status` | ProtectSchemeSiteStatus |  | 站点这一项的状态:enabled 开着;disabled 关着;pending 开着但防篡改基准还在排队采集;capture_failed 开着但基准采集多次失败、已停止重试(只有防篡改有后两种)。 可选值: ["enabled","disabled","pending","capture_failed"] |
| `tenant_id` | integer |  | 属主用户 id。 |
| `today_blocked` | integer |  | 今日(UTC)拦截与换错误页次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_blocked 同口径);其余方案、没接 ClickHouse 或查询失败为空。 |
| `today_hits` | integer |  | 今日命中数(防泄露为今日 UTC 非观察期的打码与拦截次数之和,即 today_masked + today_blocked,防篡改为今日检出篡改的页数);防重放为空。 |
| `today_masked` | integer |  | 今日(UTC)打码次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_masked 同口径);其余方案、没接 ClickHouse 或查询失败为空。 |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |
| `updated_at` | string |  | 版本(没保存过为空);修改时用 expected_updated_at。 (只读) |
| `updated_sites` | integer |  | 本次保存一并改到的按方案站点数(只在保存的回包里有)。 (只读) |

## 防重放 (`site-replay-guards`)

单个站点的防重放设置:受保护接口须带一次性令牌或 App 签名头,没有或重放时拦截或验证;可单独设置或恢复按方案;属 WAF 增强。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/site-replay-guards

### GET `/api/v2/site-replay-guards/{site_id}`

获取站点防重放设置 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/site-replay-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/site-replay-guards/{site_id}`

设置站点防重放 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `enabled` | boolean | 有 | 是否开启。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/site-replay-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/site-replay-guards/{site_id}`

站点防重放恢复按方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/site-replay-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

防重放对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `enabled` | boolean |  | 是否开启。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `gate` | string |  | 站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不生效、设置保留。 可选值: ["full","readonly","basic"] (只读) |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 (只读) |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 (只读) |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 (只读) |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `site_id` | integer |  | 网站 ID (只读) |
| `source` | ProtectSiteSource |  | 站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。 可选值: ["scheme","custom"] (只读) |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |
| `updated_at` | string |  | 版本(没设过为空);修改时用 expected_updated_at。 (只读) |

## 防泄露 (`site-leak-guards`)

单个站点的防泄露设置:查源站返回的网页、JSON 与文本里的手机号、身份证号、银行卡号、密钥和报错信息,按打码、拦截或换错误页处置;属 WAF 增强。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/site-leak-guards

### GET `/api/v2/site-leak-guards/{site_id}`

获取站点防泄露设置 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/site-leak-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/site-leak-guards/{site_id}`

设置站点防泄露 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `custom` | SiteLeakGuardCustom[] |  | 自定义正则,最多 16 条。 |
| `detect` | SiteLeakGuardDetect |  | 内置识别各类的处置;不写 = 不查这一类。 |
| `enabled` | boolean | 有 | 是否开启。 |
| `exclude` | string[] |  | 不检测的路径前缀,最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `observe_days` | integer |  | 新开启时观察的天数。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/site-leak-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/site-leak-guards/{site_id}`

站点防泄露恢复按方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/site-leak-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

防泄露对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `custom` | SiteLeakGuardCustom[] |  | 自定义正则,最多 16 条。 |
| `detect` | SiteLeakGuardDetect |  | 内置识别各类的处置;不写 = 不查这一类。 |
| `enabled` | boolean |  | 是否开启。 |
| `exclude` | string[] |  | 不检测的路径前缀,最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `gate` | string |  | 站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不检测、设置保留。 可选值: ["full","readonly","basic"] (只读) |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 (只读) |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 (只读) |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 (只读) |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |
| `observe_days` | integer |  | 新开启时观察的天数。 |
| `observe_until` | string |  | 观察期截止;为空 = 不在观察期(没开过或开时选了 0 天)。 (只读) |
| `site_id` | integer |  | 网站 ID (只读) |
| `source` | ProtectSiteSource |  | 站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。 可选值: ["scheme","custom"] (只读) |
| `updated_at` | string |  | 版本(没设过为空);修改时用 expected_updated_at。 (只读) |

## 全网 URL 防护设置 (`url-guard-settings`)

平台级全网 URL 防护的缺省开关与阈值,仅管理员可改;站点各自的开关与阈值在站点安全配置里。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/url-guard-settings

### GET `/api/v2/url-guard-settings`

获取全网 URL 防护设置 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/url-guard-settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/url-guard-settings`

修改全网 URL 防护设置 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | 触发后对该 URL 的动作:挑战验证、拦截、每 IP 限速。 可选值: ["challenge","block","limit"] |
| `baseline_ratio` | integer |  | 触发还须达到平时的这么多倍(平时 = 该 URL 过去 1 小时的平均 QPS,不含最近 1 分钟);面板最小填 1,缺省 5;0 = 不看倍数(旧配置没有该字段,按 0 沿用原判定)。只管新触发,已在途规则续期只看 QPS。修改时不带则保持原值。 |
| `enabled` | boolean | 有 | 全局默认开关;站点未单独设置时按它。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `gate` | string |  | WAF 增强(waf_enhanced)判定档:full 开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;照常生效、设置只读)、basic 未开通或已回落(不下发);修改时忽略。 可选值: ["full","readonly","basic"] |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] |
| `hold_s` | integer | 有 | 规则保持秒数;到期前仍超阈会自动续期,降下来就到期撤销。 |
| `kind` | string |  | action=challenge 的挑战类型,缺省 js;其它动作须为空。 可选值: ["js","redirect","delay_jump","cookie","captcha","slide","click","rotate"] |
| `max_per_site` | integer | 有 | 同一站点同时生效的规则条数上限。 |
| `qps` | integer | 有 | 某 URL 全网合计 QPS 不低于它(且达到平时的 baseline_ratio 倍)才触发。 |
| `rate` | integer |  | action=limit 的每 IP 每 10 秒最多请求数;其它动作须为 0。 |
| `updated_at` | string |  | 响应里的版本(没改过为空);修改时忽略,乐观锁用 expected_updated_at。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/url-guard-settings" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"challenge","baseline_ratio":5,"enabled":true,"hold_s":600,"kind":"js","max_per_site":20,"qps":300,"rate":20}'
```

全网 URL 防护设置对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 触发后对该 URL 的动作:挑战验证、拦截、每 IP 限速。 可选值: ["challenge","block","limit"] |
| `baseline_ratio` | integer |  | 触发还须达到平时的这么多倍(平时 = 该 URL 过去 1 小时的平均 QPS,不含最近 1 分钟);面板最小填 1,缺省 5;0 = 不看倍数(旧配置没有该字段,按 0 沿用原判定)。只管新触发,已在途规则续期只看 QPS。修改时不带则保持原值。 |
| `enabled` | boolean |  | 全局默认开关;站点未单独设置时按它。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `gate` | string |  | WAF 增强(waf_enhanced)判定档:full 开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;照常生效、设置只读)、basic 未开通或已回落(不下发);修改时忽略。 可选值: ["full","readonly","basic"] (只读) |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 (只读) |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 (只读) |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 (只读) |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |
| `hold_s` | integer |  | 规则保持秒数;到期前仍超阈会自动续期,降下来就到期撤销。 |
| `kind` | string |  | action=challenge 的挑战类型,缺省 js;其它动作须为空。 可选值: ["js","redirect","delay_jump","cookie","captcha","slide","click","rotate"] |
| `max_per_site` | integer |  | 同一站点同时生效的规则条数上限。 |
| `qps` | integer |  | 某 URL 全网合计 QPS 不低于它(且达到平时的 baseline_ratio 倍)才触发。 |
| `rate` | integer |  | action=limit 的每 IP 每 10 秒最多请求数;其它动作须为 0。 |
| `updated_at` | string |  | 响应里的版本(没改过为空);修改时忽略,乐观锁用 expected_updated_at。 (只读) |

## 全网 URL 防护 (`url-guard`)

按 URL 跨节点汇总请求量,超阈值后对该 URL 临时下发的挑战/限速/拦截规则,到时自动撤销;此处只读查看生效中的条目。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/url-guard

### GET `/api/v2/url-guard/active`

列出生效中的全网 URL 防护 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/url-guard/active" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

全网 URL 防护对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | UrlGuardActive[] |  | 生效中的规则,新的在前。 |

## 威胁情报上报记录 (`intel-reports`)

本主控向服务商匿名上报威胁情报(自动封禁的高危 IP、上传扫描命中/误报、新出现的文件指纹)的批次记录,每 5 分钟一批;情报共享关闭时不上报。仅管理员可查看。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/intel-reports

### GET `/api/v2/intel-reports`

查询情报上报记录 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `type` | IntelReportType |  | 按类型过滤(ip / upload_hit / false_positive / sha256_report / samples);不带为全部。 可选值: ["ip","upload_hit","false_positive","sha256_report","samples"] |

```sh
curl "https://panel.example.com/api/v2/intel-reports" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

威胁情报上报记录对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 批次时间。 |
| `error` | string |  | 失败原因;成功为空串。连续失败时只保留最近一次。 |
| `id` | integer |  | 记录 ID |
| `items` | integer |  | 本批条数。 |
| `result` | string |  | 结果:ok 已送达;failed 没送达(条目留队列下轮补报)。 可选值: ["ok","failed"] |
| `type` | IntelReportType |  | 情报类型:高危 IP / 上传命中 / 管理员标的误报 / 新出现的文件指纹 / 可疑请求样本。 可选值: ["ip","upload_hit","false_positive","sha256_report","samples"] |

## 防篡改 (`site-tamper-guards`)

单个站点的网页防篡改设置:保护范围(首页、整页、目录)、检查范围(仅结构变化 / 整页任意变化)、篡改时返回基准页或仅告警、观察期;更新基准与看差异;属 WAF 增强。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/site-tamper-guards

### GET `/api/v2/site-tamper-guards/{site_id}`

获取站点防篡改设置 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/site-tamper-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/site-tamper-guards/{site_id}`

设置站点防篡改 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 篡改时的处置。 可选值: ["restore","log"] |
| `enabled` | boolean | 有 | 是否开启。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `mode` | string |  | 检查范围。 可选值: ["structure","full"] |
| `observe_days` | integer |  | 新开启时观察的天数。 |
| `scopes` | SiteTamperScope[] |  | 保护范围。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/site-tamper-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/site-tamper-guards/{site_id}`

站点防篡改恢复按方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/site-tamper-guards/{site_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/site-tamper-guards/{site_id}/diff`

看站点防篡改差异 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `path` | string | 有 | 基准页路径(如 /、/about.html)。 |

```sh
curl "https://panel.example.com/api/v2/site-tamper-guards/{site_id}/diff" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/site-tamper-guards/{site_id}/rebase`

更新站点防篡改基准 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X POST "https://panel.example.com/api/v2/site-tamper-guards/{site_id}/rebase" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

防篡改对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 篡改时的处置。 可选值: ["restore","log"] |
| `assets` | SiteTamperAsset[] |  | 指纹不符的 JS/CSS(只记录,不替换)。 |
| `base_at` | string |  | 基准时间(最近一次更新基准)。 (只读) |
| `base_ver` | integer |  | 基准版本,每次更新基准 +1;0 = 还没有基准。 (只读) |
| `changes` | SiteTamperChange[] |  | 结构变化(删掉的链接与正文变化不列)。 |
| `enabled` | boolean |  | 是否开启。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `fetch_error` | string |  | 现抓这一页没成的原因(此时 changes 为空):fetch_failed 源站非 200 或连不上;not_html 不是网页;too_large 超 1MB。抓到时不出。 可选值: ["fetch_failed","not_html","too_large"] |
| `gate` | string |  | 站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不检测、设置保留。 可选值: ["full","readonly","basic"] (只读) |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 (只读) |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 (只读) |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 (只读) |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |
| `mode` | string |  | 检查范围。 可选值: ["structure","full"] |
| `observe_days` | integer |  | 新开启时观察的天数。 |
| `observe_until` | string |  | 观察期截止;为空 = 不在观察期(没开过或开时选了 0 天)。 (只读) |
| `pages` | SiteTamperPage[] |  | 基准页(按路径排序),含没纳入的保护范围与原因。 (只读) |
| `path` | string |  | 页面路径。 |
| `scopes` | SiteTamperScope[] |  | 保护范围。 |
| `site_id` | integer |  | 网站 ID (只读) |
| `source` | ProtectSiteSource |  | 站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。 可选值: ["scheme","custom"] (只读) |
| `tampered` | boolean |  | 按站点检查范围算不算篡改。 |
| `updated_at` | string |  | 版本(没设过为空);修改时用 expected_updated_at。 (只读) |

## 防篡改保护页面总表 (`tamper-guard`)

跨网站列出全部保护页面(网站、路径、范围、基准时间、状态、最近变化),不用先选网站;租户只看自己的网站,可按网站筛选。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/tamper-guard

### GET `/api/v2/tamper-guard/pages`

列出全部网站的防篡改保护页面 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 只看该网站;不属于调用方租户时为空列表。 |
| `q` | string |  | 按网站域名或页面路径模糊搜索(不区分大小写)。 |
| `changed` | boolean |  | 为 true 只看检出过篡改的页面(最近变化不为空的页)。 |

```sh
curl "https://panel.example.com/api/v2/tamper-guard/pages" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

防篡改保护页面总表对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `base_at` | string |  | 站点整体基准时间;还没更新过基准为 null。 |
| `domain` | string |  | 网站主域名(站点域名列表第一个;没有域名时为站点名)。 |
| `enabled` | boolean |  | 该站防篡改开关是否开着;关着时页面状态只是保留的基准,不检测。 |
| `gate` | string |  | 该站租户的 WAF 增强判定档:full 可更新基准;readonly 与 basic 不可。 可选值: ["full","readonly","basic"] |
| `gate_expired_at` | string |  | 仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。 (只读) |
| `gate_owner` | WafGateOwner |  | 站点属主,仅管理员响应带;租户响应不带别人的信息。 (只读) |
| `gate_packages` | string[] |  | 仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。 (只读) |
| `gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |
| `kind` | string |  | 来自哪类保护范围。 可选值: ["home","page","dir"] |
| `last_change_action` | string |  | 最近一次篡改的节点处置:replace 返回了基准页;log 只记录(含观察期)。 可选值: ["replace","log"] |
| `last_change_at` | string |  | 最近一次检出篡改的时间;基准以来没有为 null。 |
| `last_change_summary` | string |  | 最近一次篡改的变化摘要,如 link=bad.example.net, title。 |
| `note` | string |  | 没纳入基准的原因,取值同 SiteTamperPage.note;纳入的页不出。 可选值: ["too_large","site_limit","fetch_failed","not_html"] |
| `observe_until` | string |  | 该站防篡改观察期截止;开着且在观察期内才有值(同 SiteTamperGuard.observe_until),关着或没有观察期为 null;已过期的截止时间照回,由调用方比对当前时间。 |
| `path` | string |  | 页面路径。 |
| `site_id` | integer |  | 网站 id。 |
| `size` | integer |  | 基准页字节数。 |
| `state` | string |  | 页面状态:normal 正常;tampered 基准以来检出过篡改;excluded 没纳入基准(原因见 note)。 可选值: ["normal","tampered","excluded"] |

## 套餐 (`packages`)

可售卖的基础套餐,定义流量、带宽、域名数等额度与价格。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/packages

### GET `/api/v2/packages`

列出套餐 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/packages" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/packages`

创建套餐 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_group_id` | integer |  | 备用线路分组;null = 没有 |
| `bandwidth_mbps` | integer |  | 带宽 Mbps,-1 不限 |
| `buy_limit` | integer |  | 每租户最多持有几份,-1 不限 |
| `cname_domain_id` | integer |  | 接入根域(CNAME 域名);null = 套餐不绑线路 |
| `cname_host_suffix` | string |  | 新生成主机记录的后缀;空 = 只有 8 位随机名 |
| `cname_mode` | PackageCnameMode |  | CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。 可选值: ["site","package"] |
| `connections` | integer |  | 并发连接数,-1 不限 |
| `custom_cc_rule` | boolean |  | 可自定义 CC 规则 |
| `des` | string |  | 备注说明 |
| `domains` | integer |  | 域名数(IP 站每站占 1),-1 不限 |
| `enabled` | boolean |  | 是否启用 |
| `group_ids` | integer[] |  | 所属套餐分组 |
| `http_ports` | integer |  | HTTP/HTTPS 非标端口数(80/443 之外),-1 不限 |
| `ip_num` | integer |  | 可选 IP 数(「我的 IP」),-1 不限 |
| `ip_pool_id` | integer |  | 开通 IP 站点用的 IP 池(IP 产品线);null = 不开通 |
| `ip_site_port` | integer |  | IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数 |
| `l2` | boolean |  | 含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true) |
| `name` | string | 有 | 名称 |
| `node_group_id` | integer |  | 主线路分组;null = 套餐不绑线路 |
| `origin_ip_limit` | string[] |  | 允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许 |
| `owners` | integer[] |  | 限定可购买的租户 id;空 = 不限 |
| `price_month_cents` | integer | 有 | 月价,分 |
| `price_quarter_cents` | integer | 有 | 季价,分 |
| `price_year_cents` | integer | 有 | 年价,分 |
| `region_id` | integer |  | 区域;null = 套餐不绑线路 |
| `renew_before_days` | integer |  | 到期前几天内才许续费,-1 不限 |
| `require_verified` | boolean |  | 须实名认证才能购买 |
| `sale_until` | string |  | 过了此刻不再出售;不给/null = 不限 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `stream_ports` | integer |  | 四层转发端口数,-1 不限 |
| `traffic_gb` | integer |  | 每计费周期流量 GB,-1 不限 |
| `waf_enhanced` | boolean |  | 含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false |
| `websocket` | boolean |  | 可开 WebSocket |

```sh
curl -X POST "https://panel.example.com/api/v2/packages" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domains":10,"group_ids":[],"http_ports":2,"name":"基础版","price_month_cents":3000,"price_quarter_cents":8000,"price_year_cents":30000}'
```

### POST `/api/v2/packages/batch-enable`

批量启用或禁用套餐 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `enabled` | boolean | 有 | 是否启用 |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/packages/batch-enable" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false,"ids":[1,2]}'
```

### GET `/api/v2/packages/{id}`

获取套餐 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/packages/{id}`

修改套餐 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_group_id` | integer |  | 备用线路分组;null = 没有 |
| `bandwidth_mbps` | integer |  | 带宽 Mbps,-1 不限 |
| `buy_limit` | integer |  | 每租户最多持有几份,-1 不限 |
| `cname_domain_id` | integer |  | 接入根域(CNAME 域名);null = 套餐不绑线路 |
| `cname_host_suffix` | string |  | 新生成主机记录的后缀;空 = 只有 8 位随机名 |
| `cname_mode` | PackageCnameMode |  | CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。 可选值: ["site","package"] |
| `connections` | integer |  | 并发连接数,-1 不限 |
| `custom_cc_rule` | boolean |  | 可自定义 CC 规则 |
| `des` | string |  | 备注说明 |
| `domains` | integer |  | 域名数(IP 站每站占 1),-1 不限 |
| `enabled` | boolean |  | 是否启用 |
| `group_ids` | integer[] |  | 所属套餐分组 |
| `http_ports` | integer |  | HTTP/HTTPS 非标端口数(80/443 之外),-1 不限 |
| `ip_num` | integer |  | 可选 IP 数(「我的 IP」),-1 不限 |
| `ip_pool_id` | integer |  | 开通 IP 站点用的 IP 池(IP 产品线);null = 不开通 |
| `ip_site_port` | integer |  | IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数 |
| `l2` | boolean |  | 含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true) |
| `name` | string | 有 | 名称 |
| `node_group_id` | integer |  | 主线路分组;null = 套餐不绑线路 |
| `origin_ip_limit` | string[] |  | 允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许 |
| `owners` | integer[] |  | 限定可购买的租户 id;空 = 不限 |
| `price_month_cents` | integer | 有 | 月价,分 |
| `price_quarter_cents` | integer | 有 | 季价,分 |
| `price_year_cents` | integer | 有 | 年价,分 |
| `region_id` | integer |  | 区域;null = 套餐不绑线路 |
| `renew_before_days` | integer |  | 到期前几天内才许续费,-1 不限 |
| `require_verified` | boolean |  | 须实名认证才能购买 |
| `sale_until` | string |  | 过了此刻不再出售;不给/null = 不限 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `stream_ports` | integer |  | 四层转发端口数,-1 不限 |
| `traffic_gb` | integer |  | 每计费周期流量 GB,-1 不限 |
| `waf_enhanced` | boolean |  | 含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false |
| `websocket` | boolean |  | 可开 WebSocket |

```sh
curl -X PUT "https://panel.example.com/api/v2/packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domains":10,"group_ids":[],"http_ports":2,"name":"基础版","price_month_cents":3000,"price_quarter_cents":8000,"price_year_cents":30000}'
```

### DELETE `/api/v2/packages/{id}`

删除套餐 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/packages/{id}/syncs`

同步基础套餐到已购套餐 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | PackageSyncField[] | 有 | 要同步的字段 |

```sh
curl -X POST "https://panel.example.com/api/v2/packages/{id}/syncs" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":["traffic_gb","price_month_cents"]}'
```

套餐对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_group_id` | integer |  | 备用线路分组;null = 没有 |
| `bandwidth_mbps` | integer |  | 带宽 Mbps,-1 不限 |
| `buy_limit` | integer |  | 每租户最多持有几份,-1 不限 |
| `cname_domain_id` | integer |  | 接入根域(CNAME 域名);null = 套餐不绑线路 |
| `cname_host_suffix` | string |  | 新生成主机记录的后缀;空 = 只有 8 位随机名 |
| `cname_mode` | PackageCnameMode |  | CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。 可选值: ["site","package"] |
| `connections` | integer |  | 并发连接数,-1 不限 |
| `created_at` | string |  | 创建时间 (只读) |
| `custom_cc_rule` | boolean |  | 可自定义 CC 规则 |
| `des` | string |  | 备注说明 |
| `domains` | integer |  | 域名数(IP 站每站占 1),-1 不限 |
| `enabled` | boolean |  | 是否启用 |
| `errors` | FieldError[] |  | 没改的逐条原因;field 为 /ids/<下标>,code 同单条修改接口(not_found、readonly 等)。 |
| `group_ids` | integer[] |  | 所属套餐分组 |
| `http_ports` | integer |  | HTTP/HTTPS 非标端口数(80/443 之外),-1 不限 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] | 有 | 要改的对象 id,至多 100 个。 |
| `ip_num` | integer |  | 可选 IP 数(「我的 IP」),-1 不限 |
| `ip_pool_id` | integer |  | 开通 IP 站点用的 IP 池(IP 产品线);null = 不开通 |
| `ip_site_port` | integer |  | IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数 |
| `items` | PackageSyncField[] | 有 | 要同步的字段 |
| `l2` | boolean |  | 含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true) |
| `name` | string |  | 名称 |
| `node_group_id` | integer |  | 主线路分组;null = 套餐不绑线路 |
| `origin_ip_limit` | string[] |  | 允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许 |
| `owners` | integer[] |  | 限定可购买的租户 id;空 = 不限 |
| `price_month_cents` | integer |  | 月价,分 |
| `price_quarter_cents` | integer |  | 季价,分 |
| `price_year_cents` | integer |  | 年价,分 |
| `region_id` | integer |  | 区域;null = 套餐不绑线路 |
| `renew_before_days` | integer |  | 到期前几天内才许续费,-1 不限 |
| `require_verified` | boolean |  | 须实名认证才能购买 |
| `sale_until` | string |  | 过了此刻不再出售;不给/null = 不限 |
| `skipped` | integer |  | 不跟随或至少一个改动字段单独改过而跳过的个数(其余字段照常同步) |
| `skipped_ids` | integer[] |  | 被跳过的已购套餐 id |
| `sort` | integer |  | 排序值(小的在前)。 |
| `stream_ports` | integer |  | 四层转发端口数,-1 不限 |
| `sync` | PackageSyncResult |  | 同步结果。 |
| `synced` | integer |  | 已同步的已购套餐数(自动同步时 = 本次改动的字段全部同步了的个数) |
| `traffic_gb` | integer |  | 每计费周期流量 GB,-1 不限 |
| `updated` | integer[] |  | 已改好的 id(含本来就是目标状态的),按请求顺序。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `waf_enhanced` | boolean |  | 含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false |
| `websocket` | boolean |  | 可开 WebSocket |

## 套餐分组 (`package-groups`)

把套餐分组展示,便于客户选购。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/package-groups

### GET `/api/v2/package-groups`

列出套餐分组 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/package-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/package-groups`

创建套餐分组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/package-groups" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"入门套餐"}'
```

### GET `/api/v2/package-groups/{id}`

获取套餐分组 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/package-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/package-groups/{id}`

修改套餐分组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/package-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"入门套餐"}'
```

### DELETE `/api/v2/package-groups/{id}`

删除套餐分组 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/package-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

套餐分组对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `updated_at` | string |  | 更新时间 (只读) |

## 升级包 (`package-upgrades`)

在基础套餐之上按份加购的额度或功能。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/package-upgrades

### GET `/api/v2/package-upgrades`

列出升级包 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |

```sh
curl "https://panel.example.com/api/v2/package-upgrades" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/package-upgrades`

创建升级包 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | integer |  | 每份加多少;功能类(custom_cc_rule/websocket)恒为 1 |
| `bind_packages` | integer[] |  | 只许这些基础套餐加购;空 = 不限 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `name` | string | 有 | 名称 |
| `price_cents` | integer | 有 | 每份每月价格,分 |
| `type` | string | 有 | 加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数 可选值: ["traffic","domain","http_port","stream_port","custom_cc_rule","bandwidth","connection","websocket","ip_num"] |

```sh
curl -X POST "https://panel.example.com/api/v2/package-upgrades" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":10,"name":"域名 +10","price_cents":1000,"type":"domain"}'
```

### GET `/api/v2/package-upgrades/{id}`

获取升级包 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/package-upgrades/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/package-upgrades/{id}`

修改升级包 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | integer |  | 每份加多少;功能类(custom_cc_rule/websocket)恒为 1 |
| `bind_packages` | integer[] |  | 只许这些基础套餐加购;空 = 不限 |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `name` | string | 有 | 名称 |
| `price_cents` | integer | 有 | 每份每月价格,分 |
| `type` | string | 有 | 加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数 可选值: ["traffic","domain","http_port","stream_port","custom_cc_rule","bandwidth","connection","websocket","ip_num"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/package-upgrades/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":10,"name":"域名 +10","price_cents":1000,"type":"domain"}'
```

### DELETE `/api/v2/package-upgrades/{id}`

删除升级包 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/package-upgrades/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

升级包对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | integer |  | 每份加多少;功能类(custom_cc_rule/websocket)恒为 1 |
| `bind_packages` | integer[] |  | 只许这些基础套餐加购;空 = 不限 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `enabled` | boolean |  | 是否启用 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `price_cents` | integer |  | 每份每月价格,分 |
| `type` | string |  | 加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数 可选值: ["traffic","domain","http_port","stream_port","custom_cc_rule","bandwidth","connection","websocket","ip_num"] |
| `updated_at` | string |  | 更新时间 (只读) |

## 套餐目录 (`package-catalog`)

客户可购买的套餐、分组与升级包目录。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/package-catalog

### GET `/api/v2/package-catalog`

可购买的套餐目录 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/package-catalog" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

套餐目录对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `groups` | PackageGroup[] |  | 套餐分组。 |
| `packages` | Package[] |  | 在售的基础套餐。 |
| `upgrades` | PackageUpgrade[] |  | 在售的升级包。 |

## 已购套餐 (`user-packages`)

租户已购买的套餐:购买、续费、更换、加购升级包与用量查看。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/user-packages

### GET `/api/v2/user-packages`

列出用户套餐 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ids` | string |  | 只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。 |
| `package_id` | integer |  | 只列这个基础套餐的用户套餐。 |
| `expire_within_days` | integer |  | 只列这么多天内到期(含已到期)的用户套餐。 |
| `name` | string |  | 用户套餐名称包含(% _ 按字面匹配)。 |
| `customized` | boolean |  | true 只列单独改过额度或不跟随基础套餐的已购套餐,false 只列跟随中且没单独改过的。 |

```sh
curl "https://panel.example.com/api/v2/user-packages" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/user-packages`

购买用户套餐 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dry_run` | boolean |  | 只报价不落库 |
| `duration` | string |  | 时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。 可选值: ["month","quarter","year"] |
| `end_at` | string |  | 套餐到期时间。 |
| `name` | string |  | 名称 |
| `package_id` | integer | 有 | 基础套餐 id |

```sh
curl -X POST "https://panel.example.com/api/v2/user-packages" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"duration":"month","package_id":1}'
```

### GET `/api/v2/user-packages/{id}`

获取用户套餐 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/user-packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/user-packages/{id}`

修改用户套餐 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `backup_group_id` | integer |  | 备用线路分组;null = 没有 |
| `bandwidth_mbps` | integer |  | 带宽 Mbps,-1 不限 |
| `cname_domain_id` | integer |  | 接入根域(CNAME 域名);null = 套餐不绑线路 |
| `cname_hostname` | string |  | 共用接入名的主机记录(按套餐生成时下属站点/转发共用);空 = 还没有 |
| `cname_mode` | PackageCnameMode |  | CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。 可选值: ["site","package"] |
| `connections` | integer |  | 并发连接数,-1 不限 |
| `custom_cc_rule` | boolean |  | 可自定义 CC 规则 |
| `domains` | integer |  | 域名数(IP 站每站占 1),-1 不限 |
| `end_at` | string |  | 套餐到期时间。 |
| `follow_base` | boolean |  | 跟随基础套餐:改基础套餐的配额类字段时自动同步到本套餐(overrides 里的字段除外) |
| `http_ports` | integer |  | HTTP/HTTPS 非标端口数(80/443 之外),-1 不限 |
| `ip_num` | integer |  | 可选 IP 数(「我的 IP」),-1 不限 |
| `ip_pool_id` | integer |  | 开通 IP 站点用的 IP 池(IP 产品线);null = 不开通 |
| `ip_site_port` | integer |  | IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数 |
| `l2` | boolean |  | 含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true) |
| `name` | string |  | 名称 |
| `node_group_id` | integer |  | 主线路分组;null = 套餐不绑线路 |
| `price_month_cents` | integer |  | 购买时锁定的月价 |
| `price_quarter_cents` | integer |  | 锁定季价 |
| `price_year_cents` | integer |  | 锁定年价 |
| `region_id` | integer |  | 区域;null = 套餐不绑线路 |
| `reset_to_base` | boolean |  | 仅管理员:true = 配额类字段恢复为基础套餐的值、清空 overrides 并恢复跟随(不能与其它字段同时给) |
| `stream_ports` | integer |  | 四层转发端口数,-1 不限 |
| `traffic_gb` | integer |  | 每计费周期流量 GB,-1 不限 |
| `waf_enhanced` | boolean |  | 含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false |
| `websocket` | boolean |  | 可开 WebSocket |

```sh
curl -X PUT "https://panel.example.com/api/v2/user-packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"主站套餐"}'
```

### DELETE `/api/v2/user-packages/{id}`

删除用户套餐 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/user-packages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/user-packages/{id}/changes`

更换套餐(升级/降级) · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dry_run` | boolean |  | 只报价不落库 |
| `package_id` | integer | 有 | 基础套餐 id |

```sh
curl -X POST "https://panel.example.com/api/v2/user-packages/{id}/changes" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"package_id":2}'
```

### GET `/api/v2/user-packages/{id}/ips`

我的 IP · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/user-packages/{id}/ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/user-packages/{id}/ips`

选择 IP · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ip_ids` | integer[] | 有 | 要选的池内 IP ID 列表。 |

```sh
curl -X POST "https://panel.example.com/api/v2/user-packages/{id}/ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/user-packages/{id}/ips/{ip_id}`

修改已选 IP 的备注 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `remark` | string | 有 | 备注 |

```sh
curl -X PUT "https://panel.example.com/api/v2/user-packages/{id}/ips/{ip_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/user-packages/{id}/ips/{ip_id}`

移除已选 IP · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/user-packages/{id}/ips/{ip_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/user-packages/{id}/node-groups`

用户套餐的线路分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/user-packages/{id}/node-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/user-packages/{id}/renewals`

续费用户套餐 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `dry_run` | boolean |  | 只报价不落库 |
| `duration` | string | 有 | 时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。 可选值: ["month","quarter","year"] |

```sh
curl -X POST "https://panel.example.com/api/v2/user-packages/{id}/renewals" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"duration":"month"}'
```

### GET `/api/v2/user-packages/{id}/upgrades`

列出已购升级包 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/user-packages/{id}/upgrades" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/user-packages/{id}/upgrades`

加购升级包 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | integer |  | 份数,默认 1 |
| `dry_run` | boolean |  | 只报价不落库 |
| `upgrade_id` | integer | 有 | 要加购的升级包 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/user-packages/{id}/upgrades" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":1,"upgrade_id":1}'
```

### DELETE `/api/v2/user-packages/{id}/upgrades/{upgrade_id}`

减少或移除已购升级包 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | integer |  | 减少的份数;不带 = 整项移除。 |

```sh
curl -X DELETE "https://panel.example.com/api/v2/user-packages/{id}/upgrades/{upgrade_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/user-packages/{id}/usage`

用户套餐用量 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/user-packages/{id}/usage" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

已购套餐对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 操作类型:购买、续费、更换套餐或加购升级包。 可选值: ["buy","renew","change","upgrade"] |
| `added` | integer[] |  | 本次新选中的池内 IP ID。 |
| `amount` | integer |  | 份数,默认 1 |
| `amount_cents` | integer |  | 正 = 扣款,负 = 退回余额(降级),0 = 不收费(含管理员操作) |
| `backup_group_id` | integer |  | 备用线路分组;null = 没有 |
| `bandwidth_mbps` | integer |  | 带宽 Mbps,-1 不限 |
| `cert_auto` | IpCertState |  | 平台 IP 证书状态。 |
| `cname_domain_id` | integer |  | 接入根域(CNAME 域名);null = 套餐不绑线路 |
| `cname_hostname` | string |  | 共用接入名的主机记录(按套餐生成时下属站点/转发共用);空 = 还没有 |
| `cname_mode` | PackageCnameMode |  | CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。 可选值: ["site","package"] |
| `connections` | integer |  | 并发连接数,-1 不限 |
| `created_at` | string |  | 创建时间 (只读) |
| `custom_cc_rule` | boolean |  | 可自定义 CC 规则 |
| `cycle_end` | string |  | 本计费周期结束时间。 |
| `cycle_start` | string |  | 本计费周期开始时间。 |
| `domains` | integer |  | 域名数(IP 站每站占 1),-1 不限 |
| `dry_run` | boolean |  | 只报价不落库 |
| `duration` | string |  | 时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。 可选值: ["month","quarter","year"] |
| `enabled` | boolean |  | 是否启用 |
| `end_at` | string |  | 套餐到期时间。 |
| `follow_base` | boolean |  | 跟随基础套餐:改基础套餐的配额类字段时自动同步到本套餐(overrides 里的字段除外) (只读) |
| `http_ports` | integer |  | HTTP/HTTPS 非标端口数(80/443 之外),-1 不限 |
| `id` | integer |  | 记录 ID (只读) |
| `in_pool` | boolean |  | 仍在该套餐当前的 IP 池里。 |
| `ip` | string |  | IP 地址。 |
| `ip_ids` | integer[] | 有 | 要选的池内 IP ID 列表。 |
| `ip_num` | integer |  | 可选 IP 数(「我的 IP」),-1 不限 |
| `ip_pool_id` | integer |  | 开通 IP 站点用的 IP 池(IP 产品线);null = 不开通 |
| `ip_site_port` | integer |  | IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数 |
| `items` | UserPackageIp[] |  | 本页条目 |
| `l2` | boolean |  | 含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true) |
| `limit` | integer |  | 可选个数,-1 不限。 |
| `limits` | PackageLimits |  | 有效额度(套餐值 + 升级包;-1 不限,功能类 0/1)。 |
| `name` | string |  | 名称 |
| `node_group_id` | integer |  | 主线路分组;null = 套餐不绑线路 |
| `node_state` | IpNodeState |  | 持有主节点状态:停用 disabled;否则最近 2 分钟有心跳 online,没有 offline。 可选值: ["online","offline","disabled"] |
| `order_id` | integer |  | 订单 id(扣款/退款时) |
| `overrides` | PackageQuotaField[] |  | 管理员单独改过且与基础套餐不同的配额类字段,自动同步时跳过 (只读) |
| `package_id` | integer |  | 基础套餐 id |
| `package_name` | string |  | 基础套餐名(套餐列表与订单展示用) (只读) |
| `period` | string |  | 更换套餐时折算所用的价目 可选值: ["month","quarter","year"] |
| `price_month_cents` | integer |  | 购买时锁定的月价 |
| `price_quarter_cents` | integer |  | 锁定季价 |
| `price_year_cents` | integer |  | 锁定年价 |
| `region` | string |  | 所属区域名称。 |
| `region_id` | integer |  | 区域;null = 套餐不绑线路 |
| `remain_days` | integer |  | 折算用的剩余天数 |
| `remark` | string | 有 | 备注 |
| `requests` | integer |  | 本计费周期的请求数(已封账小时 + 还没封账的小时现算)。 |
| `reset_to_base` | boolean |  | 仅管理员:true = 配额类字段恢复为基础套餐的值、清空 overrides 并恢复跟随(不能与其它字段同时给) |
| `selected` | integer |  | 已选 IP 个数。 |
| `sites` | object[] |  | 本套餐里绑定它的 IP 站点。 |
| `start_at` | string |  | 套餐生效时间。 |
| `status` | string |  | expired = 已到期(名下站点停服 512,续费恢复) 可选值: ["active","expired"] |
| `stream_ports` | integer |  | 四层转发端口数,-1 不限 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `traffic_bytes` | integer |  | 本计费周期已用计费流量(字节,已乘补偿系数):已封账小时 + 还没封账的小时现算,与流量超额停站同口径。 |
| `traffic_gb` | integer |  | 每计费周期流量 GB,-1 不限 |
| `traffic_limit_gb` | integer |  | 有效流量额度(GB,1 GB = 1024³ 字节,含升级包);-1 不限。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `upgrade_id` | integer | 有 | 要加购的升级包 id。 |
| `user_package` | UserPackage |  | 办理后的用户套餐。 |
| `user_package_id` | integer |  | 办理的用户套餐 id(购买时即新建的那一条,等于 user_package.id);试算(dry_run)没落库,不带。 |
| `waf_enhanced` | boolean |  | 含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false |
| `websocket` | boolean |  | 可开 WebSocket |

## 套餐监控 (`package-monitor`)

仅管理员:近 1 分钟各用户套餐的带宽与连接数。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/package-monitor

### GET `/api/v2/package-monitor`

套餐监控 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `user_package_id` | integer |  | 按用户套餐 id 过滤。 |
| `node_id` | integer |  | 节点 ID |

```sh
curl "https://panel.example.com/api/v2/package-monitor" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/package-monitor/{id}/nodes`

套餐监控(按节点) · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/package-monitor/{id}/nodes" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

套餐监控对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `bandwidth_bps` | integer |  | 最近 1 分钟各节点出站带宽之和(bit/s)。 |
| `bandwidth_limit_mbps` | integer |  | 有效带宽额度(含升级包);-1 不限。 |
| `connections` | integer |  | 最近 1 分钟各节点连接数峰值之和。 |
| `connections_limit` | integer |  | 有效连接数额度(含升级包);-1 不限。 |
| `items` | PackageMonitorNode[] |  | 本页条目 |
| `name` | string |  | 名称 |
| `tenant_id` | integer |  | 所属租户(用户)ID |
| `user_package_id` | integer |  | 已购套餐 ID。 |

## 网站 (`sites`)

CDN 加速站点。新建至少要域名与源站;管理员可跨租户管理。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/sites

### GET `/api/v2/sites`

列出站点 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ids` | string |  | 只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。 |
| `domain` | string |  | 按域名子串过滤(不分大小写):a.example.com 也会命中 www.a.example.com;精确查用 domains。 |
| `domains` | string |  | 多个域名逗号分隔,站点任一域名与其中之一整项相同即命中(不分大小写,不做子串匹配)。 |
| `group_id` | integer |  | 只列该分组里的站点。 |
| `group_ids` | string |  | 多个分组 id 逗号分隔(正整数,去重后至多 200 个),站点在其中任一分组里即命中;可与 group_id 同用(两者都要满足)。 |
| `app` | string |  | 按体检识别出的程序(report_checkup_sites.app,如 wordpress)精确过滤;还没体检过的站点不命中。 |
| `enabled` | boolean |  | 按启停过滤。 |
| `id` | integer |  | 按站点 id 精确过滤。 |
| `name` | string |  | 按名称子串过滤。 |
| `origin` | string |  | 按源站主机子串过滤。 |
| `stop_code` | integer |  | 按停服码过滤;0 = 正常。 |
| `upid` | integer |  | 按用户套餐过滤。 |
| `http_port` | integer |  | 只列 HTTP 监听端口(config.http_ports)里有这个端口的站点,整段匹配。 |
| `https_port` | integer |  | 只列 HTTPS 监听端口(config.https.ports)里有这个端口的站点;没开 HTTPS 的不算,整段匹配。 |
| `https_enabled` | boolean |  | true 只列开了 HTTPS(config.https 有监听端口)的站点,false 只列没开的。 |
| `package_id` | integer |  | 按基础套餐过滤。 |
| `region_id` | integer |  | 按区域过滤:接入名的主线路分组属于该区域;没有自己接入名的按所属已售套餐的共用接入名算。 |
| `node_group_id` | integer |  | 按线路分组过滤:接入名的主线路分组或备用线路分组是它。 |
| `cname_domain_id` | integer |  | 按接入根域过滤。 |
| `cname_hostname` | string |  | 按接入名主机记录精确过滤。 |
| `sync_state` | string |  | 按配置同步状态过滤:behind = 配置落后(还有在线节点没装上它最近一次修改后的配置版本); 可选值: ["behind","synced"] |

```sh
curl "https://panel.example.com/api/v2/sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites`

创建站点 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `config` | object |  | 节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。 |
| `domains` | string[] | 有 | 站点绑定的域名。 |
| `enabled` | boolean |  | 是否启用 |
| `group_ids` | integer[] |  | 站点所属分组的 id。 |
| `name` | string |  | 名称 |
| `origins` | SiteOrigin[] | 有 | 源站列表。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `upid` | integer |  | 用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domains":["www.example.com"],"name":"demo","origins":[{"host":"203.0.113.10"}]}'
```

### POST `/api/v2/sites/batch`

批量操作站点 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | 批量动作:set_enabled(启停)、delete(删除)、set_groups(设置分组)、update_config(合并配置)、create(批量新建)。 可选值: ["set_enabled","delete","set_groups","update_config","create"] |
| `config` | object |  | 节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。 |
| `enabled` | boolean |  | 是否启用 |
| `group_ids` | integer[] |  | 站点所属分组的 id。 |
| `ids` | integer[] |  | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |
| `items` | SiteWrite[] |  | create 用:要新建的站点(最多 100 个),每条同 POST /sites 的请求体。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/batch" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"set_enabled","enabled":false,"ids":[1]}'
```

### POST `/api/v2/sites/checkup-fix-batch`

批量一键修复体检问题 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `batch` | string |  | 只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。 |
| `ids` | integer[] | 有 | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |
| `key` | string | 有 | 要修复的体检项键,含义同单站一键修复。 可选值: ["no_https","tls_old","sec_headers","waf_block","cc_mid","rec_type"] |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/checkup-fix-batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/checkup-fix-batches`

列出最近的体检修复批次 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/sites/checkup-fix-batches" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/origin-alerts`

源站内容不一致告警 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_id` | integer |  | 只看该站点。 |

```sh
curl "https://panel.example.com/api/v2/sites/origin-alerts" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/protect-recommend/apply`

批量套用推荐防护配置 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | integer[] | 有 | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |
| `observe_days` | integer |  | 覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。 |
| `skip` | string[] |  | 用户取消勾选、本次不套用的推荐项。 |
| `type` | string | 有 | 网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。 可选值: ["corporate","shop","content","api","admin","download"] |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/protect-recommend/apply" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/protect-recommend/preview`

预览推荐防护配置的影响 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | integer[] | 有 | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |
| `observe_days` | integer |  | 覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。 |
| `skip` | string[] |  | 用户取消勾选、本次不套用的推荐项。 |
| `type` | string |  | 网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。 可选值: ["corporate","shop","content","api","admin","download"] |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/protect-recommend/preview" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/protect-recommend/undo`

撤销一批推荐防护配置 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `batch` | string | 有 | 只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。 |
| `ids` | integer[] | 有 | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/protect-recommend/undo" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/region-check`

地区限制保存前检查 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `region_limit` | object | 有 | 要检查的地区限制(同 Site.config.region_limit)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/region-check" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"region_limit":{"country":["JP"],"mode":"block"}}'
```

### POST `/api/v2/sites/select-ids`

取筛选结果的全部站点 id · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `app` | string |  | 按体检识别出的程序精确过滤。 |
| `domain` | string |  | 按域名子串过滤(不分大小写)。 |
| `domains` | string[] |  | 站点绑定的域名。 |
| `enabled` | boolean |  | 是否启用 |
| `group_id` | integer |  | 只取该分组里的站点。 |
| `group_ids` | integer[] |  | 站点所属分组的 id。 |
| `name` | string |  | 名称 |
| `origin` | string |  | 按源站主机子串过滤。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `upid` | integer |  | 用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/select-ids" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}`

获取站点 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/sites/{id}`

修改站点 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `config` | object |  | 节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。 |
| `domains` | string[] |  | 站点绑定的域名。 |
| `enabled` | boolean |  | 是否启用 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `group_ids` | integer[] |  | 站点所属分组的 id。 |
| `name` | string |  | 名称 |
| `origins` | SiteOrigin[] |  | 源站列表。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `upid` | integer |  | 用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'
```

### DELETE `/api/v2/sites/{id}`

删除站点 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/{id}/checkup-fix`

一键修复体检问题 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `key` | string | 有 | 要修复的体检项键,含义同单站一键修复。 可选值: ["no_https","tls_old","sec_headers","waf_block","cc_mid","rec_type"] |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/{id}/checkup-fix" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key":"no_https"}'
```

### GET `/api/v2/sites/{id}/health`

站点回源健康状态 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/sites/{id}/health" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}/l2`

查看网站分层回源 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/sites/{id}/l2" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PATCH `/api/v2/sites/{id}/l2`

修改网站分层回源 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `enabled` | boolean |  | 是否启用 |
| `l2_group_id` | integer |  | 使用的 L2 组;null = 区域默认。 |
| `l2_pick` | string |  | 本站选 L2 的方式;null = 跟默认设置。 可选值: ["region","near"] |
| `origin_l2_only` | boolean |  | 源站只允许 L2 访问:动态请求也经 L2,本区域没 L2 时借用其他区域。 |
| `origin_max_conns` | integer |  | 源站最大并发(每节点在途);0 = 不限,超了排队不报 503。 |

```sh
curl -X PATCH "https://panel.example.com/api/v2/sites/{id}/l2" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}/l2-egress-ips`

源站放行清单 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `fmt` | string |  | text 的格式:ip 每行一个、nginx allow 行、iptables 规则;缺省 ip。 可选值: ["ip","nginx","iptables"] 默认: "ip" |

```sh
curl "https://panel.example.com/api/v2/sites/{id}/l2-egress-ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}/l2-stats`

网站的分层回源统计 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/sites/{id}/l2-stats" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/sites/{id}/site-type`

设置网站类型 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 有 | 网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。 可选值: ["corporate","shop","content","api","admin","download"] |

```sh
curl -X PUT "https://panel.example.com/api/v2/sites/{id}/site-type" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"shop"}'
```

### GET `/api/v2/sites/{id}/speed`

站点加速效果 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `range` | string |  | 统计窗口,缺省 24h。 可选值: ["1h","24h","7d"] 默认: "24h" |

```sh
curl "https://panel.example.com/api/v2/sites/{id}/speed" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}/upload-scan/exceptions`

列出站点的上传扫描例外 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/sites/{id}/upload-scan/exceptions" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/{id}/upload-scan/false-positive`

标记站点的上传扫描误报 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `path` | string |  | 路径前缀(以 / 开头);不给取 /。 |
| `sha256` | string |  | 命中文件的 sha256(小写十六进制);租户提交时须是本站上传命中事件里出现过的指纹;给了且情报共享开着、sig 非空时同事务内记一条误报情报待上报。 |
| `sig` | string |  | 误报的特征名(事件规则名,如 webshell.php.eval);空 = 该路径整段不扫描(此时必须给 path)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/{id}/upload-scan/false-positive" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path":"/upload/avatar/","sig":"ext:php"}'
```

### DELETE `/api/v2/sites/{id}/upload-scan/false-positive`

撤销站点标记的上传扫描误报 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `path` | string | 有 | 例外的路径前缀。 |
| `sig` | string |  | 例外的特征名;不给或空 = 路径整段例外。 |

```sh
curl -X DELETE "https://panel.example.com/api/v2/sites/{id}/upload-scan/false-positive" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/sites/{id}/url-guard/active`

列出站点在途的全网 URL 防护 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/sites/{id}/url-guard/active" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/sites/{id}/url-guard/revoke`

手动撤销站点在途的全网 URL 防护 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `path` | string |  | 路径前缀(以 / 开头);不给取 /。 |

```sh
curl -X POST "https://panel.example.com/api/v2/sites/{id}/url-guard/revoke" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

网站对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | 批量动作:set_enabled(启停)、delete(删除)、set_groups(设置分组)、update_config(合并配置)、create(批量新建)。 可选值: ["set_enabled","delete","set_groups","update_config","create"] |
| `added_at` | string |  | 加入时间;早期手工条目没有。 |
| `affected` | integer |  | 受影响的条数 |
| `app` | string |  | 按体检识别出的程序精确过滤。 |
| `batch` | string |  | 只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。 |
| `capacity_warnings` | SiteCapacityWarning[] |  | 只在建站(POST /sites)与改到别的线路分组(PUT /sites/{id})的响应里、目标线路分组有节点站数已达内存容量上限时给出;只提示不拦截,没有超限节点时不给这个字段。 (只读) |
| `checked_at` | string |  | 本次向节点要明细的时间。 |
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `config` | object |  | 节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。 |
| `country` | string |  | 国家/地区编号,没有不给。 |
| `created_at` | string |  | 创建时间 (只读) |
| `default_pick` | string |  | 默认设置当前的方式(l2_pick 为 null 时生效)。 可选值: ["region","near"] |
| `domain` | string |  | 按域名子串过滤(不分大小写)。 |
| `domains` | string[] |  | 站点绑定的域名。 |
| `edge_origin_requests` | integer |  | 边缘回源请求数(命中率分母)。 |
| `enabled` | boolean |  | 是否启用 |
| `end` | string |  | 窗口右端(不含,取整到 5 分钟)。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `found` | boolean |  | 库里查到了这个 IP(否则按未识别的访客判)。 |
| `gate_reasons` | SiteGateReasonIds |  | ids 里 WAF 增强没生效的站点按原因分组(只列有原因的;全都生效时整个字段不给)。选择器据此给 package 的站点标「套餐不含」并禁勾。 (只读) |
| `group_id` | integer |  | 只取该分组里的站点。 |
| `group_ids` | integer[] |  | 站点所属分组的 id。 |
| `group_options` | L2SiteRefGroup[] |  | 可选的自建 L2 组。 |
| `hit_rate` | number |  | 命中率 0–1;没有回源为 0。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] |  | 要操作的站点 id(最多 100 个;create 以外的动作必填)。 |
| `ip` | string |  | 调用者的 IP。 |
| `isp` | string |  | 运营商编号,没有不给。 |
| `items` | SiteWrite[] |  | create 用:要新建的站点(最多 100 个),每条同 POST /sites 的请求体。 |
| `key` | string | 有 | 要修复的体检项键,含义同单站一键修复。 可选值: ["no_https","tls_old","sec_headers","waf_block","cc_mid","rec_type"] |
| `l2_group_id` | integer |  | 使用的 L2 组;null = 区域默认。 |
| `l2_hit_requests` | integer |  | L2 接住的回源请求数(命中率分子)。 |
| `l2_pick` | string |  | 本站选 L2 的方式;null = 跟默认设置。 可选值: ["region","near"] |
| `log` | SiteSpeedLog |  | 按原始访问日志(按采样权重折算)统计的协议分布、回源耗时分位、未命中地址抽样与边缘响应耗时,窗口同 totals。 |
| `log_keep_days` | integer |  | 原始访问日志保留天数(reports.access_log_days);窗口超出它时 log 只统计还留着的部分。 |
| `missing` | string[] |  | 选了但当前库不含数据的字段(这些选择不会命中)。 |
| `name` | string |  | 名称 |
| `node_issues` | NodeIssue[] |  | 在线节点上站点没完全生效的口或原因(列表与详情里给);都正常时不给这个字段。 (只读) |
| `nodes` | SiteHealthNode[] |  | 各在用节点的明细(按节点 id 升序)。 |
| `observe_days` | integer |  | 覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。 |
| `origin` | string |  | 按源站主机子串过滤。 |
| `origin_l2_only` | boolean |  | 源站只允许 L2 访问:动态请求也经 L2,本区域没 L2 时借用其他区域。 |
| `origin_max_conns` | integer |  | 源站最大并发(每节点在途);0 = 不限,超了排队不报 503。 |
| `origin_requests` | integer |  | 实际到源站的请求数。 |
| `origin_requests_est` | integer |  | 未开分层时的估算(= 边缘回源请求数)。 |
| `origins` | SiteOrigin[] |  | 源站列表。 |
| `path` | string |  | 路径前缀(以 / 开头);不给取 /。 |
| `points` | SiteSpeedPoint[] |  | 按桶的明细(只列有流量的桶)。 |
| `prov` | string |  | 省份编号,没有不给。 |
| `publish_seq` | integer |  | 只在建站、改站的响应里给:这次写操作的序号(同响应头 Publish-Seq),拿它调 GET /config-publish/applied?seq= 查是否已推到节点。 (只读) |
| `range` | string |  | 统计窗口(1h、24h 或 7d)。 |
| `rec_ver` | integer |  | 本次用的推荐表版本。 |
| `region_limit` | object | 有 | 要检查的地区限制(同 Site.config.region_limit)。 |
| `region_names` | string[] |  | 有可用 L2 的区域名,按区域 id 排;个数等于 regions。 |
| `regions` | integer |  | 有可用 L2 的区域数。 |
| `revoked` | string[] |  | 已撤销的路径。 |
| `saved_bytes` | integer |  | 省的回源流量(L2 命中字节)。 |
| `sha256` | string |  | 命中文件的 sha256(小写十六进制);租户提交时须是本站上传命中事件里出现过的指纹;给了且情报共享开着、sig 非空时同事务内记一条误报情报待上报。 |
| `sig` | string |  | 误报的特征名(事件规则名,如 webshell.php.eval);空 = 该路径整段不扫描(此时必须给 path)。 |
| `site_id` | integer |  | 网站 id;0 = 所有网站。 |
| `skip` | string[] |  | 用户取消勾选、本次不套用的推荐项。 |
| `source` | string |  | user 手选;auto 按流量自动判定。 可选值: ["user","auto"] |
| `start` | string |  | 窗口起点。 |
| `state` | string |  | 生效状态:on 生效;off 网站没开;not_open 没开通(含网站所属租户的套餐不含分层回源);paused 全网暂停;no_l2 没有可用的 L2;revoking 生效中但即将停用。 可选值: ["on","off","not_open","paused","no_l2","revoking"] |
| `status` | string |  | disabled 没开主动健康检查;unknown 没有节点回明细;healthy 回了明细的节点上源站全部在线;unhealthy 有源站被摘除。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `text` | string |  | 按 fmt 排好的文本,可直接粘贴到源站。 |
| `total` | integer |  | 真实命中数(可能大于 ids 的长度)。 |
| `totals` | SiteSpeedTotals |  | 整个窗口的合计。 |
| `truncated` | boolean |  | 命中数超过 100000,ids 只含前 100000 个。 |
| `type` | string | 有 | 网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。 可选值: ["corporate","shop","content","api","admin","download"] |
| `updated_at` | string |  | 更新时间 (只读) |
| `upid` | integer |  | 用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。 |
| `verdict` | string |  | 调用者访问首页的结果:pass 放行、block 被拦、log 只记录。 可选值: ["pass","block","log"] |
| `waf_gate` | SiteWafGate |  | 只在站点详情(GET /sites/{id})里给:站点属主的 WAF 增强状态与没生效的原因。owner、packages、expired_at 仅管理员响应带,租户响应只有 gate 与 reason。列表行只有 waf_gate_reason。 (只读) |
| `waf_gate_reason` | WafGateReason |  | WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。 可选值: ["package","license","expired"] (只读) |

## 网站分组 (`site-groups`)

把站点归类管理;同一租户内分组名唯一,分组里还有站点时不能删除。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/site-groups

### GET `/api/v2/site-groups`

列出站点分组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ids` | string |  | 只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。 |

```sh
curl "https://panel.example.com/api/v2/site-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/site-groups`

创建站点分组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |

```sh
curl -X POST "https://panel.example.com/api/v2/site-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/site-groups/{id}`

获取站点分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/site-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/site-groups/{id}`

修改站点分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |

```sh
curl -X PUT "https://panel.example.com/api/v2/site-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/site-groups/{id}`

删除站点分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/site-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

网站分组对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## 缓存分组 (`cache-groups`)

一组缓存规则,可供多个站点引用;分平台分组与租户自建分组。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-groups

### GET `/api/v2/cache-groups`

列出缓存分组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/cache-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cache-groups`

创建缓存分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cache` | CacheConfig |  | 缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。 |
| `des` | string |  | 备注说明 |
| `from_site_id` | integer |  | 从站点另存(规则取该站当前生效值,忽略 cache)。 |
| `is_default` | boolean |  | 平台默认分组(恰一个)。 |
| `name` | string | 有 | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `switch_site` | boolean |  | 另存后让该站引用新分组。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cache-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/cache-groups/{id}`

获取缓存分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cache-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cache-groups/{id}`

修改缓存分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cache` | CacheConfig |  | 缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。 |
| `des` | string |  | 备注说明 |
| `name` | string |  | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cache-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/cache-groups/{id}`

删除缓存分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/cache-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cache-groups/{id}/copy`

复制缓存分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |
| `sort` | integer |  | 排序值(小的在前)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cache-groups/{id}/copy" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cache-groups/{id}/set-default`

设为平台默认分组 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/cache-groups/{id}/set-default" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

缓存分组对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cache` | CacheConfig |  | 缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。 |
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `from_site_id` | integer |  | 从站点另存(规则取该站当前生效值,忽略 cache)。 |
| `id` | integer |  | 记录 ID (只读) |
| `is_default` | boolean |  | 平台默认分组(恰一个)。 (只读) |
| `name` | string |  | 名称 |
| `site_count` | integer |  | 显式引用它的站点数(租户调用只数自己的)。 (只读) |
| `sort` | integer |  | 排序值(小的在前)。 |
| `switch_site` | boolean |  | 另存后让该站引用新分组。 |
| `tenant_id` | integer |  | 属主租户;null = 平台分组。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## 缓存策略 (`cache-policy`)

设置本租户的默认缓存分组,并可把全部站点改回按默认分组。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-policy

### GET `/api/v2/cache-policy`

缓存策略 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/cache-policy" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cache-policy`

设本租户的默认分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `default_group_id` | integer | 有 | 平台默认分组;null = 还没有分组。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cache-policy" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cache-policy/reset-sites`

全部站点改回按默认分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X POST "https://panel.example.com/api/v2/cache-policy/reset-sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

缓存策略对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `applied` | integer |  | 已改回的站点数。 |
| `default_group_id` | integer |  | 平台默认分组;null = 还没有分组。 |
| `my_default_group_id` | integer |  | 本租户生效的默认分组(自己设的,没设为平台默认)。 |
| `my_default_group_set` | boolean |  | 本租户自己设过默认分组。 |
| `sites` | object |  | 本租户站点按缓存方式的数量:group(按缓存分组)与 custom(自定义规则)。 |

## 缓存标配 (`cache-presets`)

出厂标配缓存规则,可作为新建缓存分组的参考。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-presets

### GET `/api/v2/cache-presets`

出厂标配缓存规则 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cache-presets" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

缓存标配对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `cache` | CacheConfig |  | 缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。 |

## 站点缓存方式 (`cache-sites`)

查看或设置单个站点使用的缓存分组或自定义规则。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-sites

### GET `/api/v2/cache-sites/{id}`

站点的缓存方式 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cache-sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cache-sites/{id}`

站点引用缓存分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的站点 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `group_id` | integer | 有 | 显式引用的分组;null = 按默认分组。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/cache-sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

站点缓存方式对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `effective_group_id` | integer |  | mode=group 时实际生效的分组;null = 没有可用分组(不下发缓存规则)。 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的站点 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `group_id` | integer |  | 显式引用的分组;null = 按默认分组。 |
| `mode` | string |  | 缓存方式:group 按缓存分组;custom 为站点自定义规则。 可选值: ["group","custom"] |
| `site_id` | integer |  | 网站 ID |
| `updated_at` | string |  | 站点的 updated_at(站点行的版本,改缓存方式也会更新);改缓存方式时作 expected_updated_at 带回。 (只读) |

## 刷新与预热 (`cache-jobs`)

刷新(清除)缓存的 URL 或目录,以及预热指定 URL。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-jobs

### GET `/api/v2/cache-jobs`

列出刷新/预热任务 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `type` | string |  | 只列该类型的任务。 可选值: ["purge_url","purge_dir","prefetch"] |
| `url` | string |  | 以 http:// 或 https:// 开头时按完整 URL(同提交时规范化)精确匹配(任务的 URL 列表里含它);否则按主机名精确匹配。 |

```sh
curl "https://panel.example.com/api/v2/cache-jobs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cache-jobs`

创建刷新/预热任务 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `type` | string | 有 | purge_url 刷新 URL;purge_dir 刷新目录(URL 以 / 结尾);prefetch 预热。 可选值: ["purge_url","purge_dir","prefetch"] |
| `urls` | string[] | 有 | http(s)://主机/路径(规范化后,见创建接口);预热一次最多 100 条。 |

```sh
curl -X POST "https://panel.example.com/api/v2/cache-jobs" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"purge_url","urls":["https://www.example.com/index.html"]}'
```

### GET `/api/v2/cache-jobs/{id}`

获取刷新/预热任务 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cache-jobs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

刷新与预热对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 (只读) |
| `id` | integer |  | 记录 ID (只读) |
| `results` | CacheJobNodeResult[] |  | 各节点的执行结果(只在详情里回)。 (只读) |
| `site_id` | integer |  | 网站 ID (只读) |
| `status` | string |  | 下发任务的状态(有节点失败时 pending 退避重试,次数用完 failed)。 可选值: ["pending","running","done","failed"] (只读) |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `type` | string |  | purge_url 刷新 URL;purge_dir 刷新目录(URL 以 / 结尾);prefetch 预热。 可选值: ["purge_url","purge_dir","prefetch"] |
| `updated_at` | string |  | 更新时间 (只读) |
| `urls` | string[] |  | http(s)://主机/路径(规范化后,见创建接口);预热一次最多 100 条。 |

## 刷新预热限额 (`cache-quota`)

每日刷新与预热的限额及今日已用量。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/cache-quota

### GET `/api/v2/cache-quota`

刷新/预热每日限额与今日已用 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/cache-quota" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

刷新预热限额对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | CacheQuotaItem[] |  | 本页条目 |

## 四层转发 (`streams`)

TCP/UDP 端口转发规则。每条规则含监听端口与协议、源站列表、负载方式;(协议, 端口) 全平台唯一。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/streams

### GET `/api/v2/streams`

列出四层转发 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `port` | integer |  | 只列监听该端口的转发。 |
| `group_id` | integer |  | 只列该分组里的转发。 |
| `upid` | integer |  | 只列该用户套餐下的转发。 |
| `enabled` | boolean |  | 按启停过滤。 |
| `id` | integer |  | 按转发 id 精确过滤。 |
| `origin` | string |  | 按源站 IP 子串过滤。 |
| `protocol` | string |  | 只列有该协议监听的转发。 可选值: ["tcp","udp"] |
| `stop_code` | integer |  | 按停用码过滤;0 = 正常。 |
| `package_id` | integer |  | 按基础套餐过滤。 |
| `region_id` | integer |  | 按区域过滤:接入名的主线路分组属于该区域;没有自己接入名的按所属已售套餐的共用接入名算。 |
| `node_group_id` | integer |  | 按线路分组过滤:接入名的主线路分组或备用线路分组是它。 |
| `cname_domain_id` | integer |  | 按接入根域过滤。 |
| `cname_hostname` | string |  | 按接入名主机记录精确过滤。 |
| `sync_state` | string |  | 按配置同步状态过滤:behind = 配置落后(还有在线节点没装上它最近一次修改后的配置版本); 可选值: ["behind","synced"] |

```sh
curl "https://panel.example.com/api/v2/streams" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/streams`

创建四层转发 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acl` | StreamAcl |  | 四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。 |
| `balance` | StreamBalance |  | 负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。 可选值: ["rr","ip_hash","least_conn","random"] |
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `conn_limit` | integer |  | 单 IP 并发连接上限,0 = 不限。 |
| `enabled` | boolean |  | 是否启用 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `group_ids` | integer[] |  | 所属转发分组 id 列表。 |
| `listen` | StreamListen[] | 有 | 监听列表:每项为端口与协议。 |
| `name` | string |  | 名称 |
| `origin_port` | integer | 有 | 回源端口。 |
| `origins` | StreamOrigin[] | 有 | 源站列表:每项为源站 IP、权重与备用/下线标记。 |
| `proxy_protocol` | boolean |  | 是否向源站发送 PROXY protocol 头。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。 |
| `udp_responses` | integer |  | UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。 |
| `upid` | integer |  | 用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/streams" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"listen":[{"port":30001}],"name":"demo","origin_port":22,"origins":[{"host":"203.0.113.10"}]}'
```

### POST `/api/v2/streams/batch`

批量操作四层转发 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string | 有 | 操作类型:set_enabled 启停、delete 删除、set_groups 换分组、update 批量修改、create 批量新建、 set_lines 改接入名的主/备线路分组(仅管理员)、set_cname_domain 改接入名的根域(仅管理员,主机记录不变)。 可选值: ["set_enabled","delete","set_groups","update","create","set_lines","set_cname_domain"] |
| `backup_group_id` | integer |  | set_lines 用:备用线路分组;0 = 清空,不给 = 不动。 |
| `cname_domain_id` | integer |  | set_cname_domain 用:新的接入根域。 |
| `enabled` | boolean |  | 是否启用 |
| `group_ids` | integer[] |  | 所属转发分组 id 列表。 |
| `ids` | integer[] |  | 要操作的转发 id 列表,一次最多 100 条(create 以外的操作必填)。 |
| `items` | StreamWrite[] |  | create 用:要新建的转发(最多 100 条),每条同 POST /streams 的请求体。 |
| `node_group_id` | integer |  | set_lines 用:主线路分组(必填)。 |
| `patch` | StreamPatch |  | 批量 update 用:给了的字段改到每一条上,规则同单条修改。 |
| `region_id` | integer |  | set_lines 用:区域;给了就校验主/备线路分组都属于它(不给不校验)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/streams/batch" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"set_enabled","enabled":false,"ids":[1]}'
```

### GET `/api/v2/streams/{id}`

获取四层转发 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/streams/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/streams/{id}`

修改四层转发 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acl` | StreamAcl |  | 四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。 |
| `balance` | StreamBalance |  | 负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。 可选值: ["rr","ip_hash","least_conn","random"] |
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `conn_limit` | integer |  | 单 IP 并发连接上限,0 = 不限。 |
| `enabled` | boolean |  | 是否启用 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `group_ids` | integer[] |  | 所属转发分组 id 列表。 |
| `listen` | StreamListen[] | 有 | 监听列表:每项为端口与协议。 |
| `name` | string |  | 名称 |
| `origin_port` | integer | 有 | 回源端口。 |
| `origins` | StreamOrigin[] | 有 | 源站列表:每项为源站 IP、权重与备用/下线标记。 |
| `proxy_protocol` | boolean |  | 是否向源站发送 PROXY protocol 头。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。 |
| `udp_responses` | integer |  | UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。 |
| `upid` | integer |  | 用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/streams/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"listen":[{"port":30001}],"name":"demo","origin_port":22,"origins":[{"host":"203.0.113.10"}]}'
```

### DELETE `/api/v2/streams/{id}`

删除四层转发 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/streams/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

四层转发对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `acl` | StreamAcl |  | 四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。 |
| `action` | string | 有 | 操作类型:set_enabled 启停、delete 删除、set_groups 换分组、update 批量修改、create 批量新建、 set_lines 改接入名的主/备线路分组(仅管理员)、set_cname_domain 改接入名的根域(仅管理员,主机记录不变)。 可选值: ["set_enabled","delete","set_groups","update","create","set_lines","set_cname_domain"] |
| `affected` | integer |  | 受影响的条数 |
| `backup_group_id` | integer |  | set_lines 用:备用线路分组;0 = 清空,不给 = 不动。 |
| `balance` | StreamBalance |  | 负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。 可选值: ["rr","ip_hash","least_conn","random"] |
| `cname` | CnameBinding |  | 接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。 |
| `cname_domain_id` | integer |  | set_cname_domain 用:新的接入根域。 |
| `conn_limit` | integer |  | 单 IP 并发连接上限,0 = 不限。 |
| `created_at` | string |  | 创建时间 (只读) |
| `enabled` | boolean |  | 是否启用 |
| `expected_updated_at` | string |  | 乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。 |
| `group_ids` | integer[] |  | 所属转发分组 id 列表。 |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] |  | 要操作的转发 id 列表,一次最多 100 条(create 以外的操作必填)。 |
| `items` | StreamWrite[] |  | create 用:要新建的转发(最多 100 条),每条同 POST /streams 的请求体。 |
| `listen` | StreamListen[] |  | 监听列表:每项为端口与协议。 |
| `name` | string |  | 名称 |
| `node_group_id` | integer |  | set_lines 用:主线路分组(必填)。 |
| `node_issues` | NodeIssue[] |  | 在线节点上这条转发没完全生效的口或原因(列表与详情里给);都正常时不给这个字段。 (只读) |
| `origin_port` | integer |  | 回源端口。 |
| `origins` | StreamOrigin[] |  | 源站列表:每项为源站 IP、权重与备用/下线标记。 |
| `patch` | StreamPatch |  | 批量 update 用:给了的字段改到每一条上,规则同单条修改。 |
| `proxy_protocol` | boolean |  | 是否向源站发送 PROXY protocol 头。 |
| `region_id` | integer |  | set_lines 用:区域;给了就校验主/备线路分组都属于它(不给不校验)。 |
| `stop_code` | integer |  | 0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `udp_responses` | integer |  | UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `upid` | integer |  | 用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。 |

## 转发分组 (`stream-groups`)

给四层转发规则分组,便于批量管理;同租户分组名唯一,分组里还有转发时不能删除。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/stream-groups

### GET `/api/v2/stream-groups`

列出四层转发分组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/stream-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/stream-groups`

创建四层转发分组 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |

```sh
curl -X POST "https://panel.example.com/api/v2/stream-groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/stream-groups/{id}`

获取四层转发分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/stream-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/stream-groups/{id}`

修改四层转发分组 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `des` | string |  | 备注说明 |
| `name` | string | 有 | 名称 |

```sh
curl -X PUT "https://panel.example.com/api/v2/stream-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/stream-groups/{id}`

删除四层转发分组 · 鉴权: 用户（部分参数仅管理员）

```sh
curl -X DELETE "https://panel.example.com/api/v2/stream-groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

转发分组对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `created_at` | string |  | 创建时间 (只读) |
| `des` | string |  | 备注说明 |
| `id` | integer |  | 记录 ID (只读) |
| `name` | string |  | 名称 |
| `tenant_id` | integer |  | 所属租户(用户)ID (只读) |
| `updated_at` | string |  | 更新时间 (只读) |

## 分层回源 L2 (`l2`)

边缘回源先经同区域的 L2 节点,L2 有缓存就不再打源站;付费功能 l2,未开通时整块不生效。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/l2

### POST `/api/v2/l2/enable-batch`

批量加 L2 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `apply_sites` | boolean |  | 给现有网站也开(只动从没设过的网站,手动关过的、所属租户套餐不含分层回源的不动)。 |
| `node_ids` | integer[] | 有 | 要改做 L2 的边缘节点 id。 |

```sh
curl -X POST "https://panel.example.com/api/v2/l2/enable-batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/groups`

列出 L2 组 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/groups`

新建 L2 组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `all_regions` | boolean |  | 服务全部区域(须勾跨区域)。 |
| `balance` | string |  | 分配方式:url_hash 按网址固定,rr 轮流。 可选值: ["url_hash","rr"] |
| `cross_region` | boolean |  | 允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。 |
| `name` | string | 有 | 组名,全平台唯一。 |
| `node_ids` | integer[] |  | 要改做 L2 的边缘节点 id。 |
| `regions` | integer[] |  | 服务区域 id;all_regions 为真时忽略。 |
| `rules` | L2Rule[] |  | 组内规则(随组保存)。 |

```sh
curl -X POST "https://panel.example.com/api/v2/l2/groups" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/groups/{id}`

查看 L2 组 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PATCH `/api/v2/l2/groups/{id}`

修改 L2 组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `all_regions` | boolean |  | 服务全部区域(须勾跨区域)。 |
| `balance` | string |  | 分配方式:url_hash 按网址固定,rr 轮流。 可选值: ["url_hash","rr"] |
| `cross_region` | boolean |  | 允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。 |
| `name` | string |  | 组名,全平台唯一。 |
| `node_ids` | integer[] |  | 要改做 L2 的边缘节点 id。 |
| `regions` | integer[] |  | 服务区域 id;all_regions 为真时忽略。 |
| `rules` | L2Rule[] |  | 组内规则(随组保存)。 |

```sh
curl -X PATCH "https://panel.example.com/api/v2/l2/groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/l2/groups/{id}`

删除 L2 组 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/l2/groups/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/groups/{id}/copy`

复制 L2 组 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 有 | 组名,全平台唯一。 |

```sh
curl -X POST "https://panel.example.com/api/v2/l2/groups/{id}/copy" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/groups/{id}/reset-sites`

把用这个组的网站改回区域默认 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/groups/{id}/reset-sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/nodes`

列出 L2 节点 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/nodes" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PATCH `/api/v2/l2/nodes/{id}`

修改 L2 节点 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `access_addr` | string |  | 边缘访问它的内网地址(只收 IP,不带端口;IPv4 映射的 IPv6 存成 IPv4);空 = 公网 IP。 |
| `role` | string |  | 主备:同组有主可用时备只待命,主全挂才用备(在组内成员间比较)。 可选值: ["primary","backup"] |
| `weight` | integer |  | 权重 1–100,多台主按权重分网址。 |

```sh
curl -X PATCH "https://panel.example.com/api/v2/l2/nodes/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/nodes/{id}/disable`

停用 L2 节点 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `reason` | string |  | 停用原因。 |

```sh
curl -X POST "https://panel.example.com/api/v2/l2/nodes/{id}/disable" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/nodes/{id}/enable`

启用 L2 节点 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/nodes/{id}/enable" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/nodes/{id}/impact`

改回 / 停用前的影响 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/nodes/{id}/impact" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/nodes/{id}/mark-allowed`

标记源站已放行 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/nodes/{id}/mark-allowed" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/nodes/{id}/probe-access`

检测源站是否已放行 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/nodes/{id}/probe-access" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/nodes/{id}/revert`

改回边缘节点 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/nodes/{id}/revert" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/pause`

全网暂停分层回源 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_resume_at` | string |  | 自动恢复时刻(须在现在之后);不给 = 手动恢复。 |

```sh
curl -X POST "https://panel.example.com/api/v2/l2/pause" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/recommend`

一键启用推荐 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/recommend" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/l2/resume`

全网恢复分层回源 · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/l2/resume" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/revoke-impact`

授权失效的影响与回落窗口 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/l2/revoke-impact" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/stats`

分层回源统计 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/l2/stats" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/stats/nodes`

按 L2 节点的统计 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |

```sh
curl "https://panel.example.com/api/v2/l2/stats/nodes" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/stats/sites`

按网站的分层回源统计 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `domain` | string |  | 主域名子串,不分大小写。 |

```sh
curl "https://panel.example.com/api/v2/l2/stats/sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/status`

分层回源总览 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/status" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/l2/tasks/{id}`

查看 L2 任务进度 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/l2/tasks/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

分层回源 L2对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `access_addr` | string |  | 边缘访问它的内网地址(只收 IP,不带端口;IPv4 映射的 IPv6 存成 IPv4);空 = 公网 IP。 |
| `all_regions` | boolean |  | 服务全部区域(须勾跨区域)。 |
| `allow` | string |  | 源站放行:空 = 不涉及(没有网站只允许 L2),pending 待放行(只接可缓存请求),allowed 已放行。 |
| `allow_since` | string |  | 进入待放行的时刻;满 24 小时自动转已放行。 |
| `apply_sites` | boolean |  | 给现有网站也开(只动从没设过的网站,手动关过的、所属租户套餐不含分层回源的不动)。 |
| `auto_resume_at` | string |  | 自动恢复时刻(须在现在之后);不给 = 手动恢复。 |
| `balance` | string |  | 分配方式:url_hash 按网址固定,rr 轮流。 可选值: ["url_hash","rr"] |
| `checked_at` | string |  | 检测时刻。 |
| `created_at` | string |  | 开始时间。 |
| `cross_region` | boolean |  | 允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。 |
| `defaults` | L2Defaults |  | 默认设置(改用 PUT /configs/l2.defaults)。 |
| `disabled_at` | string |  | 停用时刻。 |
| `disabled_reason` | string |  | 停用原因。 |
| `edge_origin_requests` | integer |  | 边缘回源请求数(命中率分母)。 |
| `empty_group` | integer[] |  | 去掉它后没有可用 L2 的组(用这些组的网站将暂时绕过)。 |
| `enabled` | boolean |  | 启用;停用时仍是 L2、缓存保留。 |
| `feature` | string |  | 付费功能 l2 开通档:on 开通;limited 冻结、即将停用或授权失效后的回落窗口(照常下发,只能停用、暂停等,见 GET /l2/revoke-impact);off 没开通(不下发)。 可选值: ["on","limited","off"] |
| `finished_at` | string |  | 结束时间。 |
| `groups` | integer[] |  | 所在 L2 组 id。 |
| `hit_rate` | number |  | 命中率 0–1;没有回源为 0。 |
| `host` | string |  | 网站主域名。 |
| `id` | integer |  | 组 id。 |
| `ip` | string |  | 公网 IP。 |
| `is_region_default` | boolean |  | 区域默认组(每区域一个,不能删,只能改分配方式)。 |
| `items` | L2Group[] |  | L2 组。 |
| `kind` | string |  | 任务种类:enable 加 L2,revert 改回边缘。 可选值: ["enable","revert"] |
| `l2_group_id` | integer |  | 网站选的 L2 组;null = 区域默认。 |
| `l2_group_name` | string |  | L2 组名;区域默认时为空串。 |
| `l2_hit_requests` | integer |  | L2 接住的回源请求数(命中率分子)。 |
| `l2_pick` | string |  | 网站生效的选 L2 方式(网站单独设的,否则默认设置):region 跟边缘同区域;near 离源站最近。 可选值: ["region","near"] |
| `low_hit` | boolean |  | 命中率低于 30% 且源站请求不少于 1000 次(动态内容多,建议关)。 |
| `manual_off_sites` | integer |  | 手动关过分层回源的网站数(一键启用勾「给现有网站也开」时不动它们;IP 站不计)。 |
| `name` | string | 有 | 组名,全平台唯一。 |
| `node_id` | integer |  | 节点 id。 |
| `node_ids` | integer[] | 有 | 要改做 L2 的边缘节点 id。 |
| `nodes_pending` | integer |  | 待放行的 L2 数。 |
| `nodes_serving` | integer |  | 在接回源的 L2 数(启用且没在改回)。 |
| `nodes_total` | integer |  | L2 节点总数(含停用、改回中)。 |
| `online` | boolean |  | 在线(最近 2 分钟有心跳)。 |
| `only_block` | boolean |  | 有网站开了「源站只允许 L2 访问」(改回后源站要撤掉它的放行)。 |
| `only_block_sites` | integer |  | 开了「源站只允许 L2 访问」的网站数(only_block 为真时大于 0)。 |
| `origin_l2_only` | boolean |  | 开了「源站只允许 L2 访问」:回落窗口满后源站没放行边缘节点就会整站不可用。 |
| `origin_requests` | integer |  | 实际到源站的请求数。 |
| `origin_requests_est` | integer |  | 未开分层时的估算(= 边缘回源请求数)。 |
| `owner_id` | integer |  | 所属用户 ID。 |
| `owner_name` | string |  | 所属用户名。 |
| `paused` | boolean |  | 全网暂停中。 |
| `paused_at` | string |  | 暂停时刻。 |
| `progress` | integer |  | 进度 0–100。 |
| `reason` | string |  | 停用原因。 |
| `region_id` | integer |  | 区域默认组所属区域;自建组 0。 |
| `region_last` | boolean |  | 它是本区域最后一台启用中的 L2。 |
| `regions` | integer[] |  | 服务区域 id;all_regions 为真时忽略。 |
| `revert_at` | string |  | 开始改回的时刻。 |
| `role` | string |  | 主备:同组有主可用时备只待命,主全挂才用备(在组内成员间比较)。 可选值: ["primary","backup"] |
| `rules` | L2Rule[] |  | 组内规则(随组保存)。 |
| `saved_bytes` | integer |  | 省的回源流量(L2 命中字节)。 |
| `site_id` | integer |  | 网站 ID。 |
| `sites` | integer |  | 用这个组的网站数;区域默认组为开着 L2 且没指定组的网站数(各区域默认组同数)。 |
| `sites_only_l2` | integer |  | 开了「源站只允许 L2 访问」的网站数(暂停、新加节点时写进提醒)。 |
| `state` | string |  | 状态:active 正常,reverting 改回边缘中。 可选值: ["active","reverting"] |
| `thresholds` | L2Thresholds |  | 判定阈值(只读)。 |
| `updated_at` | string |  | 最后修改时间。 |
| `weight` | integer |  | 权重 1–100,多台主按权重分网址。 |

## 消息 (`messages`)

站内信与公告;管理员发布公告,租户查看、标记已读。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/messages

### GET `/api/v2/messages`

列出消息 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `type` | string |  | 消息类型,如 announcement、cert-expire。 |
| `site_id` | integer |  | 网站 ID |

```sh
curl "https://panel.example.com/api/v2/messages" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/messages`

发布公告 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string |  | 消息正文。 |
| `is_bold` | boolean |  | 标题是否加粗。 |
| `is_external` | boolean |  | 为真时点击跳 url,url 必填;否则 content 必填。 |
| `is_popup` | boolean |  | 是否弹窗显示。 |
| `is_red` | boolean |  | 标题是否标红。 |
| `is_show` | boolean |  | 是否显示。 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `title` | string | 有 | 消息标题。 |
| `url` | string |  | is_external 为真时点击跳转的链接。 |

```sh
curl -X POST "https://panel.example.com/api/v2/messages" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"今晚 23 点维护。","title":"维护通知"}'
```

### POST `/api/v2/messages/read`

标记已读 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ids` | integer[] |  | 为空表示发给自己的全部已读。 |

```sh
curl -X POST "https://panel.example.com/api/v2/messages/read" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/recent`

近期未读消息 · 鉴权: 用户

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `days` | integer |  | 只取最近这么多天的消息。 默认: 30 |
| `limit` | integer |  | 最多返回的条数。 默认: 8 |

```sh
curl "https://panel.example.com/api/v2/messages/recent" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/unread-count`

未读消息数 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/messages/unread-count" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/messages/{id}`

获取消息 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/messages/{id}`

修改消息 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string |  | 消息正文。 |
| `is_bold` | boolean |  | 标题是否加粗。 |
| `is_external` | boolean |  | 为真时点击跳 url,url 必填;否则 content 必填。 |
| `is_popup` | boolean |  | 是否弹窗显示。 |
| `is_red` | boolean |  | 标题是否标红。 |
| `is_show` | boolean |  | 是否显示。 |
| `sort` | integer |  | 排序值(小的在前)。 |
| `title` | string |  | 消息标题。 |
| `url` | string |  | is_external 为真时点击跳转的链接。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/messages/{id}`

删除消息 · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/messages/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

消息对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | string |  | 消息正文。 |
| `count` | integer |  | 未读消息数。 |
| `created_at` | string |  | 创建时间 (只读) |
| `id` | integer |  | 记录 ID (只读) |
| `ids` | integer[] |  | 为空表示发给自己的全部已读。 |
| `is_bold` | boolean |  | 标题是否加粗。 |
| `is_external` | boolean |  | 为真时点击跳 url,url 必填;否则 content 必填。 |
| `is_popup` | boolean |  | 是否弹窗显示。 |
| `is_red` | boolean |  | 标题是否标红。 |
| `is_show` | boolean |  | 是否显示。 |
| `items` | Message[] |  | 本页条目 |
| `read` | boolean |  | 是否已读。 (只读) |
| `site_id` | integer |  | 网站 ID (只读) |
| `sort` | integer |  | 排序值(小的在前)。 |
| `tenant_id` | integer |  | 收件租户;公告为空。 (只读) |
| `title` | string |  | 消息标题。 |
| `title_args` | object |  | 标题键的参数:名字 → 字符串、数字,或子句 {key, args}(子句同样先查词典再填占位,可嵌套)。 (只读) |
| `title_key` | string |  | 标题键(中文原句,{名字} 占位)。有值时面板拿它查界面语言的词典、用 title_args 填占位来显示标题;为空(旧消息、公告、标题被改过)显示 title 原文。 (只读) |
| `type` | string |  | announcement = 公告;其余为通知类型(如 cert-expire、package-expire)。 (只读) |
| `updated_at` | string |  | 更新时间 (只读) |
| `url` | string |  | is_external 为真时点击跳转的链接。 |

## 消息订阅 (`message-subscriptions`)

选择要接收哪些类型的通知。

鉴权: 用户 · 文档: https://www-demo.kuxitong.com/zh/docs/api/message-subscriptions

### GET `/api/v2/message-subscriptions`

消息订阅 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/message-subscriptions" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/message-subscriptions`

修改消息订阅 · 鉴权: 用户

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | SubscriptionItem[] | 有 | 本页条目 |

```sh
curl -X PUT "https://panel.example.com/api/v2/message-subscriptions" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

消息订阅对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `items` | SubscriptionItem[] |  | 本页条目 |

## 发信通道 (`message-channels`)

邮件(SMTP)与短信发信通道的配置及测试。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/message-channels

### GET `/api/v2/message-channels`

发信通道 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/message-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/message-channels`

修改发信通道 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `sms` | SmsChannel | 有 | 短信通道配置。 |
| `smtp` | SmtpChannel | 有 | SMTP 邮件通道配置。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/message-channels" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/message-channels/test`

测试发信通道 · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `channel` | string | 有 | 要测试的通道(email 邮件、sms 短信)。 可选值: ["email","sms"] |
| `draft` | ChannelTestDraft |  | 未保存的通道设置草稿;字段形状同保存接口,没给的字段、留空的密钥沿用已存值。 |
| `template_id` | string |  | 腾讯云短信须给已审核的模板 id(短信宝不需要)。 |
| `to` | string | 有 | 收件邮箱或手机号。 |

```sh
curl -X POST "https://panel.example.com/api/v2/message-channels/test" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel":"email","to":"admin@example.com"}'
```

发信通道对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `channel` | string | 有 | 要测试的通道(email 邮件、sms 短信)。 可选值: ["email","sms"] |
| `draft` | ChannelTestDraft |  | 未保存的通道设置草稿;字段形状同保存接口,没给的字段、留空的密钥沿用已存值。 |
| `error` | string |  | 失败时的错误信息。 |
| `ok` | boolean |  | 测试发送是否成功。 |
| `sms` | SmsChannel |  | 短信通道配置。 |
| `smtp` | SmtpChannel |  | SMTP 邮件通道配置。 |
| `template_id` | string |  | 腾讯云短信须给已审核的模板 id(短信宝不需要)。 |
| `to` | string | 有 | 收件邮箱或手机号。 |

## 告警 Webhook (`message-webhooks`)

钉钉、飞书、企业微信、Telegram 与通用 JSON 告警出口,可配多个,地址与密钥只回后 4 位。

鉴权: 仅管理员 · 文档: https://www-demo.kuxitong.com/zh/docs/api/message-webhooks

### GET `/api/v2/message-webhooks`

告警 Webhook 列表 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/message-webhooks" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/message-webhooks`

新建告警 Webhook · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `chat_id` | string |  | Telegram 会话(数字 id 或 @频道名)。 |
| `created_at` | string | 有 | 创建时间 |
| `enabled` | boolean |  | 是否启用;停用的不发。缺省启用。 |
| `id` | integer | 有 | 记录 ID |
| `kind` | string | 有 | 类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。 可选值: ["dingtalk","feishu","wecom","telegram","generic"] |
| `last4` | string |  | 地址(Telegram 为 Token)的末 4 位,仅用于辨认。 |
| `name` | string | 有 | 名称,全局唯一。 |
| `secret` | string |  | Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。 |
| `updated_at` | string | 有 | 更新时间 |
| `url` | string |  | 机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。 |

```sh
curl -X POST "https://panel.example.com/api/v2/message-webhooks" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/message-webhooks/test`

测试未保存的告警 Webhook · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `chat_id` | string |  | Telegram 会话(数字 id 或 @频道名)。 |
| `id` | integer |  | 记录 ID |
| `kind` | string | 有 | 类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。 可选值: ["dingtalk","feishu","wecom","telegram","generic"] |
| `secret` | string |  | Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。 |
| `url` | string |  | 机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。 |

```sh
curl -X POST "https://panel.example.com/api/v2/message-webhooks/test" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/message-webhooks/{id}`

修改告警 Webhook · 鉴权: 仅管理员

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `chat_id` | string |  | Telegram 会话(数字 id 或 @频道名)。 |
| `created_at` | string | 有 | 创建时间 |
| `enabled` | boolean |  | 是否启用;停用的不发。缺省启用。 |
| `id` | integer | 有 | 记录 ID |
| `kind` | string | 有 | 类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。 可选值: ["dingtalk","feishu","wecom","telegram","generic"] |
| `last4` | string |  | 地址(Telegram 为 Token)的末 4 位,仅用于辨认。 |
| `name` | string | 有 | 名称,全局唯一。 |
| `secret` | string |  | Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。 |
| `updated_at` | string | 有 | 更新时间 |
| `url` | string |  | 机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/message-webhooks/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/message-webhooks/{id}`

删除告警 Webhook · 鉴权: 仅管理员

```sh
curl -X DELETE "https://panel.example.com/api/v2/message-webhooks/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/message-webhooks/{id}/test`

测试已保存的告警 Webhook · 鉴权: 仅管理员

```sh
curl -X POST "https://panel.example.com/api/v2/message-webhooks/{id}/test" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

告警 Webhook对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `chat_id` | string |  | Telegram 会话(数字 id 或 @频道名)。 |
| `created_at` | string |  | 创建时间 (只读) |
| `enabled` | boolean |  | 是否启用;停用的不发。缺省启用。 |
| `error` | string |  | 失败时的错误信息。 |
| `id` | integer |  | 记录 ID (只读) |
| `kind` | string |  | 类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。 可选值: ["dingtalk","feishu","wecom","telegram","generic"] |
| `last4` | string |  | 地址(Telegram 为 Token)的末 4 位,仅用于辨认。 (只读) |
| `name` | string |  | 名称,全局唯一。 |
| `ok` | boolean |  | 测试发送是否成功。 |
| `secret` | string |  | Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。 |
| `updated_at` | string |  | 更新时间 (只读) |
| `url` | string |  | 机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。 |

## 报表 (`reports`)

站点与四层转发的实时曲线、排行、用量,节点监控曲线与排行,未配置域名 Top、临时白名单与访问日志;租户只见本租户数据。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/reports

### GET `/api/v2/reports/access-log-export-quota`

查看今天的访问日志下载额度 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/reports/access-log-export-quota" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/access-log-exports`

列出访问日志下载申请 · 鉴权: 用户

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/reports/access-log-exports" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/reports/access-log-exports`

申请下载访问日志 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `host` | string |  | 按请求 Host 精确过滤(不分大小写)。 |
| `server_port` | integer |  | 按接入端口过滤。 |
| `ip` | string |  | 按客户端地址精确过滤。 |
| `uri` | string |  | 按请求 URI 前缀过滤(须以 / 开头)。 |
| `referer` | string |  | 按来源页(Referer 请求头)精确过滤,区分大小写;给空值(referer=)= 只看没带来源的直接访问。 |
| `http_ver` | string |  | 按 HTTP 协议版本过滤(与响应的 http_ver 同写法)。 可选值: ["1.0","1.1","2","3"] |
| `method` | string |  | 按请求方法过滤(大写,如 GET、POST)。 |
| `status` | integer |  | 按状态码过滤。 |
| `node_id` | integer |  | 按节点过滤。 |
| `cache_status` | string |  | 按缓存状态过滤。 可选值: ["NONE","HIT","MISS","EXPIRED","STALE","UPDATING","REVALIDATED","BYPASS"] |
| `country` | string |  | 按客户端归属国家过滤(ISO 3166-1 两位码,如 CN)。 |
| `prov` | string |  | 按客户端归属省份过滤(GB/T 2260 前两位,如 44)。 |
| `isp` | string |  | 按客户端运营商过滤(telecom、unicom、mobile、cbn、edu、cloud、other)。 |
| `blocked` | boolean |  | true = 只看被拦截的请求(action = block)。 |
| `block_reason` | string |  | 按拦截原因过滤,口径同日志行的 block_reason:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截。 可选值: ["region","region_log","acl","other"] |
| `status_class` | string |  | 按状态码类别过滤:1xx / 2xx / 3xx / 4xx / 5xx;error = 出错(状态码 ≥ 400 且不是被拦截的请求)。与 status 同给时取交集。 可选值: ["1xx","2xx","3xx","4xx","5xx","error"] |
| `slow_ms` | integer |  | 只看慢请求:请求耗时(request_time_ms)大于该毫秒数。 |
| `cache_status_not` | string |  | 排除该缓存状态(cache_status 的取反);facets 的 miss 就是 cache_status_not=HIT。与 cache_status 同给时取交集。 可选值: ["NONE","HIT","MISS","EXPIRED","STALE","UPDATING","REVALIDATED","BYPASS"] |
| `q` | string |  | 包含搜索:状态码(恰为 3 位数字时按状态码相等;1xx~5xx 按类别)、客户端 IP(包含)、URL(包含)、域名(包含,不分大小写)任一命中即算;与其他条件取交集。 |

```sh
curl -X POST "https://panel.example.com/api/v2/reports/access-log-exports" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/access-log-exports/{id}`

查看访问日志下载申请 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/reports/access-log-exports/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/access-log-exports/{id}/file`

下载访问日志文件 · 鉴权: 用户

```sh
curl "https://panel.example.com/api/v2/reports/access-log-exports/{id}/file" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/access-logs`

列出访问日志 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `sort` | string |  | 排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `cursor` | string |  | 时间游标:上一页响应的 next_cursor 原样带回(须同一 sort 与筛选),从那条之后续读;带上时忽略 page。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `host` | string |  | 按请求 Host 精确过滤(不分大小写)。 |
| `server_port` | integer |  | 按接入端口过滤。 |
| `ip` | string |  | 按客户端地址精确过滤。 |
| `uri` | string |  | 按请求 URI 前缀过滤(须以 / 开头)。 |
| `referer` | string |  | 按来源页(Referer 请求头)精确过滤,区分大小写;给空值(referer=)= 只看没带来源的直接访问。 |
| `http_ver` | string |  | 按 HTTP 协议版本过滤(与响应的 http_ver 同写法)。 可选值: ["1.0","1.1","2","3"] |
| `method` | string |  | 按请求方法过滤(大写,如 GET、POST)。 |
| `status` | integer |  | 按状态码过滤。 |
| `node_id` | integer |  | 按节点过滤。 |
| `cache_status` | string |  | 按缓存状态过滤。 可选值: ["NONE","HIT","MISS","EXPIRED","STALE","UPDATING","REVALIDATED","BYPASS"] |
| `country` | string |  | 按客户端归属国家过滤(ISO 3166-1 两位码,如 CN)。 |
| `prov` | string |  | 按客户端归属省份过滤(GB/T 2260 前两位,如 44)。 |
| `isp` | string |  | 按客户端运营商过滤(telecom、unicom、mobile、cbn、edu、cloud、other)。 |
| `blocked` | boolean |  | true = 只看被拦截的请求(action = block)。 |
| `block_reason` | string |  | 按拦截原因过滤,口径同日志行的 block_reason:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截。 可选值: ["region","region_log","acl","other"] |
| `status_class` | string |  | 按状态码类别过滤:1xx / 2xx / 3xx / 4xx / 5xx;error = 出错(状态码 ≥ 400 且不是被拦截的请求)。与 status 同给时取交集。 可选值: ["1xx","2xx","3xx","4xx","5xx","error"] |
| `slow_ms` | integer |  | 只看慢请求:请求耗时(request_time_ms)大于该毫秒数。 |
| `cache_status_not` | string |  | 排除该缓存状态(cache_status 的取反);facets 的 miss 就是 cache_status_not=HIT。与 cache_status 同给时取交集。 可选值: ["NONE","HIT","MISS","EXPIRED","STALE","UPDATING","REVALIDATED","BYPASS"] |
| `q` | string |  | 包含搜索:状态码(恰为 3 位数字时按状态码相等;1xx~5xx 按类别)、客户端 IP(包含)、URL(包含)、域名(包含,不分大小写)任一命中即算;与其他条件取交集。 |
| `facets` | boolean |  | true / 1 = 响应带 facets(快捷筛选各项的条数)。条数在除快捷筛选(status_class、slow_ms、cache_status_not、blocked、block_reason)外的其余条件下统计,不受快捷筛选影响。 |
| `total` | boolean |  | false / 0 = 不统计总条数(响应不带 total,省一次全表计数);缺省 true。 |

```sh
curl "https://panel.example.com/api/v2/reports/access-logs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup`

网站体检总览 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `q` | string |  | 按网站名称或域名搜索(包含匹配)。 |
| `sort` | string |  | 排序:score 按得分升序(最差在前,缺省),name 按名称。 可选值: ["score","name"] |
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/history`

体检历史得分 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 按站点过滤。 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup/history" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/ignores`

体检忽略项 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 按站点过滤。 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup/ignores" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/reports/checkup/ignores/batch`

批量增减体检忽略项 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `keys` | string[] | 有 | 检查项键。 |
| `op` | string | 有 | add 补上 keys(已有的不动);remove 去掉 keys。 可选值: ["add","remove"] |
| `site_ids` | integer[] | 有 | 要处理的网站,最多 500 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/reports/checkup/ignores/batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/issues`

体检问题汇总 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `q` | string |  | 按网站名称或域名搜索(包含匹配),汇总只算匹配的网站。 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup/issues" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/issues/{key}/sites`

受某类体检问题影响的网站 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `q` | string |  | 按网站名称或域名搜索(包含匹配)。 |
| `sort` | string |  | 排序:score 体检得分从低到高(缺省);attacks 近 7 天攻击数从多到少(WAF 类与 CC 默认档的问题带这个数,其余检查项都按 0,同数再按得分)。 可选值: ["score","attacks"] |
| `type` | string |  | 只用于 rec_type:按网站类型筛选;undecided 是判不出类型的网站(体检只给了说明、不算问题,只能在这里列出)。key 不是 rec_type 时给了 422。 可选值: ["corporate","shop","content","api","admin","download","undecided"] |
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup/issues/{key}/sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/reports/checkup/recheck`

重新体检 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_ids` | integer[] |  | 要处理的网站,最多 500 个。 |

```sh
curl -X POST "https://panel.example.com/api/v2/reports/checkup/recheck" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/runs/active`

进行中的体检批次 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/reports/checkup/runs/active" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/runs/{id}`

体检批次进度 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/reports/checkup/runs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/settings`

读体检设置 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/reports/checkup/settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/reports/checkup/settings`

保存体检设置 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `frequency` | string | 有 | 检查频率:每天 03:00、每周一 03:00、仅手动。 可选值: ["daily","weekly","manual"] |
| `notify_critical` | boolean | 有 | 出现严重问题时告警(用告警设置里的渠道)。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/reports/checkup/settings" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/checkup/sites/{id}`

网站体检报告 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/reports/checkup/sites/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/reports/checkup/sites/{id}/app`

改写网站识别到的程序 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string |  | 网站名称。 |
| `reset` | boolean |  | true = 撤销人工改写、回到自动识别(此时忽略 name 与 version)。 |
| `version` | string |  | 程序版本;不知道可留空。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/reports/checkup/sites/{id}/app" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/reports/checkup/sites/{id}/ignores`

设置网站的体检忽略项 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `keys` | string[] | 有 | 检查项键。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/reports/checkup/sites/{id}/ignores" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/host-not-found/top`

未配置域名 Top · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `node_id` | integer |  | 只看这个节点上报的。 |
| `domain` | string |  | 按 host 子串过滤(不分大小写,字面匹配)。 |
| `kind` | HostNotFoundKind |  | 只看这一类(类型由主控判定、不在库里:先取次数最高的 500 个域名判定、按类型过滤后再分页,total 为过滤后行数)。 可选值: ["site","pointed_here","not_pointed","typo","scanner","unknown"] |
| `order` | string |  | 按次数排序方向,缺省 desc。 可选值: ["desc","asc"] |

```sh
curl "https://panel.example.com/api/v2/reports/host-not-found/top" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/ip-seen`

访客 IP 的首次与最近出现 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `ip` | string | 有 | 要查的客户端地址(IPv4 或 IPv6)。 |

```sh
curl "https://panel.example.com/api/v2/reports/ip-seen" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/nodes/realtime`

节点实时曲线 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `node_id` | integer | 有 | 节点。给子 IP 的 id 时取它所属主节点的曲线(指标按主节点采集)。 |
| `metric` | string | 有 | 节点指标(同 node_metrics.metric)。tls_hs_reject 为握手洪水防御拦掉的 TLS 握手数;worker_drain_killed 为被强关(SIGTERM)的排空中旧 nginx worker 数。 可选值: ["nic_in_bps","nic_out_bps","cpu_pct","mem_pct","load1","disk_space_pct","disk_inode_pct","tcp_conn","nginx_active","nginx_reading","nginx_writing","nginx_waiting","log_dropped","tls_hs_reject","worker_drain_killed"] |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |

```sh
curl "https://panel.example.com/api/v2/reports/nodes/realtime" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/nodes/realtime-batch`

节点实时曲线(多指标一次取) · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `node_id` | integer | 有 | 节点。给子 IP 的 id 时取它所属主节点的曲线(指标按主节点采集)。 |
| `metrics` | string | 有 | 节点指标列表,逗号分隔。 |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |

```sh
curl "https://panel.example.com/api/v2/reports/nodes/realtime-batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/nodes/summary`

节点排行总表 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `window` | integer |  | 取均值的窗口(分钟),缺省 5。 可选值: [1,5,30,60] |

```sh
curl "https://panel.example.com/api/v2/reports/nodes/summary" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/nodes/top`

节点排行 · 鉴权: 仅管理员

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `metric` | string | 有 | 节点指标(同 node_metrics.metric)。tls_hs_reject 为握手洪水防御拦掉的 TLS 握手数;worker_drain_killed 为被强关(SIGTERM)的排空中旧 nginx worker 数。 可选值: ["nic_in_bps","nic_out_bps","cpu_pct","mem_pct","load1","disk_space_pct","disk_inode_pct","tcp_conn","nginx_active","nginx_reading","nginx_writing","nginx_waiting","log_dropped","tls_hs_reject","worker_drain_killed"] |

```sh
curl "https://panel.example.com/api/v2/reports/nodes/top" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/nodes/visitor-rtt`

节点访客时延 · 鉴权: 仅管理员

```sh
curl "https://panel.example.com/api/v2/reports/nodes/visitor-rtt" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/security/overview`

安全总览 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_id` | integer |  | 按站点过滤。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/reports/security/overview" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/security/screen`

安全大屏聚合 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_id` | integer |  | 按站点过滤。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/reports/security/screen" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/geo`

访问归属地统计 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `ip` | string |  | 按客户端地址精确过滤。 |

```sh
curl "https://panel.example.com/api/v2/reports/sites/geo" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/overview`

站点流量概览 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |
| `include_noconfig` | boolean |  | 仅管理员:把未配置流量(site_id = 0)也算上。 |
| `compare` | string |  | prev = 同时返回上一周期同长度的点列与合计(compare 字段);缺省不返回。 可选值: ["prev"] |

```sh
curl "https://panel.example.com/api/v2/reports/sites/overview" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/protocol-config`

站点协议配置分布 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/reports/sites/protocol-config" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/realtime`

站点实时曲线 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `metric` | string | 有 | 指标。 可选值: ["bandwidth","bandwidth_in","traffic","traffic_in","backend_bandwidth","backend_traffic","req","qps","req_hit_ratio","byte_hit_ratio","status_4xx","status_5xx","backend_resp_time","backend_timeout","blocked","challenged"] |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |
| `include_noconfig` | boolean |  | 仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。 |

```sh
curl "https://panel.example.com/api/v2/reports/sites/realtime" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/realtime-batch`

站点实时曲线(多指标一次取) · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `metrics` | string | 有 | 指标列表,逗号分隔。 |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |
| `include_noconfig` | boolean |  | 仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。 |

```sh
curl "https://panel.example.com/api/v2/reports/sites/realtime-batch" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/sites/top`

站点排行 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `dim` | string |  | 排行维度;与 dims 二选一。 可选值: ["ip","prefix","url","referer","site","status","http_ver","scheme","cache_status","ctype","country","prov","isp","port","block_reason"] |
| `dims` | string |  | 一次取多个维度的前 limit 名,逗号分隔的维度名(取值同 dim,至多 12 个);与 dim 二选一。 |
| `limit` | integer |  | 每个维度取前几名,缺省与上限为系统配置 reports.top_size。 |
| `metric` | string |  | 排序与 value 取哪一项,缺省 count。 可选值: ["count","bytes"] |
| `action` | string |  | 只算该处置动作的请求(pass 放行、challenge 质询、block 拦截)。 可选值: ["pass","challenge","block"] |
| `server_port` | integer |  | 只算该监听端口的请求;prefix 维度不支持(422)。 |

```sh
curl "https://panel.example.com/api/v2/reports/sites/top" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/streams/realtime`

四层转发实时曲线 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `port` | integer |  | 按四层监听端口过滤。 |
| `metric` | string | 有 | 指标。 可选值: ["bandwidth","bandwidth_in","traffic","traffic_in","req","conn_peak"] |
| `interval` | string |  | 桶宽;缺省按时间跨度自动取。 可选值: ["1m","2m","5m","10m","30m","1h"] |

```sh
curl "https://panel.example.com/api/v2/reports/streams/realtime" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/streams/top`

四层转发排行 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `dim` | string |  | 排行维度,缺省 port。 可选值: ["port","ip"] |
| `metric` | string |  | 排序与 value 取哪一项,缺省 count。 可选值: ["count","bytes"] |

```sh
curl "https://panel.example.com/api/v2/reports/streams/top" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/tmp-whitelist`

列出节点临时白名单记录 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `site_id` | integer |  | 按站点过滤。 |
| `ip` | string |  | 按客户端地址精确过滤(IPv6 为 /64 前缀地址)。 |
| `active` | boolean |  | true = 只看未到期的。 |

```sh
curl "https://panel.example.com/api/v2/reports/tmp-whitelist" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/usage`

用量曲线 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `start` | string | 有 | 起始时间(含),RFC 3339。 |
| `end` | string | 有 | 结束时间(不含),RFC 3339。 |
| `site_ids` | string |  | 只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。 |
| `group_id` | integer |  | 只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。 |
| `upid` | integer |  | 只看该用户套餐下的站点。 |
| `tenant_ids` | string |  | 仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `kind` | string |  | site(缺省)= 站点;stream = 四层转发。 可选值: ["site","stream"] |
| `metric` | string | 有 | 指标。 可选值: ["bandwidth","traffic","req","qps","req_hit_ratio","status_5xx_ratio","status_4xx_ratio","backend_bandwidth","backend_traffic","backend_resp_time","blocked"] |
| `interval` | string |  | auto(缺省)、5m 或 1h。 可选值: ["auto","5m","1h"] |
| `port` | integer |  | 按四层监听端口过滤。 |
| `include_noconfig` | boolean |  | 仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。 |

```sh
curl "https://panel.example.com/api/v2/reports/usage" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/waf-events`

列出 WAF 事件 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `start` | string |  | 起始时间(含),RFC 3339;缺省不限(事件只保留 7 天)。 |
| `end` | string |  | 结束时间(不含),RFC 3339;缺省不限。 |
| `site_id` | integer |  | 按站点过滤。 |
| `ip` | string |  | 按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。 |
| `url` | string |  | URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。 |
| `ja4` | string |  | 按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。 |
| `rule_id` | integer |  | 按命中规则号过滤。 |
| `action` | string |  | 按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。 可选值: ["block","log","challenge","mask","replace"] |
| `type` | string[] |  | 按事件类型过滤,可重复多选,不给 = 全部。 |
| `country` | string |  | 按国家过滤(节点归属地库给的名称,精确匹配)。 |
| `province` | string |  | 按省份过滤(精确匹配)。 |
| `node_id` | integer |  | 按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。 |
| `observe` | boolean |  | true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。 |
| `blocked` | boolean |  | true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。 |
| `disposition` | string |  | other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。 可选值: ["other"] |

```sh
curl "https://panel.example.com/api/v2/reports/waf-events" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/waf-events/export`

导出 WAF 事件 CSV · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `start` | string |  | 起始时间(含),RFC 3339;缺省不限(事件只保留 7 天)。 |
| `end` | string |  | 结束时间(不含),RFC 3339;缺省不限。 |
| `site_id` | integer |  | 按站点过滤。 |
| `ip` | string |  | 按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。 |
| `url` | string |  | URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。 |
| `ja4` | string |  | 按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。 |
| `rule_id` | integer |  | 按命中规则号过滤。 |
| `action` | string |  | 按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。 可选值: ["block","log","challenge","mask","replace"] |
| `type` | string[] |  | 按事件类型过滤,可重复多选,不给 = 全部。 |
| `country` | string |  | 按国家过滤(节点归属地库给的名称,精确匹配)。 |
| `province` | string |  | 按省份过滤(精确匹配)。 |
| `node_id` | integer |  | 按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。 |
| `observe` | boolean |  | true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。 |
| `blocked` | boolean |  | true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。 |
| `disposition` | string |  | other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。 可选值: ["other"] |

```sh
curl "https://panel.example.com/api/v2/reports/waf-events/export" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/waf-events/summary`

WAF 事件汇总 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `start` | string | 有 | 时间窗起点(含),RFC 3339。 |
| `end` | string | 有 | 时间窗终点(不含),RFC 3339;须晚于 start,跨度最长 31 天。 |
| `site_id` | integer |  | 按站点过滤。 |
| `ip` | string |  | 按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。 |
| `url` | string |  | URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。 |
| `ja4` | string |  | 按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。 |
| `rule_id` | integer |  | 按命中规则号过滤。 |
| `action` | string |  | 按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。 可选值: ["block","log","challenge","mask","replace"] |
| `type` | string[] |  | 按事件类型过滤,可重复多选,不给 = 全部。 |
| `country` | string |  | 按国家过滤(节点归属地库给的名称,精确匹配)。 |
| `province` | string |  | 按省份过滤(精确匹配)。 |
| `node_id` | integer |  | 按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。 |
| `observe` | boolean |  | true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。 |
| `blocked` | boolean |  | true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。 |
| `disposition` | string |  | other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。 可选值: ["other"] |

```sh
curl "https://panel.example.com/api/v2/reports/waf-events/summary" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/reports/waf-events/{event_id}`

获取 WAF 事件详情 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

```sh
curl "https://panel.example.com/api/v2/reports/waf-events/{event_id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/reports/waf-events/{event_id}/allow`

一键加白 WAF 事件 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `param` | string |  | 命中的参数名/请求头名/Cookie 名;无名部位为空。 |
| `path` | string |  | 仅限该路径前缀;须等于事件 URL 路径,或是以 / 结尾的前缀(如 /api/);单独的 / 须同时选规则号或参数。不给 = 不限路径。 |
| `rule` | boolean |  | 仅跳过事件命中的这条规则(rule_ids);非规则类事件(规则号 0)与语义事件不能勾。 默认: false |

```sh
curl -X POST "https://panel.example.com/api/v2/reports/waf-events/{event_id}/allow" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

报表对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | string |  | 防护处置:pass 放行、challenge 验证、block 拦截。 |
| `advice` | integer |  | 建议数。 |
| `app` | string |  | 识别到的程序名;空串 = 没识别出。 |
| `app_manual` | boolean |  | 程序是用户人工改写的。 |
| `app_version` | string |  | 程序版本;读不到时为空串。 |
| `approx` | boolean |  | 本榜取自节点每分钟前 K(ip、prefix、url、referer),各节点只上报自己的前 K,合计为近似值;带 action 或 server_port 改读访问日志时为 false。 |
| `at` | string |  | 发生时刻(窗口内最后一次命中)。 |
| `attack_types` | WafEventCount[] |  | 攻击类型分布(sqli、xss、scanner、rce、traversal、other 与 semantic、bot、upload、tamper、leak),按行数降序;之和等于 total。 |
| `attacked_sites` | integer |  | 被攻击网站去重数。 |
| `ban_hits` | integer |  | 封禁 IP 挡下的复访次数:blocked_by_feature 里 auto_ban 与 status_ban 两项之和。节点开始给封禁拦截打标之前恒为 0。 |
| `block` | integer |  | 拦截模式的拦截(action = block 且非观察)。 |
| `block_reason` | string |  | 拦截原因:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截;没拦也没命中地区限制不回。 可选值: ["region","region_log","acl","other"] |
| `blocked` | integer |  | 被拦截(action = block)的请求数。 |
| `blocked_acl` | integer |  | 被 ACL 拦截的请求数(含不带地区条件的 ACL)。 |
| `blocked_by_feature` | SecurityFeatureCount[] |  | 按防护功能的拦截次数(被拦截请求按采样权重折算,不含挑战验证)。固定 12 项(只含真拦截类,防泄露、防篡改是换体不在此列,见 handled_by_feature),次数降序、同次数按固定顺序;各项 count 之和等于同一时间窗、同一网站范围的 summary.blocked。功能归类看节点写进访问日志的 rule_ref,旧节点没打标的拦截记在 waf_rule。 |
| `blocked_region` | integer |  | 被地区限制拦截的请求数。 |
| `body_trunc` | boolean |  | 请求体超过检查上限,只查了前一段。 |
| `bot_score` | integer |  | Bot 行为评分 0–100;仅 Bot 事件(type = bot)有,其余类型没有此字段(score 是 WAF 异常分,含义不同)。 |
| `bytes_sent` | integer |  | 原始下行字节。 |
| `cache_status` | string |  | 缓存状态,如 HIT、MISS、BYPASS。 |
| `category` | string |  | 规则分类(sqli xss scanner rce php nodejs java lfi rfi protocol 等);查不到为空。 |
| `challenge` | integer |  | 非观察的验证(action = challenge)。 |
| `checked_at` | string |  | 体检时刻。 |
| `checkup` | object |  | 网站体检接入:防护评分(各网站体检分按流量加权)与待处理建议;随 site_id 过滤,不随时间窗。 |
| `client_ip` | string |  | 客户端 IP;IPv4 按原样。 |
| `combo` | object |  | HTTP/2 与 HTTP/3 的组合分布(站点数)。 |
| `compare` | SitesOverviewCompare |  | 上一周期(compare=prev):窗口 [start, end) 与按桶点列、合计;点列与当前周期逐点对齐。不含 h3_ratio、backend_resp_time_p95、noconfig_req(恒为 null)。 |
| `content_encoding` | string |  | 响应的 Content-Encoding。 |
| `count` | integer |  | 时间窗内 530 次数(各节点之和)。 |
| `countries` | SecurityCountryCount[] |  | 攻击来源国(被拦截与被挑战的请求数,按采样权重折算),次数降序;country 为空串 = 归属地未识别。 |
| `country` | string |  | 客户端归属国家(ISO 3166-1 两位码);未识别不回。 |
| `covered` | integer |  | 按识别到的程序对照防护清单,节点内置规则已防护的已知漏洞数;没有识别到程序或清单里没有该产品为 0。 |
| `created_at` | string |  | 创建时间 |
| `critical` | integer |  | 严重问题数(不含已忽略与未开通)。 |
| `ctype` | string |  | 响应的 Content-Type(去参数小写)。 |
| `current_site_id` | integer |  | 正在保存结果的网站 id;只在阶段 5 有值(阶段 1-4 是整批执行,没有单个当前站),没有时缺省。 |
| `cves` | SecurityCve[] |  | 最近 7 天命中的 CVE(规则包 meta 节对照),按命中次数降序,最多 50 条;没接入规则包时为空。 |
| `dims` | object |  | dims 请求的结果:键为维度名,值为该维度的排行(其中不再有 dims);单维度请求不带。 |
| `domain` | string |  | 第一个域名。 |
| `done_rows` | integer |  | 已写入文件的行数。 |
| `done_site_ids` | integer[] |  | 本批次已保存体检结果的网站 id(升序);不在其中的网站还没体检完(或没体检成功)。重试时清空重来。 |
| `done_sites` | integer |  | 已保存结果的网站数;完成后小于 total_sites 表示有网站没体检成功。 |
| `error` | string |  | 最近一次失败的原因(重试期间保留,导出成功后清空;failed 时即最终失败原因)。 |
| `exception` | WafEventAllowException |  | 这次加白写入(或本站已有)的站点例外。 |
| `expires_at` | string |  | 文件到期被清理的时刻(完成时刻 + 保留小时数)。 |
| `extra` | integer |  | 同上口径下,开通 WAF 规则更新后可再防护的已知漏洞数。 |
| `facets` | object |  | 筛选按钮上的分面计数。 |
| `file_bytes` | integer |  | 压缩后文件大小(字节,完成后才有)。 |
| `file_count` | integer |  | 本请求已扫的上传文件数。 |
| `file_ctype` | string |  | 上传文件的 Content-Type(客户端给的)。 |
| `file_field` | string |  | 上传文件的表单字段名。 |
| `file_magic` | string |  | 按文件头识别的类型;认不出为空。 |
| `file_name` | string |  | 上传文件名(客户端给的原名);仅上传事件(type = upload)有。 |
| `file_sha256` | string |  | 上传文件 sha256;没算为空。 |
| `file_size` | integer |  | 上传文件大小(字节);仅上传事件(type = upload)有。 |
| `filter` | AccessLogExportFilter |  | 申请时的筛选条件(同列表查询参数)。 |
| `findings` | CheckupFinding[] |  | 有问题的检查项(通过的项不列出),按检查项顺序。 |
| `finished_at` | string |  | 完成时刻。 |
| `first_seen` | string |  | 该问题本轮连续出现的起点;首次体检、旧结果没记的不返回。 |
| `first_seen_at` | string |  | 保留期内最早一条访问日志的时间;没有记录时不回。 |
| `flows` | SecurityFlow[] |  | 攻击流向 Top 50(来源国 → 节点所在国家/城市,被拦截与被挑战的请求数,按采样权重折算),次数降序;其余与位置未知的节点合并成排在最后的一条 node_country 为空串的「其他」行(不画);总和等于 countries 的总和。属 WAF 增强,未开通时为空数组;只收流向表建好之后写入的数据,更早的时间窗为空。 |
| `foreign` | integer |  | 中国大陆以外(已识别国家且不是 CN)的请求数;运营商分布不含这部分。 |
| `frequency` | string |  | 检查频率:每天 03:00、每周一 03:00、仅手动。 可选值: ["daily","weekly","manual"] |
| `geo_summary` | TopGeoSummary |  | 地区维度(country、prov、isp)的汇总,按整个时间窗与同样的筛选条件统计,不受榜单行数限制。 |
| `handled_by_feature` | SecurityHandledCount[] |  | 已处理(替换内容)次数:防泄露、防篡改在响应体上替换内容,状态码不变、记为放行,不算拦截,所以不进 blocked_by_feature 也不进 summary.blocked,也不应算拦截百分比。只列次数大于 0 的功能,次数降序、同次数先 leak 后 tamper;没有数据(含节点尚未给换体打标)返回空数组,前端据此隐藏。同样按采样权重折算,随时间窗与网站范围。 |
| `headers` | string[] |  | 前 20 个请求头,每个「小写名: 值」,值截取 256 字节;Cookie 与 Authorization 类只留名。 |
| `history` | CheckupHistoryPoint[] |  | 该网站近 8 周得分。 |
| `hit_layer` | string |  | 上传扫描命中层;没命中为空。 |
| `host` | string |  | 请求的 Host。 |
| `http2` | ProtocolSwitch |  | 某项协议开关的站点数分布(开启、关闭、未设置)。 |
| `http3` | ProtocolSwitch |  | 某项协议开关的站点数分布(开启、关闭、未设置)。 |
| `http_ver` | string |  | HTTP 协议版本(HTTP/x.y 归一为 1.0、1.1、2、3)。 |
| `https_off` | integer |  | 未开启 HTTPS 的站点数。 |
| `https_on` | integer |  | 开启 HTTPS 的站点数。 |
| `id` | integer |  | 记录 ID |
| `intel_hit` | boolean |  | 该 IP 当前是否在平台高危 IP 库(按当前库现查);null = 库没在下发,未判定。 |
| `interval` | integer |  | 桶宽(秒)。 |
| `invalid` | integer |  | 配置解不开或开关取值不是布尔的站点数。 |
| `ip` | string |  | 查询的地址(规范写法)。 |
| `isp` | string |  | 客户端运营商编号;未识别不回。 |
| `isps` | GeoCount[] |  | 中国大陆各运营商请求数,从多到少(key 为空 = 运营商未识别)。 |
| `items` | CheckupHistoryPoint[] |  | 本页条目 |
| `ja4` | string |  | 客户端 TLS 指纹 JA4(节点在 TLS 握手时算,同连接各请求相同);明文 HTTP 或取不到不回。 |
| `keys` | string[] | 有 | 检查项键。 |
| `kind` | string |  | 站点类型:domain 域名站、ip IP 站(编辑页不同)。 可选值: ["domain","ip"] |
| `last_seen` | string |  | 最近出现的分钟。 |
| `last_seen_at` | string |  | 保留期内最近一条访问日志的时间;没有记录时不回。 |
| `level` | string |  | 命中时站点的防护等级:basic / standard / strict。 |
| `limit` | integer |  | 每天可申请的次数(reports.access_log_export_daily;0 = 不许下载)。 |
| `max` | number |  | bandwidth、backend_bandwidth:时间窗内 5 分钟带宽峰值。 |
| `medium` | integer |  | 中等问题数。 |
| `message` | string |  | 兼容旧版的说明串(处置与累计分),新界面用 type/action/category 自行组文案。 |
| `method` | string |  | HTTP 请求方法。 |
| `metrics` | NodeRealtimeMetric[] |  | 各指标的曲线,顺序同请求。 |
| `name` | string |  | 网站名称。 |
| `next_retry_at` | string |  | 下次重试时刻(失败后等退避重试的 pending 申请才有)。 |
| `node_city` | string |  | 上报的节点所在城市名;只知道国家、没有城市或位置未知时为空串。 |
| `node_id` | integer |  | 处理该请求的节点 ID。 |
| `node_ids` | integer[] |  | 上报过它的节点(最多 50 个,升序)。 |
| `node_ips` | string[] |  | 该网站实际调度到的线路分组内节点的对外地址(去重排序,最多 500 个;内网/管理出口地址不出),源站防火墙放行它们即可只允许经 CDN 访问;仅在有「源站可被直连」问题时返回,否则为空数组。 |
| `node_lat` | number |  | 节点落点纬度,含义同 node_lon。 |
| `node_lon` | number |  | 节点落点经度(城市坐标,没有城市时为国家质心);位置未知时没有此字段。 |
| `node_names` | string[] |  | 与 node_ids 同序的节点名;节点没名字或已删为 "#<id>"。 |
| `node_spots` | SecurityNodeSpot[] |  | 节点落点分布(落点国家/城市 → 在用节点台数),仅管理员返回,租户恒为空数组;口径同 flows 的落点(启用的主节点、位置未知的不计),不随 WAF 增强开通与否、时间窗或 site_id 变化;台数降序,同台数按国家、城市升序。 |
| `node_unknown` | integer |  | 位置未知的在用节点台数(启用的主节点里国家定不下来的,不在 node_spots 中),仅管理员返回,租户响应不含该字段;不随 WAF 增强开通与否、时间窗或 site_id 变化。 |
| `nodes` | integer |  | 上报过它的节点数。 |
| `notify_critical` | boolean |  | 出现严重问题时告警(用告警设置里的渠道)。 |
| `observe` | boolean |  | 站点当时在观察期(只记录不处置)。 |
| `observe_rule` | boolean |  | true = 命中的是观察期内的新规则,只记录没有拦(此时 observe 也为 true);应急规则无观察期,恒为 false。 |
| `op` | string | 有 | add 补上 keys(已有的不动);remove 去掉 keys。 可选值: ["add","remove"] |
| `open_url` | string |  | 这条请求的可点开地址(该条日志自己的协议 + 域名 + 非默认端口 + 路径与查询串);只放 http/https、域名或 IP 合法、长度不到 2048 的,否则不回。 |
| `other` | integer |  | 其余(非观察的 log、mask、replace)。 |
| `p95` | number |  | bandwidth、backend_bandwidth:95 值(interval=5m 按 5 分钟带宽、否则按小时峰值;只算有数据的样本,降序第 n×5/100+1 个,n=1 时等于峰值)。 |
| `param` | string |  | 命中的参数名/请求头名/Cookie 名;无名部位为空。 |
| `params` | object |  | 展示用的数字与名称,同体检结果里该项的 params(含 open_url)。 |
| `path` | string |  | 仅限该路径前缀;须等于事件 URL 路径,或是以 / 结尾的前缀(如 /api/);单独的 / 须同时选规则号或参数。不给 = 不限路径。 |
| `points` | SecurityPoint[] |  | 攻击趋势;桶宽随时间跨度自动取(约 288 个点以内),空桶补 0。 |
| `prefix_len` | integer |  | 32(IPv4)或 64(IPv6)。 |
| `prev_score` | integer |  | 上一次体检得分;第一次体检为 null。 |
| `previous` | object |  | 上一同长时间窗的对照。 |
| `probes` | CheckupProbeExtra[] |  | 近 7 天被探测里 WAF 事件之外的行(CC 已断开、源站返回 404);已拦截 / 只记录行由面板按 WAF 事件聚合。 |
| `progress` | integer |  | 进度百分比(已写行数 / 总行数)。 |
| `protocol` | string |  | HTTP 版本,如 HTTP/2.0。 |
| `prov` | string |  | 客户端归属省份(GB/T 2260 前两位,仅中国大陆);未识别不回。 |
| `province` | string |  | 省份;未识别时为空。 |
| `provinces` | SecurityProvinceCount[] |  | 中国大陆攻击来源省份(被拦截与被挑战的请求数,按采样权重折算),次数降序;省份未识别的不列。 |
| `provs` | GeoCount[] |  | 中国大陆各省请求数,从多到少(key 为空 = 省份未识别)。 |
| `publish_seq` | integer |  | 触发的重发布序号(result = added 时)。 |
| `reason_args` | object |  | 依据文案的参数(id 站点/证书 id、at 删除时间、domain 近似的站点域名、n 相差字符数、names 节点名、cname、ip、nodes、count)。 |
| `reason_code` | string |  | 判定依据(文案码,面板按语言出文案):site_unsynced 站点仍在但节点没有它的配置、site_disabled 站点已停用、 可选值: ["site_unsynced","site_disabled","site_deleted","cert_cover","bare_ip","bad_domain","typo","not_resolved","dns_error","nxdomain","nxdomain_random","pointed_a","pointed_cname","elsewhere_ip","elsewhere_cname","no_a","unavailable"] |
| `recent` | WafEventRecent |  | 同一 IP 近 1 小时的事件(总数、命中规则分布、最近若干条)。 |
| `referer` | string |  | 请求的 Referer。 |
| `referer_open_url` | string |  | 来源页的可点开地址;来源不是 http/https 页面(如 javascript:、android-app://)、地址不合法或长达 2048 字符以上时不回。 |
| `region_logged` | integer |  | 命中「只记录」地区限制(未拦截)的请求数。 |
| `remaining` | integer |  | 今天还能申请的次数。 |
| `request_id` | string |  | 请求 ID。 |
| `request_length` | integer |  | 请求长度,字节。 |
| `request_time_ms` | integer |  | 请求处理耗时,毫秒。 |
| `reset` | boolean |  | true = 撤销人工改写、回到自动识别(此时忽略 name 与 version)。 |
| `result` | string |  | added 已添加;exists 本站已有相同例外,未重复添加;full 本站例外已满,未添加。 可选值: ["added","exists","full"] |
| `retries` | integer |  | 已失败次数;pending/running 且大于 0 即在第 N 次重试。 |
| `rule` | boolean |  | 仅跳过事件命中的这条规则(rule_ids);非规则类事件(规则号 0)与语义事件不能勾。 默认: false |
| `rule_id` | integer |  | 命中的规则 ID。 |
| `rule_name` | string |  | 规则短名。 |
| `rules_ver` | string |  | 规则库版本;空 = 节点内置规则。 |
| `run` | object |  | 进行中的批次;没有时缺省。 |
| `sample_factor` | integer |  | 采样倍数 N(所读访问日志的最大 sample_weight);未采样为 1。 |
| `sample_weight` | integer |  | 采样权重(1 = 未采样)。 |
| `sampled` | boolean |  | 所读访问日志里有采样行(sample_weight > 1),计数按权重折算、结果不完整。 |
| `saved_bytes` | integer |  | 省下的回源流量(字节):时间窗内命中缓存、未被拦截的请求发给客户端的字节数,按采样权重折算。 |
| `scan_status` | string |  | 上传扫描结果(type = upload);其他类型为空。 |
| `scan_steps` | string[] |  | 上传扫描过程,按序每层一项「层:结果」。 |
| `scheme` | string |  | 请求协议(http 或 https)。 |
| `score` | integer |  | 体检得分(满分 100)。 |
| `series` | LabeledLine[] |  | 按子对象分组的时间序列。 |
| `server_port` | integer |  | 请求到达的端口。 |
| `severity` | string |  | 该问题在这个网站上的严重程度。 可选值: ["critical","medium","advice"] |
| `site_deleted` | boolean |  | 这条日志所属的网站已被删除时为 true;网站仍在(或没有所属网站)不回。 |
| `site_id` | integer |  | 网站 ID |
| `site_ids` | integer[] | 有 | 要处理的网站,最多 500 个。 |
| `site_name` | string |  | 所属站点名称(主域名,没有域名用站点名);站点已删取删除时审计里的域名,审计里没有再取近 7 天访问日志里最常见的域名,都没有则不回。 |
| `snippet` | string |  | 命中片段(节点已脱敏,命中参数或请求头的值);列表截取前 200 个字符,详情给完整。片段不带命中位置,不能据此定位高亮。Bot 事件为触发的信号名。 |
| `source_ips` | integer |  | 来源 IP 去重数。 |
| `stage` | integer |  | 当前阶段:0 排队,1 读取配置,2 统计日志,3 直连探测,4 逐项判定,5 保存并告警。站点多于 200 个时每 200 个一批,阶段号随批循环;逐项判定在后端是瞬时的。 |
| `started_at` | string |  | 批次建立时刻。 |
| `state` | string |  | 状态:pending 排队,running 运行,done 完成,failed 重试耗尽失败。 可选值: ["pending","running","done","failed"] |
| `status` | string |  | 状态:pending 排队、running 导出中、done 可下载、failed 失败、expired 文件已过保留期被清理。 可选值: ["pending","running","done","failed","expired"] |
| `step` | integer |  | series 的桶宽(秒)。 |
| `summary` | CheckupRunSummary |  | 各阶段的处理量摘要;某阶段还没走到时该键缺省。多批任务按批累加。 |
| `target` | string |  | 命中位置:uri / query_string / args / args_names / cookies / headers / body 等。 |
| `tenant_id` | integer |  | 站点所属租户(用户)ID。 |
| `top_rules` | SecurityRuleCount[] |  | 命中规则 Top 10(按命中次数降序)。 |
| `top_sites` | SecuritySiteCount[] |  | 被攻击网站 Top 10(按拦截与挑战数降序)。 |
| `total` | integer |  | 时间窗内请求数(按采样权重折算)。 |
| `total_rows` | integer |  | 符合筛选的总行数(开始导出时统计)。 |
| `total_sites` | integer |  | 本批次要体检的网站数;排队中可能还是 0。 |
| `totals` | SitesOverviewTotals |  | 时间窗内合计。 |
| `traffic_month` | integer |  | 本月累计流量(出口字节):end 所在月 1 日 0 点(Asia/Shanghai)到 end;已封账的小时取 5 分钟汇总,其后取实时数据。 |
| `traffic_today` | integer |  | 今日流量(出口字节):end 所在日的 0 点(Asia/Shanghai)到 end;口径同 totals.traffic(含不含未配置流量随 include_noconfig)。 |
| `ts` | string |  | 请求时刻。 |
| `type` | string |  | 事件类型:规则 / 语义 / Bot / 上传扫描 / 防篡改 / 防泄露。 可选值: ["waf","semantic","bot","upload","tamper","leak"] |
| `types` | SecurityTypeCount[] |  | 攻击类型分布(WAF 事件按类型折算命中次数),次数降序。 |
| `unavailable` | string[] |  | 本次没取到的补充项(规则库或 ClickHouse 暂时读失败时才有;其余内容照常返回,取不到的项按空值给)。coverage = covered / extra,probes = probes,node_ips = node_ips。缺省 = 全部取到。 |
| `unknown` | integer |  | 归属国家未识别的请求数(无库、内网或库里没有)。 |
| `unlimited` | boolean |  | true = 不限次数(管理员),此时不给 limit / remaining。 |
| `upid` | integer |  | 回源的源站 ID。 |
| `upstream_addr` | string |  | 回源实际连的源站「地址:端口」;换源站重试时逗号分隔多跳;未回源为空。 |
| `upstream_bytes` | integer |  | 从源站收到的字节数。 |
| `upstream_status` | string |  | 各跳源站回的状态码,与 upstream_addr 逐跳对应;未回源为空。 |
| `upstream_time_ms` | integer |  | 源站响应耗时,毫秒;未回源为 null。 |
| `uri` | string |  | 请求 URI(含查询串)。 |
| `url` | string |  | 请求路径 + 查询串(已脱敏)。 |
| `used` | integer |  | 今天已建成的申请数。 |
| `user_agent` | string |  | 请求的 User-Agent。 |
| `version` | string |  | 程序版本;不知道可留空。 |
| `window_min` | integer |  | 本次取均值的窗口(分钟)。 |
| `window_s` | integer |  | 统计窗口秒数。 |
