## 已购套餐 (`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 |
