{
 "components": {
  "schemas": {
   "account": {
    "properties": {
     "balance_cents": {
      "description": "Account balance in cents.",
      "type": "integer",
      "x-description-zh": "账户余额(分)。"
     },
     "freeze_reason": {
      "description": "Freeze reason; empty if not frozen.",
      "type": "string",
      "x-description-zh": "冻结原因;未冻结为空。"
     },
     "frozen": {
      "description": "Whether the account is frozen; deductions are rejected while frozen.",
      "type": "boolean",
      "x-description-zh": "是否已冻结;冻结后扣款一律被拒。"
     },
     "updated_at": {
      "description": "Updated at",
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "user_id": {
      "description": "User ID",
      "type": "integer",
      "x-description-zh": "用户 ID"
     }
    },
    "type": "object"
   },
   "acls": {
    "properties": {
     "builtin": {
      "description": "Built-in object; cannot be deleted.",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "内置对象,不可删。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "default_action": {
      "description": "Action when no rule matches.",
      "enum": [
       "allow",
       "deny"
      ],
      "type": "string",
      "x-description-zh": "都不命中时的动作。"
     },
     "des": {
      "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
      "type": "string",
      "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
     },
     "enabled": {
      "default": true,
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "errors": {
      "description": "Why each remaining item was not changed; field is /ids/\u003cindex\u003e, code as in the single-item update (not_found, readonly and so on).",
      "items": {
       "type": "object",
       "x-gocdn-type": "FieldError"
      },
      "type": "array",
      "x-description-zh": "没改的逐条原因;field 为 /ids/\u003c下标\u003e,code 同单条修改接口(not_found、readonly 等)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "IDs of the objects to change, at most 100.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要改的对象 id,至多 100 个。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "rules": {
      "description": "Matched in order; the count is limited by the setting protect.acl_rules_max.",
      "items": {
       "type": "object",
       "x-gocdn-type": "AclRule"
      },
      "type": "array",
      "x-description-zh": "按序匹配;条数受配置 protect.acl_rules_max 约束。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
     },
     "updated": {
      "description": "IDs that were set (including those already in the target state), in request order.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "已改好的 id(含本来就是目标状态的),按请求顺序。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "acme-accounts": {
    "properties": {
     "api_checked_at": {
      "description": "Time the API key was last checked.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "最近一次检测 API Key 的时间。"
     },
     "api_error": {
      "description": "Last account-level error from checking the API key or issuing with it.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "API Key 最近一次检测或签发遇到的账号级错误。"
     },
     "api_key": {
      "description": "Mask of the ZeroSSL REST API key (`****abcd`); empty = not set. The key is stored encrypted and never returned in plaintext.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。"
     },
     "api_state": {
      "description": "API key state: none = not set; ok = usable; blocked = account-level error (quota reached, unpaid, key rejected; retried after 6 hours or after a successful recheck); error = the key cannot be decrypted and must be re-entered.",
      "enum": [
       "none",
       "ok",
       "blocked",
       "error"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "API Key 状态:none 没配;ok 可用;blocked 账号级错误(额度满、欠费、Key 被拒,6 小时后或重新检测通过再签);error Key 解不开须重填。"
     },
     "ca": {
      "description": "CA that issues certificates: lets = Let's Encrypt; zerossl = ZeroSSL.",
      "enum": [
       "lets",
       "zerossl"
      ],
      "type": "string",
      "x-description-zh": "签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "directory": {
      "description": "ACME directory URL; empty = the CA's URL in the controller's acme.directories (the production URL by default).",
      "type": "string",
      "x-description-zh": "ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。"
     },
     "eab_hmac": {
      "description": "Masked (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
      "type": "string",
      "x-description-zh": "掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
     },
     "eab_kid": {
      "description": "EAB key ID (used by ZeroSSL).",
      "type": "string",
      "x-description-zh": "EAB 密钥 id(ZeroSSL 用)。"
     },
     "email": {
      "description": "Email",
      "type": "string",
      "x-description-zh": "邮箱"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "last_error": {
      "description": "Last error",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "最近一次错误"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "recheck": {
      "description": "When true, re-check the stored API key; on success the account becomes usable again and certificates waiting on it are retried immediately.",
      "type": "boolean",
      "x-description-zh": "为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。"
     },
     "status": {
      "description": "new = not registered yet; registered = registered with the CA; error = registration failed (see last_error).",
      "enum": [
       "new",
       "registered",
       "error"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "new = 还没注册;registered = 已在 CA 注册;error = 注册失败(原因见 last_error)。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform account.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台账号。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "alert-rules": {
    "properties": {
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "AlertRule"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     }
    },
    "type": "object"
   },
   "alerts": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "detail": {
      "description": "Additional details.",
      "type": "string",
      "x-description-zh": "补充说明。"
     },
     "id": {
      "description": "Record ID",
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "kind": {
      "description": "fire: alert fired; resolve: recovered.",
      "enum": [
       "fire",
       "resolve"
      ],
      "type": "object",
      "x-description-zh": "fire 告警;resolve 恢复。",
      "x-gocdn-type": "AlertKind"
     },
     "msg_id": {
      "description": "Notification sent (in-app message ID).",
      "type": "integer",
      "x-description-zh": "发出的通知(站内信 id)。"
     },
     "rule": {
      "description": "Alert rule key.",
      "type": "string",
      "x-description-zh": "告警规则标识。"
     },
     "subject": {
      "description": "Subject the alert is about, such as a node or site.",
      "type": "string",
      "x-description-zh": "告警针对的对象,如节点或站点。"
     },
     "threshold": {
      "description": "Threshold of the rule.",
      "type": "number",
      "x-description-zh": "规则的阈值。"
     },
     "title": {
      "description": "Chinese name of the rule (same as rule when the rule no longer exists).",
      "type": "string",
      "x-description-zh": "规则中文名(规则已不在表里时同 rule)。"
     },
     "unit": {
      "description": "Unit of the value and threshold.",
      "type": "string",
      "x-description-zh": "数值与阈值的单位。"
     },
     "value": {
      "description": "Value that triggered the alert.",
      "type": "number",
      "x-description-zh": "触发告警的当前值。"
     }
    },
    "type": "object"
   },
   "api-keys": {
    "properties": {
     "allow_ips": {
      "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
      "type": "object",
      "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
      "x-gocdn-type": "ApiKeyAllowIps"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "expires_at": {
      "description": "Expires at",
      "type": "string",
      "x-description-zh": "过期时间"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "last_used_at": {
      "description": "Time of last use; null if never used",
      "type": "string",
      "x-description-zh": "最近一次使用时间;从未使用为空。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "prefix": {
      "description": "First few characters of the plaintext key, for recognition",
      "type": "string",
      "x-description-zh": "明文的前几位,便于辨认。"
     },
     "reset": {
      "description": "When true, issue a new key; the old one stops working at once",
      "type": "boolean",
      "x-description-zh": "为 true 时换新 key,旧 key 立即失效。"
     },
     "scopes": {
      "description": "Granted scopes, same values as scopes at creation",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "授权范围,取值同创建时的 scopes。"
     },
     "secret": {
      "description": "Plaintext key (the X-API-Key value), returned only once at creation; only a hash is stored",
      "type": "string",
      "x-description-zh": "明文 key(X-API-Key 的值),只在创建时返回一次;库里只存哈希。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "auth": {
    "properties": {
     "access_token": {
      "description": "Access token, sent as Authorization: Bearer",
      "type": "string",
      "x-description-zh": "访问令牌,放在 Authorization: Bearer 里调用接口。"
     },
     "captcha_code": {
      "description": "Characters shown in the captcha image",
      "type": "string",
      "x-description-zh": "图形验证码上显示的字符。"
     },
     "captcha_id": {
      "description": "Captcha id from GET /auth/captcha; required after repeated failed logins",
      "type": "string",
      "x-description-zh": "图形验证码 id,来自 GET /auth/captcha;连续登录失败后必填。"
     },
     "channel": {
      "description": "Recover by email or by phone number",
      "enum": [
       "email",
       "sms"
      ],
      "type": "string",
      "x-description-zh": "按邮箱还是手机号找回。"
     },
     "code": {
      "description": "Verification code sent to target (POST /verify-codes, purpose=reset_password)",
      "type": "string",
      "x-description-zh": "发到 target 的验证码(POST /verify-codes,purpose=reset_password)。"
     },
     "expires_in": {
      "description": "Access token lifetime in seconds",
      "type": "integer",
      "x-description-zh": "access token 有效秒数。"
     },
     "id": {
      "description": "Pass back as captcha_id when logging in; single use, invalidated after one check whether right or wrong",
      "type": "string",
      "x-description-zh": "登录时作为 captcha_id 回传;一次性,验一次即作废(不论对错)。"
     },
     "image": {
      "description": "PNG data URI",
      "type": "string",
      "x-description-zh": "PNG 的 data URI。"
     },
     "key": {
      "description": "Base32 secret (returned only once, here)",
      "type": "string",
      "x-description-zh": "base32 密钥(只在这里返回一次)。"
     },
     "must_change_password": {
      "description": "Login response only; true means the account still uses the installer-generated initial password and must change it first.",
      "type": "boolean",
      "x-description-zh": "只在登录响应里出现;true = 该账号还在用装机生成的初始口令(/root/gocdn-admin.pass),须先改口令(PUT /auth/password)再用,改过后不再出现。"
     },
     "new_password": {
      "description": "New password, 8 to 128 characters",
      "example": "correct-horse-battery",
      "type": "string",
      "x-description-zh": "新口令,8 到 128 个字符。"
     },
     "old_password": {
      "description": "Current password",
      "type": "string",
      "x-description-zh": "原口令。"
     },
     "otpauth_uri": {
      "description": "otpauth:// URI to add to an authenticator app by scanning",
      "type": "string",
      "x-description-zh": "otpauth:// 地址,用认证器 App 扫码添加。"
     },
     "password": {
      "description": "Login password",
      "type": "string",
      "x-description-zh": "登录口令。"
     },
     "recovery_codes": {
      "description": "Eight one-time recovery codes (XXXXX-XXXXX), returned only once, when TOTP is enabled",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "8 个一次性恢复码(XXXXX-XXXXX),只在启用成功时返回这一次。"
     },
     "refresh_token": {
      "description": "Refresh token, exchanged for a new token pair",
      "type": "string",
      "x-description-zh": "刷新令牌,用来换新的一对令牌。"
     },
     "sso_ticket": {
      "description": "Login ticket issued by the super admin: base64url (no padding) bytes of a licwire envelope (kind sso_ticket)",
      "type": "string",
      "x-description-zh": "超管签发的登录票:licwire 信封(kind sso_ticket)字节的 base64url(无填充)。"
     },
     "switch_ticket": {
      "description": "One-time switch ticket obtained by an administrator.",
      "type": "string",
      "x-description-zh": "管理员换到的一次性切换票。"
     },
     "target": {
      "description": "Email or phone number bound to the account",
      "type": "string",
      "x-description-zh": "账号绑定的邮箱或手机号。"
     },
     "token_type": {
      "description": "Token type, always Bearer",
      "example": "Bearer",
      "type": "string",
      "x-description-zh": "令牌类型,固定为 Bearer。"
     },
     "totp_code": {
      "description": "Current 6-digit TOTP code, or an unused recovery code (XXXXX-XXXXX, consumed on use); required when the account has TOTP enabled",
      "type": "string",
      "x-description-zh": "动态口令(TOTP)的 6 位当前码,或一个未用过的恢复码(XXXXX-XXXXX,用后作废);账号启用动态口令时必填。"
     },
     "user_id": {
      "description": "User ID",
      "type": "integer",
      "x-description-zh": "用户 ID"
     },
     "username": {
      "description": "Username",
      "type": "string",
      "x-description-zh": "用户名"
     },
     "verify_code": {
      "description": "Second-factor login code. Required when the account has email/SMS code login (login_verify) enabled; obtain it first via POST /verify-codes (purpose=login)",
      "type": "string",
      "x-description-zh": "登录二次验证码。账号开了邮件/短信验证码登录(login_verify)时必填,先经 POST /verify-codes(purpose=login)获取。"
     }
    },
    "type": "object"
   },
   "bans": {
    "properties": {
     "all": {
      "description": "true = unban the whole site, clearing every ban of site_id; level=site only and counts as one unban toward the daily limit.",
      "type": "boolean",
      "x-description-zh": "true = 全站解封:清空 site_id 这个站的全部封禁,只用于 level=site,计 1 次每天解封次数。"
     },
     "batch_max": {
      "description": "Maximum IPs per unban request (setting protect.unban_batch_max).",
      "type": "integer",
      "x-description-zh": "一次最多解封几个 IP(配置 protect.unban_batch_max)。"
     },
     "by_admin": {
      "description": "true = unbanned by an administrator on the site owner's behalf (recorded under and visible to the owner, does not use the owner's daily quota).",
      "type": "boolean",
      "x-description-zh": "true = 管理员代站主解封(记在站主名下、站主可见,不占站主每天次数)。"
     },
     "count": {
      "description": "Number of unexpired bans.",
      "type": "integer",
      "x-description-zh": "未到期封禁条数。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "daily_max": {
      "description": "Maximum unbans per tenant per day (setting protect.unban_daily_max).",
      "type": "integer",
      "x-description-zh": "租户每天最多解封几次(配置 protect.unban_daily_max)。"
     },
     "expires_at": {
      "description": "Expiry time; null = permanent.",
      "type": "string",
      "x-description-zh": "到期时刻;null = 永久。"
     },
     "filter_id": {
      "description": "The filter (rule set or module) that triggered the ban, split from reason, such as cc.level.r5, waf, scan.builtin or ssl_handshake; absent for manual bans and for auto.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "触发的过滤器(规则集或模块),由 reason 拆出,如 cc.level.r5、waf、scan.builtin、ssl_handshake;手工封禁与无规则的 auto 不给。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "intel": {
      "description": "Where a banned IP stands in the platform high-risk IP library right now (looked up against the current library when listing; fields the library does not carry, or entries already expired, are absent).",
      "type": "object",
      "x-description-zh": "封禁 IP 在平台高危 IP 库里的现状(列表时按当前库现查;库没在下发、已出库或库没给的字段不返回)。",
      "x-gocdn-type": "BanIntel"
     },
     "intel_hit": {
      "description": "Whether the IP is in the platform high-risk IP library; null = not judged yet (always null until the library ships).",
      "type": "boolean",
      "x-description-zh": "该 IP 是否在平台高危 IP 库;null = 尚未判定(高危 IP 库上线前恒为 null)。"
     },
     "ip": {
      "description": "IP or CIDR.",
      "type": "string",
      "x-description-zh": "IP 或 CIDR。"
     },
     "ip_count": {
      "description": "Number of unbanned IPs/CIDRs (0 for a whole-site unban).",
      "type": "integer",
      "x-description-zh": "解封的 IP/CIDR 条数(全站解封为 0)。"
     },
     "ips": {
      "description": "IPs/CIDRs to unban (omit when all=true, required otherwise); the number per request is limited by protect.unban_batch_max and the daily count per tenant by protect.unban_daily_max.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "要解封的 IP/CIDR(all=true 时不带,否则必填);一次条数受 protect.unban_batch_max 约束,租户每天次数受 protect.unban_daily_max 约束。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "BanSourceCount"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "level": {
      "description": "Scope: site = one site; tenant = all sites of the tenant; global = the whole network (admin only).",
      "enum": [
       "site",
       "tenant",
       "global"
      ],
      "type": "string",
      "x-description-zh": "作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。"
     },
     "reason": {
      "description": "Reason: manual by default for bans created in the panel; for automatic bans by a node, the triggering rule (ruleset/rule id such as cc.level.r5/r1) or module name (ssl_handshake = handshake flood), or auto when there is no rule.",
      "type": "string",
      "x-description-zh": "原因:人工封禁默认 manual;节点自动封的是触发规则(规则集/规则 id,如 cc.level.r5/r1)或模块名(ssl_handshake = 握手洪水),无规则的记 auto。"
     },
     "removed": {
      "description": "Number of entries removed from the ban table at the same time.",
      "type": "integer",
      "x-description-zh": "同时从封禁表删除的条数。"
     },
     "rule_id": {
      "description": "The rule number that triggered the ban, split from reason (r1 of cc.level.r5/r1, 941100 of waf:941100); absent when there is none.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "触发的规则号,由 reason 拆出(cc.level.r5/r1 的 r1、waf:941100 的 941100);没有规则号的不给。"
     },
     "site_id": {
      "description": "Site id, required when level=site; 0 otherwise.",
      "type": "integer",
      "x-description-zh": "level=site 时必填的站点 id;其余为 0。"
     },
     "source": {
      "description": "manual = created in the panel; node = banned automatically by a node and reported (one row per target while unexpired; a repeat ban extends it). Both are lifted the same way, by deleting or via /bans/unban.",
      "enum": [
       "manual",
       "node"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "manual = 面板下的;node = 节点自动封后上报的(同一对象未到期时只留一行,再封续期)。解封两者一样:删除或 /bans/unban。"
     },
     "source_type": {
      "description": "Source type: manual = created in the panel; cc = CC rule group (cc.level.*, cc.user.*, auto and other rule sets); waf = repeated WAF rule hits; scan = built-in scanner set; status = built-in status-code set; tls = handshake flood; intel = platform high-risk IP library. A ban made by a node is never manual.",
      "enum": [
       "manual",
       "cc",
       "waf",
       "scan",
       "status",
       "tls",
       "intel"
      ],
      "type": "object",
      "x-description-zh": "来源细类:manual = 面板下的;cc = CC 规则组(含 cc.level.*、cc.user.*、auto 及其余规则集);waf = WAF 规则连续命中;scan = 扫描器内置集;status = 状态码内置集;tls = 握手洪水;intel = 平台高危 IP 库。节点自动封的永不是 manual。",
      "x-gocdn-type": "BanSourceType"
     },
     "status": {
      "description": "Status of the push task pending/running/done/failed; null once the task has been purged.",
      "type": "string",
      "x-description-zh": "下发任务状态 pending/running/done/failed;任务已被清理为 null。"
     },
     "task_id": {
      "description": "Id of the background task that pushes the change to nodes (poll progress with GET /tasks/{id}).",
      "type": "integer",
      "x-description-zh": "下发节点的后台任务 id(GET /tasks/{id} 查进度)。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "used": {
      "description": "Unbans the tenant made itself today (since 00:00 UTC); unbans by an administrator do not count, and it is 0 when an administrator calls.",
      "type": "integer",
      "x-description-zh": "本租户今天(UTC 零点起)自己解封的次数;管理员代解不计,管理员调用时为 0。"
     }
    },
    "type": "object"
   },
   "bot-settings": {
    "properties": {
     "actions": {
      "description": "Action per class; defaults are allow for search engines and monitors/tools, log for automation tools, challenge for headless browsers and block for malicious bots and fake crawlers. headless, malicious and fake belong to WAF enhanced.",
      "type": "object",
      "x-description-zh": "按类处置;缺省搜索引擎、监控·工具放行,自动化工具只记录,无头浏览器验证,恶意 Bot 与伪造爬虫拦截。headless、malicious、fake 属 WAF 增强。"
     },
     "challenge": {
      "description": "Challenge kind used when the action is challenge - js (invisible), slide, rotate, click or captcha (default js).",
      "enum": [
       "js",
       "slide",
       "rotate",
       "click",
       "captcha"
      ],
      "type": "string",
      "x-description-zh": "处置为 challenge 时的验证方式:js 无感、slide 滑块、rotate 旋转图片、click 点选、captcha 字符(缺省 js)。"
     },
     "enabled": {
      "description": "Master switch; false = no site does bot detection.",
      "type": "boolean",
      "x-description-zh": "总开关;false = 所有站点都不做 Bot 判定。"
     },
     "enhanced": {
      "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; headless browsers, malicious bots and fake crawlers are treated as ordinary visitors and not scored, settings kept); ignored on update.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(无头浏览器、恶意 Bot、伪造爬虫按普通访客,不打分,设置保留);修改时忽略。"
     },
     "exceptions": {
      "description": "Exceptions - matching requests skip bot detection (at least one of path, cidr and ja4; several in one entry must all match).",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "例外:命中的请求不做 Bot 判定(path、cidr、ja4 至少一项,同一条里多项须同时满足)。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "protect": {
      "description": "Protected endpoints (path prefixes such as /login, WAF enhanced) - requesting them without loading a page first adds to the score.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "保护接口(路径前缀,如 /login,WAF 增强):没看过页面直接请求它们加分。"
     },
     "score": {
      "description": "Behaviour score bands (WAF enhanced, 0-100) - below js pass; js to slide invisible challenge; slide to block challenge by kind; from block act as a malicious bot. Requires js \u003c slide \u003c block. A visitor who passes a challenge scores 0 for 30 minutes.",
      "type": "object",
      "x-description-zh": "行为评分分段(WAF 增强,0–100):低于 js 放行;js 到 slide 无感验证;slide 到 block 按 kind 验证;达到 block 按恶意 Bot 处置。须 js \u003c slide \u003c block。通过验证的访客 30 分钟内分数清零。"
     },
     "updated_at": {
      "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。"
     }
    },
    "type": "object"
   },
   "bot-stats": {
    "properties": {
     "classes": {
      "description": "Bot classes seen today with their action breakdown, in fixed class order (search, monitor, automation, headless, malicious, fake); classes not seen today are omitted; empty when the log database is unavailable.",
      "items": {
       "type": "object",
       "x-gocdn-type": "BotClassStat"
      },
      "type": "array",
      "x-description-zh": "今日出现过的 Bot 分类及处置分项,按分类固定次序(search、monitor、automation、headless、malicious、fake);今日没出现的分类不列;日志库不可用为空数组。"
     },
     "node_upgrade": {
      "description": "Node upgrade progress - approved nodes whose reported version matches this master; visible to admins only, omitted from tenant responses.",
      "type": "object",
      "x-description-zh": "节点升级进度:上报版本与本主控一致的节点占已通过审核的节点;仅管理员能看到,租户的响应不带此字段。",
      "x-gocdn-type": "BotNodeUpgrade"
     },
     "replay_sites": {
      "description": "Replay protection coverage.",
      "type": "object",
      "x-description-zh": "防重放启用情况。",
      "x-gocdn-type": "BotReplaySites"
     },
     "today_requests": {
      "description": "All requests today; null when the log database is unavailable.",
      "type": "integer",
      "x-description-zh": "今日全部请求数;日志库不可用为 null。"
     }
    },
    "type": "object"
   },
   "cache-groups": {
    "properties": {
     "cache": {
      "description": "Cache rules, same as the cache field ({rules, ignore_params}) of the node contract schema/site.json; validated by the server against the contract.",
      "type": "object",
      "x-description-zh": "缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。",
      "x-gocdn-type": "CacheConfig"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "from_site_id": {
      "description": "Save from a site (rules are taken from the site's current effective value; cache is ignored).",
      "type": "integer",
      "x-description-zh": "从站点另存(规则取该站当前生效值,忽略 cache)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "is_default": {
      "description": "Platform default group (exactly one).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "平台默认分组(恰一个)。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "site_count": {
      "description": "Number of sites that reference it explicitly (tenant callers only count their own).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "显式引用它的站点数(租户调用只数自己的)。"
     },
     "sort": {
      "description": "Display order (smaller first).",
      "type": "integer",
      "x-description-zh": "排序值(小的在前)。"
     },
     "switch_site": {
      "description": "After saving, make the site reference the new group.",
      "type": "boolean",
      "x-description-zh": "另存后让该站引用新分组。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform group.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "属主租户;null = 平台分组。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "cache-jobs": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "results": {
      "description": "Execution result of each node (returned in details only).",
      "items": {
       "type": "object",
       "x-gocdn-type": "CacheJobNodeResult"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "各节点的执行结果(只在详情里回)。"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "status": {
      "description": "Status of the push task (if some nodes fail it stays pending and retries with backoff, then becomes failed when retries run out).",
      "enum": [
       "pending",
       "running",
       "done",
       "failed"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "下发任务的状态(有节点失败时 pending 退避重试,次数用完 failed)。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "type": {
      "description": "purge_url = purge URLs; purge_dir = purge directories (URL ends with /); prefetch = prefetch.",
      "enum": [
       "purge_url",
       "purge_dir",
       "prefetch"
      ],
      "type": "string",
      "x-description-zh": "purge_url 刷新 URL;purge_dir 刷新目录(URL 以 / 结尾);prefetch 预热。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "urls": {
      "description": "http(s)://host/path (normalized, see create); at most 100 entries per prefetch.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "http(s)://主机/路径(规范化后,见创建接口);预热一次最多 100 条。"
     }
    },
    "type": "object"
   },
   "cache-policy": {
    "properties": {
     "applied": {
      "description": "Number of sites updated.",
      "type": "integer",
      "x-description-zh": "已改回的站点数。"
     },
     "default_group_id": {
      "description": "Platform default group; null = no group yet.",
      "type": "integer",
      "x-description-zh": "平台默认分组;null = 还没有分组。"
     },
     "my_default_group_id": {
      "description": "Default group in effect for this tenant (the one it set, or the platform default if none).",
      "type": "integer",
      "x-description-zh": "本租户生效的默认分组(自己设的,没设为平台默认)。"
     },
     "my_default_group_set": {
      "description": "Whether this tenant has set its own default group.",
      "type": "boolean",
      "x-description-zh": "本租户自己设过默认分组。"
     },
     "sites": {
      "description": "Number of the tenant's sites by cache mode: group (follows a cache group) and custom (own rules).",
      "type": "object",
      "x-description-zh": "本租户站点按缓存方式的数量:group(按缓存分组)与 custom(自定义规则)。"
     }
    },
    "type": "object"
   },
   "cache-presets": {
    "properties": {
     "cache": {
      "description": "Cache rules, same as the cache field ({rules, ignore_params}) of the node contract schema/site.json; validated by the server against the contract.",
      "type": "object",
      "x-description-zh": "缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。",
      "x-gocdn-type": "CacheConfig"
     }
    },
    "type": "object"
   },
   "cache-quota": {
    "properties": {
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "CacheQuotaItem"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     }
    },
    "type": "object"
   },
   "cache-sites": {
    "properties": {
     "effective_group_id": {
      "description": "Group actually in effect when mode=group; null = no usable group (no cache rules are pushed).",
      "type": "integer",
      "x-description-zh": "mode=group 时实际生效的分组;null = 没有可用分组(不下发缓存规则)。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
      "type": "string",
      "x-description-zh": "乐观锁(修改时用):调用方读到的站点 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
     },
     "group_id": {
      "description": "Group referenced explicitly; null = follows the default group.",
      "type": "integer",
      "x-description-zh": "显式引用的分组;null = 按默认分组。"
     },
     "mode": {
      "description": "Cache mode: group = follows a cache group; custom = site's own rules.",
      "enum": [
       "group",
       "custom"
      ],
      "type": "string",
      "x-description-zh": "缓存方式:group 按缓存分组;custom 为站点自定义规则。"
     },
     "site_id": {
      "description": "Site ID",
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "updated_at": {
      "description": "updated_at of the site (the version of the site row, also bumped when the cache mode changes); send it back as expected_updated_at when changing the cache mode.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "站点的 updated_at(站点行的版本,改缓存方式也会更新);改缓存方式时作 expected_updated_at 带回。"
     }
    },
    "type": "object"
   },
   "cc-filters": {
    "properties": {
     "builtin": {
      "description": "Built-in object; cannot be deleted.",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "内置对象,不可删。"
     },
     "count_key": {
      "description": "Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip).",
      "enum": [
       "ip",
       "ja4",
       "ip_ja4"
      ],
      "type": "string",
      "x-description-zh": "按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
      "type": "string",
      "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "kind": {
      "description": "Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate.",
      "type": "string",
      "x-description-zh": "挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。"
     },
     "max": {
      "description": "Requests allowed within the window.",
      "type": "integer",
      "x-description-zh": "窗口内允许的请求数。"
     },
     "mode": {
      "description": "Required for url_auth: signing scheme. a = ?\u003csign_arg\u003e=md5(key+path+timestamp)\u0026\u003ctime_arg\u003e=timestamp; b = ?\u003csign_arg\u003e=timestamp-random-uid-md5(path-timestamp-random-uid-key).",
      "enum": [
       "a",
       "b"
      ],
      "type": "string",
      "x-description-zh": "url_auth 必填:鉴权方式。a = ?\u003csign_arg\u003e=md5(密钥+路径+时间戳)\u0026\u003ctime_arg\u003e=时间戳;b = ?\u003csign_arg\u003e=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "per_uri_max": {
      "description": "rate: per-URI limit; 0 = unlimited.",
      "type": "integer",
      "x-description-zh": "rate:单 URI 上限;0 = 不限。"
     },
     "sign_arg": {
      "description": "Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen).",
      "type": "string",
      "x-description-zh": "url_auth 必填:签名参数名(字母、数字、下划线、连字符)。"
     },
     "sign_use_max": {
      "description": "url_auth: how many times the same signature may be used; 0 = unlimited.",
      "type": "integer",
      "x-description-zh": "url_auth:同一签名最多用几次;0 = 不限。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
     },
     "time_arg": {
      "description": "Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b.",
      "type": "string",
      "x-description-zh": "url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。"
     },
     "ttl_s": {
      "description": "Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time.",
      "type": "integer",
      "x-description-zh": "url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。"
     },
     "type": {
      "description": "rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt).",
      "enum": [
       "rate",
       "challenge",
       "url_auth"
      ],
      "type": "string",
      "x-description-zh": "rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "window_s": {
      "description": "Counting window in seconds.",
      "type": "integer",
      "x-description-zh": "统计窗口秒数。"
     }
    },
    "type": "object"
   },
   "cc-matches": {
    "properties": {
     "builtin": {
      "description": "Built-in object; cannot be deleted.",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "内置对象,不可删。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
      "type": "string",
      "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
     },
     "hits": {
      "description": "Requests matched in the window (restored by sample_weight).",
      "type": "integer",
      "x-description-zh": "窗口内命中的请求数(按 sample_weight 还原)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ips": {
      "description": "Distinct client IPs among the matched requests (a distinct count, not restored by sample weight).",
      "type": "integer",
      "x-description-zh": "命中请求涉及的不同客户端 IP 数(去重计数,不按采样还原)。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "reason": {
      "description": "Explanation when supported=false.",
      "type": "string",
      "x-description-zh": "supported=false 时的说明。"
     },
     "sampled": {
      "description": "Some rows in the window were sampled (sample_weight \u003e 1); hits and total are estimates.",
      "type": "boolean",
      "x-description-zh": "窗口内有被采样的行(sample_weight \u003e 1);此时 hits、total 是估计值。"
     },
     "site_id": {
      "description": "Count this site's traffic only; omitted = every site visible to the caller.",
      "type": "integer",
      "x-description-zh": "只算这个网站的流量;不给 = 当前身份可见的全部网站。"
     },
     "sites": {
      "description": "Distinct sites among the matched requests (a distinct count, not restored by sample weight).",
      "type": "integer",
      "x-description-zh": "命中请求涉及的不同网站数(去重计数,不按采样还原)。"
     },
     "supported": {
      "description": "false = the condition uses something access_log does not hold (request headers, accept_language, named sets), so nothing was replayed; see reason.",
      "type": "boolean",
      "x-description-zh": "false = 条件里有访问日志没有的字段(请求头、accept_language、命名集合),没有回放;原因见 reason。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
     },
     "top_ips": {
      "description": "Client IPs with the most matched requests, at most 20, sorted by requests descending; empty when supported=false or nothing matched.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CcMatchReplayIp"
      },
      "type": "array",
      "x-description-zh": "命中请求最多的客户端 IP,最多 20 条,按请求数降序;supported=false 或没有命中时为空。"
     },
     "top_urls": {
      "description": "URLs (without the query string) with the most matched requests, at most 5, sorted by requests descending; empty when supported=false or nothing matched.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CcMatchReplayUrl"
      },
      "type": "array",
      "x-description-zh": "命中请求最多的 URL(不含查询串),最多 5 条,按请求数降序;supported=false 或没有命中时为空。"
     },
     "total": {
      "description": "Total requests in the window (also restored).",
      "type": "integer",
      "x-description-zh": "窗口内的请求总数(同样还原)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "when": {
      "description": "Rule DSL condition: a combination of all/any/not, or a leaf {f, op, v, set, neg}; validated by the server and errors are returned as 422 (field is a JSON Pointer, code is the lowercase DSL error code). null = match everything.",
      "type": "object",
      "x-description-zh": "规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。"
     },
     "window_hours": {
      "description": "Replay window in hours (fixed at 24).",
      "type": "integer",
      "x-description-zh": "回放窗口小时数(固定 24)。"
     }
    },
    "type": "object"
   },
   "cc-rules": {
    "properties": {
     "builtin": {
      "description": "Built-in object; cannot be deleted.",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "内置对象,不可删。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
      "type": "string",
      "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
     },
     "enabled": {
      "default": true,
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "errors": {
      "description": "Why each remaining item was not changed; field is /ids/\u003cindex\u003e, code as in the single-item update (not_found, readonly and so on).",
      "items": {
       "type": "object",
       "x-gocdn-type": "FieldError"
      },
      "type": "array",
      "x-description-zh": "没改的逐条原因;field 为 /ids/\u003c下标\u003e,code 同单条修改接口(not_found、readonly 等)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "IDs of the objects to change, at most 100.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要改的对象 id,至多 100 个。"
     },
     "items": {
      "description": "Rule items, executed in order; the count is limited by the setting protect.cc_rule_items_max.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CcRuleItem"
      },
      "type": "array",
      "x-description-zh": "规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "ruleset_id": {
      "description": "Compiled ruleset id: cc.level.\u003cname\u003e for platform groups (referenced by the site's cc_level and guard.default_cc_level); cc.user.r\u003cid\u003e for tenant groups (selectable as cc_level by the tenant's own sites; sites on a package need custom_cc_rule).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "编译成的规则集 id:平台 cc.level.\u003c名\u003e(站点 cc_level、guard.default_cc_level 引用它);租户 cc.user.r\u003cid\u003e(本租户站点的 cc_level 可选它,带套餐的站点须套餐有 custom_cc_rule)。"
     },
     "show_to": {
      "description": "Tenants that can see a platform rule group; empty = visible to all tenants, otherwise only the listed tenants can see it and select it as a site's cc_level. Returned to admins only.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。"
     },
     "sort": {
      "description": "Panel sort order (smaller first).",
      "type": "integer",
      "x-description-zh": "面板排序(小的在前)。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
     },
     "updated": {
      "description": "IDs that were set (including those already in the target state), in request order.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "已改好的 id(含本来就是目标状态的),按请求顺序。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "visible": {
      "default": true,
      "description": "Shown in the site's rule group drop-down.",
      "type": "boolean",
      "x-description-zh": "在站点的规则组下拉里展示。"
     }
    },
    "type": "object"
   },
   "cc-settings": {
    "properties": {
     "auto_switch": {
      "description": "Settings for automatically switching to a stricter CC rule group.",
      "type": "object",
      "x-description-zh": "CC 防护自动升级设置:攻击时自动切换到更严的规则组。",
      "x-gocdn-type": "CcAutoSwitch"
     },
     "default_page_rule_id": {
      "description": "Platform CC rule group id used by the default page (requests to unbound domains); null or omitted = no protection.",
      "type": "integer",
      "x-description-zh": "默认页(未绑定域名)用的平台 CC 规则组 id;null 或不带 = 不防护。"
     },
     "default_rule_id": {
      "description": "Platform CC rule group id used when a site has not chosen one; null = node default.",
      "type": "integer",
      "x-description-zh": "站点未选规则组时用的平台 CC 规则组 id;null = 节点缺省。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared by CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "updated_at": {
      "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
     }
    },
    "type": "object"
   },
   "cert-settings": {
    "properties": {
     "default_type": {
      "description": "The user's own default type (custom/lets/zerossl); null = follow the platform.",
      "type": "string",
      "x-description-zh": "本人设的默认类型(custom/lets/zerossl);null = 跟随平台。"
     },
     "effective_type": {
      "description": "The default type actually in effect.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "实际生效的默认类型。"
     }
    },
    "type": "object"
   },
   "certify-channels": {
    "properties": {
     "alipay": {
      "description": "Merchant parameters of Alipay identity verification (alipay.user.certify.open.*).",
      "type": "object",
      "x-description-zh": "支付宝身份验证(alipay.user.certify.open.*)的商户参数。",
      "x-gocdn-type": "CertifyAlipay"
     },
     "wechat": {
      "description": "Parameters of Tencent Cloud FaceID (WeChat face verification, faceid DetectAuth).",
      "type": "object",
      "x-description-zh": "腾讯云慧眼(微信人脸核身,faceid DetectAuth)的参数。",
      "x-gocdn-type": "CertifyWechat"
     }
    },
    "type": "object"
   },
   "certs": {
    "properties": {
     "acme": {
      "description": "Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.).",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。",
      "x-gocdn-type": "CertAcmeSummary"
     },
     "acme_account_id": {
      "description": "Account to issue with (same as acme.acme_account_id in POST /certs); if omitted, the tenant's enabled account for the type is used first, then the platform's.",
      "type": "integer",
      "x-description-zh": "指定签发账号(同 POST /certs 的 acme.acme_account_id);不给按类型先取本租户启用的、再取平台启用的。"
     },
     "ari_end": {
      "description": "End of the renewal window suggested by the CA via ARI.",
      "type": "string",
      "x-description-zh": "CA 经 ARI 建议的续签窗口结束时间。"
     },
     "ari_start": {
      "description": "Renewal window suggested by the CA via ARI; null = none given by the CA, renew cert.acme.renew_before_days days before expiry.",
      "type": "string",
      "x-description-zh": "CA 经 ARI 建议的续签窗口;null = CA 没给,按到期前 cert.acme.renew_before_days 天续签。"
     },
     "auto_renew": {
      "description": "Defaults to true if omitted.",
      "type": "boolean",
      "x-description-zh": "不给为 true。"
     },
     "cert": {
      "description": "Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。"
     },
     "cert_id": {
      "description": "Certificate ID.",
      "type": "integer",
      "x-description-zh": "证书 id。"
     },
     "challenge": {
      "description": "Validation method: http-01, dns-01, or http-file (ZeroSSL file validation for zerossl_api).",
      "enum": [
       "http-01",
       "dns-01",
       "http-file"
      ],
      "type": "string",
      "x-description-zh": "验证方式:http-01、dns-01,或 http-file(zerossl_api 的 ZeroSSL 文件验证)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "dns_api_id": {
      "description": "DNS API credential used for DNS-01 validation (for ACME certificates).",
      "type": "integer",
      "x-description-zh": "DNS-01 验证用的 DNS API 凭据(ACME 证书用)。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "err_times": {
      "description": "Number of failures in the current round.",
      "type": "integer",
      "x-description-zh": "这一轮已失败次数。"
     },
     "failed": {
      "description": "Number of failed items.",
      "type": "integer",
      "x-description-zh": "失败的条数。"
     },
     "fingerprint": {
      "description": "SHA-256 fingerprint of the leaf certificate (lowercase hex).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "叶证书 SHA-256 指纹(小写十六进制)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "Certificate IDs.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "证书 id。"
     },
     "issued_at": {
      "description": "Time of the last successful issuance.",
      "type": "string",
      "x-description-zh": "最近一次签发成功的时间。"
     },
     "issuer": {
      "description": "Certificate issuer.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "证书颁发者。"
     },
     "items": {
      "description": "Issuance states.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CertAcme"
      },
      "type": "array",
      "x-description-zh": "签发状态。"
     },
     "key": {
      "description": "Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key.",
      "type": "string",
      "x-description-zh": "私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。"
     },
     "last_error": {
      "description": "Last error",
      "type": "string",
      "x-description-zh": "最近一次错误"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "names": {
      "description": "SANs (domains, wildcard domains or IPs); falls back to CN when there is no SAN.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "SAN(域名、通配域名或 IP);无 SAN 时取 CN。"
     },
     "next_try_at": {
      "description": "After a renewal ends in failure, the earliest time the renewal scan will retry.",
      "type": "string",
      "x-description-zh": "续签失败终态后,续签扫描最早再试的时刻。"
     },
     "not_after": {
      "description": "Certificate expiry time.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "证书到期时间。"
     },
     "not_before": {
      "description": "Time the certificate becomes valid.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "证书生效时间。"
     },
     "ocsp": {
      "description": "The leaf certificate carries an OCSP URL (nodes can staple).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "叶证书带 OCSP 地址(节点可装订)。"
     },
     "ok": {
      "description": "Number of items queued for issuance.",
      "type": "integer",
      "x-description-zh": "已排队签发的条数。"
     },
     "password": {
      "description": "Current login password.",
      "type": "string",
      "x-description-zh": "当前登录口令。"
     },
     "renewing": {
      "description": "The current round is a renewal (the old certificate stays in use on failure).",
      "type": "boolean",
      "x-description-zh": "当前这轮是续签(失败时旧证书照用)。"
     },
     "scope": {
      "description": "Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate.",
      "enum": [
       "site",
       "ip",
       "panel"
      ],
      "type": "string",
      "x-description-zh": "证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。"
     },
     "site_ids": {
      "description": "Sites using this certificate.",
      "items": {
       "type": "integer"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "在用此证书的站点。"
     },
     "state": {
      "description": "pending = queued or waiting to retry; running = issuing; issued = issued; failed = retries exhausted (alert sent).",
      "enum": [
       "pending",
       "running",
       "issued",
       "failed"
      ],
      "type": "string",
      "x-description-zh": "pending 排队或等重试;running 签发中;issued 已签出;failed 重试用完(已发提醒)。"
     },
     "tenant_id": {
      "description": "Owning tenant; null = platform IP certificate.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户;null = 平台 IP 证书。"
     },
     "totp_code": {
      "description": "Current 6-digit TOTP code; the account must have TOTP enabled.",
      "type": "string",
      "x-description-zh": "动态口令(TOTP)的 6 位当前码;账号须已启用动态口令。"
     },
     "type": {
      "description": "custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API.",
      "type": "string",
      "x-description-zh": "custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "version": {
      "description": "Certificate content version; incremented on each replacement.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "证书内容版本,换证 +1。"
     },
     "zerossl_order_id": {
      "description": "Current ZeroSSL order ID of a zerossl_api certificate; empty = no order yet.",
      "type": "string",
      "x-description-zh": "zerossl_api 证书当前的 ZeroSSL 订单号;空 = 还没下单。"
     },
     "zerossl_order_state": {
      "description": "ZeroSSL order status (draft, pending_validation, issued, cancelled, etc.); empty = no order yet.",
      "type": "string",
      "x-description-zh": "ZeroSSL 订单状态(draft、pending_validation、issued、cancelled 等);空 = 还没下单。"
     }
    },
    "type": "object"
   },
   "cname-domains": {
    "properties": {
     "actual": {
      "description": "What it actually resolves to (CNAME target or IP); on lookup failure, the reason (NXDOMAIN, Timeout, ...).",
      "type": "string",
      "x-description-zh": "实际解析到的(CNAME 目标或 IP);查询失败时为原因(NXDOMAIN、Timeout…)。"
     },
     "changed": {
      "description": "Number of rows now switched.",
      "type": "integer",
      "x-description-zh": "重查后已改的行数。"
     },
     "check_rows": {
      "description": "Number of check rows created (one per site domain).",
      "type": "integer",
      "x-description-zh": "新建的核对行数(每个网站域名一行)。"
     },
     "checked": {
      "description": "Number of rows rechecked.",
      "type": "integer",
      "x-description-zh": "本次重查的行数。"
     },
     "checked_at": {
      "description": "Time of the last resolution check.",
      "type": "string",
      "x-description-zh": "最近一次解析检查时间。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "dns_provider_id": {
      "description": "ID of the provider account hosting this root domain.",
      "type": "integer",
      "x-description-zh": "托管该根域的服务商账号 id。"
     },
     "domain": {
      "description": "Lowercase root domain, such as cdn.example.com.",
      "type": "string",
      "x-description-zh": "小写根域,如 cdn.example.com。"
     },
     "example_hostname": {
      "description": "An existing access name (without the root domain), used by the wizard to build old and new access address examples.",
      "type": "string",
      "x-description-zh": "一个现有接入名(不含根域),向导里拼新旧接入地址示例用。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
      "type": "string",
      "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
     },
     "expire_at": {
      "description": "Expiry date entered by the admin, YYYY-MM-DD; the admin is reminded 30, 7 and 1 days before expiry and once after it.",
      "type": "string",
      "x-description-zh": "管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。"
     },
     "failed": {
      "description": "Number of rows whose lookup failed.",
      "type": "integer",
      "x-description-zh": "查询失败的行数。"
     },
     "from": {
      "description": "Source root domain.",
      "type": "string",
      "x-description-zh": "原根域。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "IDs of the access domains to update.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要设置状态的接入域名 id 列表。"
     },
     "messaged": {
      "description": "Number of customers who received an in-app message.",
      "type": "integer",
      "x-description-zh": "发了站内信的客户数。"
     },
     "new_target": {
      "description": "CNAME target after the switch.",
      "type": "string",
      "x-description-zh": "切换后的 CNAME 目标。"
     },
     "not_cname": {
      "description": "Number of rows not using a CNAME.",
      "type": "integer",
      "x-description-zh": "非 CNAME 接入的行数。"
     },
     "notified_at": {
      "description": "Time the customer was notified.",
      "type": "string",
      "x-description-zh": "通知客户的时间。"
     },
     "notify": {
      "default": true,
      "description": "Whether to send in-app messages to the affected customers.",
      "type": "boolean",
      "x-description-zh": "是否给受影响客户发站内信。"
     },
     "old_target": {
      "description": "CNAME target before the switch.",
      "type": "string",
      "x-description-zh": "切换前的 CNAME 目标。"
     },
     "package": {
      "description": "Number of package access names switched.",
      "type": "integer",
      "x-description-zh": "切走的套餐接入名数。"
     },
     "package_list": {
      "description": "First 20 purchased packages referencing this root domain.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "前 20 个引用本根域的用户套餐。"
     },
     "provider_name": {
      "description": "Name of the owning account.",
      "type": "string",
      "x-description-zh": "归属账号名称。"
     },
     "provider_type": {
      "description": "Provider type of the owning account.",
      "type": "string",
      "x-description-zh": "归属账号的服务商类型。"
     },
     "remark": {
      "description": "Remark",
      "type": "string",
      "x-description-zh": "备注"
     },
     "retire": {
      "default": true,
      "description": "Whether to set the old domain to retiring.",
      "type": "boolean",
      "x-description-zh": "是否把旧域名置为停用中。"
     },
     "site": {
      "description": "Number of site access names switched.",
      "type": "integer",
      "x-description-zh": "切走的站点接入名数。"
     },
     "site_id": {
      "description": "Site ID",
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "site_list": {
      "description": "List of site access names switched.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "切走的站点接入名清单。"
     },
     "skipped": {
      "description": "Skipped access domains with reasons.",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "被跳过的接入域名及原因。"
     },
     "state": {
      "description": "changed: already switched; unchanged: not switched yet; not_cname: not a CNAME access (points elsewhere or only has an A record); failed: lookup failed; pending: waiting to be checked.",
      "enum": [
       "changed",
       "unchanged",
       "not_cname",
       "failed",
       "pending"
      ],
      "type": "object",
      "x-description-zh": "changed 已改;unchanged 未改;not_cname 非 CNAME 接入(指向别处或只有 A 记录);failed 查询失败;pending 待核对。",
      "x-gocdn-type": "CnameSwitchState"
     },
     "status": {
      "description": "active: in use; retiring: being retired (migrated away, no longer offered when choosing a package domain).",
      "enum": [
       "active",
       "retiring"
      ],
      "type": "object",
      "x-description-zh": "active 使用中;retiring 停用中(已更换走,不再给套餐选)。",
      "x-gocdn-type": "CnameDomainStatus"
     },
     "stream": {
      "description": "Number of TCP/UDP forwarding access names switched.",
      "type": "integer",
      "x-description-zh": "切走的四层转发接入名数。"
     },
     "stream_list": {
      "description": "First 20 TCP/UDP forwardings (id:\u003cid\u003e \u003caccess name\u003e).",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "前 20 个四层转发(id:\u003cid\u003e \u003c接入名\u003e)。"
     },
     "switched_at": {
      "description": "Time of the migration; empty if not migrated.",
      "type": "string",
      "x-description-zh": "整体更换发生的时间;未更换为空。"
     },
     "switched_to": {
      "description": "ID of the root domain it was migrated to.",
      "type": "integer",
      "x-description-zh": "整体更换到的根域 id。"
     },
     "switched_to_domain": {
      "description": "Name of the root domain it was migrated to; empty if not migrated.",
      "type": "string",
      "x-description-zh": "更换到的根域名称;未更换为空。"
     },
     "target_id": {
      "description": "ID of the target root domain.",
      "type": "integer",
      "x-description-zh": "目标根域 id。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "to": {
      "description": "Target root domain.",
      "type": "string",
      "x-description-zh": "目标根域。"
     },
     "unchanged": {
      "description": "Number of rows still not switched.",
      "type": "integer",
      "x-description-zh": "仍未改的行数。"
     },
     "updated": {
      "description": "Number of domains actually updated.",
      "type": "integer",
      "x-description-zh": "实际更新的个数。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "user_list": {
      "description": "List of affected customers.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "受影响的客户清单。"
     },
     "user_name": {
      "description": "Customer (tenant) name; empty if the tenant was deleted.",
      "type": "string",
      "x-description-zh": "客户(租户)名;租户已删为空。"
     },
     "users": {
      "description": "Number of affected customers (distinct tenants owning the sites).",
      "type": "integer",
      "x-description-zh": "受影响客户数(站点所属租户去重)。"
     }
    },
    "type": "object"
   },
   "dns-apis": {
    "properties": {
     "auth": {
      "description": "Credential key name to mask (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
      "type": "object",
      "x-description-zh": "凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "type": {
      "description": "DNS provider.",
      "type": "string",
      "x-description-zh": "DNS 服务商。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "dns-providers": {
    "properties": {
     "auth_id": {
      "description": "Credential ID (Alibaba Cloud AccessKey ID, DNSPod Token ID or Tencent Cloud SecretId, Cloudflare email; empty when a Cloudflare API Token is used).",
      "type": "string",
      "x-description-zh": "凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。"
     },
     "auth_key": {
      "description": "Credential (AccessKey Secret / Token / SecretKey / API Key); required on create, omitted or empty on update = keep the existing value. Stored encrypted.",
      "type": "string",
      "x-description-zh": "凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。"
     },
     "auth_key_hint": {
      "description": "Last 4 characters of the credential (padded with * in front); the original is never returned.",
      "type": "string",
      "x-description-zh": "凭据末 4 位(前面以 * 补齐),不回原文。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "default_line": {
      "description": "ID of the default line of this provider.",
      "type": "string",
      "x-description-zh": "该服务商默认线路的 id。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
      "type": "string",
      "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
     },
     "gateway": {
      "description": "Self-hosted API gateway address (used by dnsdun only).",
      "type": "string",
      "x-description-zh": "自建 API 网关地址(只有 dnsdun 用)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "DnsLine"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "lines": {
      "description": "Cached line tree from the last fetch (refreshed by GET /dns-providers/{id}/lines); an empty array if never fetched.",
      "items": {
       "type": "object",
       "x-gocdn-type": "DnsLine"
      },
      "type": "array",
      "x-description-zh": "最近一次拉取的线路树缓存(GET /dns-providers/{id}/lines 刷新);未拉取为空数组。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "remark": {
      "description": "Remark",
      "type": "string",
      "x-description-zh": "备注"
     },
     "ttl": {
      "description": "Default TTL (seconds) of records under this account.",
      "type": "integer",
      "x-description-zh": "本账号下记录的默认 TTL(秒)。"
     },
     "type": {
      "description": "Provider type: aliyun, cloudflare, dnspod_cn, dnspod_com, dns_la, dnsdotcom, dnsdun.",
      "type": "string",
      "x-description-zh": "服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "dns-sync": {
    "properties": {},
    "type": "object"
   },
   "global-ip-lists": {
    "properties": {
     "added": {
      "description": "Entries added.",
      "type": "integer",
      "x-description-zh": "新增条数。"
     },
     "applied": {
      "description": "Whether the import was saved (false for dry_run or when blocking issues exist).",
      "type": "boolean",
      "x-description-zh": "是否已保存(dry_run 或有挡导入的问题时为 false)。"
     },
     "black": {
      "description": "IP/CIDR of the unexpired blacklist entries.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "黑名单的 IP/CIDR(未过期的全部条目)。"
     },
     "black_items": {
      "description": "Blacklist entries with expiry, reason and source.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListItem"
      },
      "type": "array",
      "x-description-zh": "黑名单条目(含到期时间、原因、来源)。"
     },
     "dry_run": {
      "default": false,
      "description": "true only checks the file and saves nothing.",
      "type": "boolean",
      "x-description-zh": "true 只预检,不保存。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (use 1970-01-01T00:00:00Z when it was null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "issues": {
      "description": "Per-line issues (at most 1000, ascending by line).",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListImportIssue"
      },
      "type": "array",
      "x-description-zh": "逐行问题(最多 1000 条,按行号升序)。"
     },
     "lines": {
      "description": "Number of valid entries (after de-duplication).",
      "type": "integer",
      "x-description-zh": "有效条目数(去重后)。"
     },
     "list": {
      "description": "Which list to import into.",
      "enum": [
       "black",
       "white"
      ],
      "type": "string",
      "x-description-zh": "导入到哪张名单。"
     },
     "mode": {
      "default": "merge",
      "description": "merge adds to the current list (the imported row wins for the same IP); replace swaps the whole list for the imported rows.",
      "enum": [
       "merge",
       "replace"
      ],
      "type": "string",
      "x-description-zh": "merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。"
     },
     "removed": {
      "description": "In replace mode, existing entries that are not in the new list (entries with the same IP count as updated, not removed).",
      "type": "integer",
      "x-description-zh": "replace 模式下原有、新名单里没有的条数(同 IP 的算「更新」,不算在内)。"
     },
     "text": {
      "description": "File content (txt/csv), one entry per line: IP/CIDR[,expiry][,reason].",
      "type": "string",
      "x-description-zh": "文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。"
     },
     "updated": {
      "description": "Entries already in the list that were updated by the import.",
      "type": "integer",
      "x-description-zh": "已在名单里、被导入行更新的条数。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "white": {
      "description": "IP/CIDR of the unexpired whitelist entries.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "白名单的 IP/CIDR(未过期的全部条目)。"
     },
     "white_items": {
      "description": "Whitelist entries with expiry, reason and source.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListItem"
      },
      "type": "array",
      "x-description-zh": "白名单条目(含到期时间、原因、来源)。"
     }
    },
    "type": "object"
   },
   "intel": {
    "properties": {
     "action": {
      "description": "Handling: challenge (pass only after a JS check), block (ban on the site and answer 403), log (record only).",
      "enum": [
       "challenge",
       "block",
       "log"
      ],
      "type": "object",
      "x-description-zh": "处置方式:challenge 验证(JS 验证通过才放行);block 拦截(封本站并回 403);log 观察(只记录)。",
      "x-gocdn-type": "IntelAction"
     },
     "actions": {
      "description": "Handling applied to it today.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IntelAction"
      },
      "type": "array",
      "x-description-zh": "今日对它用过的处置方式。"
     },
     "added_at": {
      "description": "When the entry was added (kept when the same IP is written again).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "加入名单的时间(同一 IP 再次写入时保持原值)。"
     },
     "cidr": {
      "description": "Address or network (canonical form).",
      "type": "string",
      "x-description-zh": "地址或网段(规范写法)。"
     },
     "count": {
      "description": "Number of entries.",
      "type": "integer",
      "x-description-zh": "条目数。"
     },
     "entry": {
      "description": "One entry of the high-risk IP library.",
      "type": "object",
      "x-description-zh": "高危 IP 库里一条。",
      "x-gocdn-type": "IntelEntry"
     },
     "error": {
      "description": "Why the latest sync failed (the version in use is kept); empty on success.",
      "type": "string",
      "x-description-zh": "最近一次同步失败的原因(在用的一版保留);成功为空串。"
     },
     "expires_at": {
      "description": "Expiry time; empty = permanent. An expired entry stops matching by itself (nodes judge by their own clock, independent of the master); the master then removes it and the next config push carries the removal. Must be in the future when written.",
      "type": "string",
      "x-description-zh": "到期时间;空 = 永久。到期后自动失效(节点按本机时钟判,不依赖主控),主控随后清理并随下次配置下发。写入时须晚于当前时刻。"
     },
     "first_seen_at": {
      "description": "When it first entered the library; absent when the library does not say.",
      "type": "string",
      "x-description-zh": "首次入库的时刻;库没给时不返回。"
     },
     "generated_at": {
      "description": "When the library was generated (on the super admin side).",
      "type": "string",
      "x-description-zh": "库的生成时刻(超管侧)。"
     },
     "halt": {
      "description": "Why updates are halted by the license (expired, disabled, or the super admin unreachable for long) (admins only; not a failure, separate from error; absent when not halted).",
      "type": "string",
      "x-description-zh": "授权已过期、停用或超管长时间不可达而停止更新的原因(只给管理员;不是故障,与 error 分开;没有停更时不出现)。"
     },
     "high": {
      "description": "Number of high-risk entries.",
      "type": "integer",
      "x-description-zh": "高危条目数。"
     },
     "hits": {
      "description": "Hits today.",
      "type": "integer",
      "x-description-zh": "今日命中次数。"
     },
     "ip": {
      "description": "Address or network.",
      "type": "string",
      "x-description-zh": "地址或网段。"
     },
     "last_at": {
      "description": "Time of the latest hit.",
      "type": "string",
      "x-description-zh": "最近一次命中时刻。"
     },
     "level": {
      "description": "Level: high (exploit type or score \u003e= 80); medium.",
      "enum": [
       "high",
       "medium"
      ],
      "type": "object",
      "x-description-zh": "等级:high 高危(漏洞利用类或分数 ≥ 80);medium 中危。",
      "x-gocdn-type": "IntelLevel"
     },
     "masters": {
      "description": "Number of controllers that reported it within 24 hours; absent when the library does not say.",
      "type": "integer",
      "x-description-zh": "24 小时内报告该条的主控数;库没给时不返回。"
     },
     "medium": {
      "description": "Number of medium-risk entries.",
      "type": "integer",
      "x-description-zh": "中危条目数。"
     },
     "policy": {
      "description": "Platform-wide policy of the high-risk IP library; the site config field intel.action can override or turn it off.",
      "example": {
       "action": "challenge",
       "level": "high"
      },
      "type": "object",
      "x-description-zh": "高危 IP 库全局处置策略;站点配置 intel.action 可单独改或关闭。",
      "x-gocdn-type": "IntelPolicy"
     },
     "reason": {
      "description": "Why it is whitelisted (kept on the whitelist entry); defaults to a fixed note when omitted.",
      "type": "string",
      "x-description-zh": "加白原因(记在白名单条目上);不带记「高危 IP 库加白」。"
     },
     "reported_at": {
      "description": "When it was last reported.",
      "type": "string",
      "x-description-zh": "最近一次被报告的时刻。"
     },
     "score": {
      "description": "Risk score (1-100).",
      "type": "integer",
      "x-description-zh": "风险分(1–100)。"
     },
     "serving": {
      "description": "Whether a library is being pushed to nodes (fetched at least once and not expired).",
      "type": "boolean",
      "x-description-zh": "是否在向节点下发(拉成过且没过期)。"
     },
     "sites": {
      "description": "Number of sites involved.",
      "type": "integer",
      "x-description-zh": "涉及网站数。"
     },
     "source": {
      "description": "Where the entry came from: manual (added by hand), import (bulk import), ip_detail (blacklisted/whitelisted from the IP detail page), api (written through the API).",
      "enum": [
       "manual",
       "import",
       "ip_detail",
       "api"
      ],
      "type": "object",
      "x-description-zh": "条目来源:manual 手工添加;import 批量导入;ip_detail 在 IP 详情里拉黑/加白;api 经接口写入。",
      "x-gocdn-type": "IpListSource"
     },
     "stale": {
      "description": "The license no longer carries the library and the last version is over 24 hours old, so it is no longer served.",
      "type": "boolean",
      "x-description-zh": "授权不再带库(停更)且最后一版已过 24 小时,不再下发。"
     },
     "sub": {
      "description": "Sub-type (for example WAF consecutive hits); absent when the library does not say.",
      "type": "string",
      "x-description-zh": "子类(如 WAF 连续命中);库没给时不返回。"
     },
     "synced_at": {
      "description": "Time of the latest sync.",
      "type": "string",
      "x-description-zh": "最近一次同步时刻。"
     },
     "version": {
      "description": "Version of the library being served; empty if none.",
      "type": "string",
      "x-description-zh": "在下发的库版本;没有为空串。"
     }
    },
    "type": "object"
   },
   "intel-reports": {
    "properties": {
     "created_at": {
      "description": "Batch time.",
      "type": "string",
      "x-description-zh": "批次时间。"
     },
     "error": {
      "description": "Failure reason; empty on success. Consecutive failures keep only the latest.",
      "type": "string",
      "x-description-zh": "失败原因;成功为空串。连续失败时只保留最近一次。"
     },
     "id": {
      "description": "Record ID",
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "items": {
      "description": "Number of items in the batch.",
      "type": "integer",
      "x-description-zh": "本批条数。"
     },
     "result": {
      "description": "Result - ok delivered; failed not delivered (items stay queued for the next round).",
      "enum": [
       "ok",
       "failed"
      ],
      "type": "string",
      "x-description-zh": "结果:ok 已送达;failed 没送达(条目留队列下轮补报)。"
     },
     "type": {
      "description": "Intelligence type - risky IP / upload hit / false positive marked by an admin / newly seen file fingerprint / suspicious request samples.",
      "enum": [
       "ip",
       "upload_hit",
       "false_positive",
       "sha256_report",
       "samples"
      ],
      "type": "object",
      "x-description-zh": "情报类型:高危 IP / 上传命中 / 管理员标的误报 / 新出现的文件指纹 / 可疑请求样本。",
      "x-gocdn-type": "IntelReportType"
     }
    },
    "type": "object"
   },
   "ip-pools": {
    "properties": {
     "bind_addr": {
      "description": "The local address the node actually listens on (NAT setups); null means use ip.",
      "type": "string",
      "x-description-zh": "节点上实际监听的本机地址(NAT 场景);null = 用 ip。"
     },
     "cert": {
      "description": "Platform IP certificate status.",
      "type": "object",
      "x-description-zh": "平台 IP 证书状态。",
      "x-gocdn-type": "IpCertState"
     },
     "confirm": {
      "description": "Confirm re-issuing when a valid certificate already exists.",
      "type": "boolean",
      "x-description-zh": "已有有效证书时确认重签。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "hints": {
      "description": "Hints (e.g. the node reported no NIC addresses, so the pool entry was not verified).",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "提示(如节点没上报网卡地址,入池未核对)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ip": {
      "description": "IP address.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "IP 地址。"
     },
     "ip_count": {
      "description": "Number of IPs in the pool.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "池内 IP 数。"
     },
     "ips": {
      "description": "Pool IPs that have references, with their referencing sites.",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "有引用的池内 IP 及其引用站点。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpCandidate"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_id": {
      "description": "Node ID",
      "type": "integer",
      "x-description-zh": "节点 ID"
     },
     "node_name": {
      "description": "Name of the node that owns the IP.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "所属节点名称。"
     },
     "node_state": {
      "description": "State of the owning primary node: disabled if the node is disabled; otherwise online if a heartbeat arrived in the last 2 minutes, else offline.",
      "enum": [
       "online",
       "offline",
       "disabled"
      ],
      "type": "object",
      "x-description-zh": "持有主节点状态:停用 disabled;否则最近 2 分钟有心跳 online,没有 offline。",
      "x-gocdn-type": "IpNodeState"
     },
     "pool_id": {
      "description": "ID of the IP pool it belongs to.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属 IP 池 ID。"
     },
     "region_id": {
      "description": "Region ID",
      "type": "integer",
      "x-description-zh": "区域 ID"
     },
     "region_name": {
      "description": "Region name.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "区域名称。"
     },
     "site_count": {
      "description": "Number of IP sites referencing IPs in the pool (deduplicated by site).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "引用池内 IP 的 IP 站点数(按站点去重)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "ip-sites": {
    "properties": {
     "access_addrs": {
      "description": "Access address in ip:port form.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "访问地址 ip:端口。"
     },
     "config": {
      "description": "Node configuration fields (same as the site config; kind is always ip, and listen_addrs is derived from the bindings at publish time).",
      "type": "object",
      "x-description-zh": "节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "hints": {
      "description": "Hints (e.g. the node reported no listening ports, so that check was skipped).",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "提示(如节点没上报在听端口,跳过了该项检查)。"
     },
     "http_ports": {
      "description": "HTTP ports to check; ports outside 1-65535 are not rejected but reported as range.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要检查的 HTTP 端口列表;超出 1~65535 的不拒,结果里标 range。"
     },
     "https_ports": {
      "description": "HTTPS ports to check; ports outside 1-65535 are not rejected but reported as range.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要检查的 HTTPS 端口列表;超出 1~65535 的不拒,结果里标 range。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ip_ids": {
      "description": "IDs of the bound pool IPs, in order.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "绑定的池内 IP id(按次序)。"
     },
     "ips": {
      "description": "Details of the bound pool IPs.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpSiteIp"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "绑定的池内 IP 详情。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "AvailableIp"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "origins": {
      "description": "Origin servers.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpSiteOrigin"
      },
      "type": "array",
      "x-description-zh": "源站列表。"
     },
     "ports": {
      "description": "Per-port check results.",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "逐端口检查结果。"
     },
     "site_id": {
      "description": "Pass when editing a site: ports held by this site itself are not counted as occupied.",
      "type": "integer",
      "x-description-zh": "改站时给:本站自己占的不算占用。"
     },
     "stop_code": {
      "description": "0 = normal; non-zero = every request returns this status code (set by admins or billing).",
      "type": "integer",
      "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "upid": {
      "description": "User package ID.",
      "type": "integer",
      "x-description-zh": "用户套餐 id。"
     }
    },
    "type": "object"
   },
   "l2": {
    "properties": {
     "access_addr": {
      "description": "Private address edges use to reach it (IP only, no port; IPv4-mapped IPv6 is stored as IPv4); empty means the public IP.",
      "type": "string",
      "x-description-zh": "边缘访问它的内网地址(只收 IP,不带端口;IPv4 映射的 IPv6 存成 IPv4);空 = 公网 IP。"
     },
     "all_regions": {
      "description": "Serve all regions (requires cross_region).",
      "type": "boolean",
      "x-description-zh": "服务全部区域(须勾跨区域)。"
     },
     "allow": {
      "description": "Origin allowlisting: empty if not applicable, pending (cacheable requests only), or allowed.",
      "type": "string",
      "x-description-zh": "源站放行:空 = 不涉及(没有网站只允许 L2),pending 待放行(只接可缓存请求),allowed 已放行。"
     },
     "allow_since": {
      "description": "Pending since; turns allowed after 24 hours.",
      "type": "string",
      "x-description-zh": "进入待放行的时刻;满 24 小时自动转已放行。"
     },
     "apply_sites": {
      "description": "Also enable on existing sites (only those never set; sites turned off manually, or whose tenant package does not include tiered origin, stay unchanged).",
      "type": "boolean",
      "x-description-zh": "给现有网站也开(只动从没设过的网站,手动关过的、所属租户套餐不含分层回源的不动)。"
     },
     "auto_resume_at": {
      "description": "Automatic resume time (must be in the future); omit for manual resume.",
      "type": "string",
      "x-description-zh": "自动恢复时刻(须在现在之后);不给 = 手动恢复。"
     },
     "balance": {
      "description": "Distribution: url_hash pins by URL, rr round-robin.",
      "enum": [
       "url_hash",
       "rr"
      ],
      "type": "string",
      "x-description-zh": "分配方式:url_hash 按网址固定,rr 轮流。"
     },
     "checked_at": {
      "description": "Checked at.",
      "type": "string",
      "x-description-zh": "检测时刻。"
     },
     "created_at": {
      "description": "Started at.",
      "type": "string",
      "x-description-zh": "开始时间。"
     },
     "cross_region": {
      "description": "Allow cross-region use (required for nodes outside the regions or all regions; adds about 50-200 ms).",
      "type": "boolean",
      "x-description-zh": "允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。"
     },
     "defaults": {
      "description": "Defaults (change via PUT /configs/l2.defaults).",
      "type": "object",
      "x-description-zh": "默认设置(改用 PUT /configs/l2.defaults)。",
      "x-gocdn-type": "L2Defaults"
     },
     "disabled_at": {
      "description": "Disabled at.",
      "type": "string",
      "x-description-zh": "停用时刻。"
     },
     "disabled_reason": {
      "description": "Reason for disabling.",
      "type": "string",
      "x-description-zh": "停用原因。"
     },
     "edge_origin_requests": {
      "description": "Edge origin requests (hit rate denominator).",
      "type": "integer",
      "x-description-zh": "边缘回源请求数(命中率分母)。"
     },
     "empty_group": {
      "description": "Groups left without a serving L2 (their sites will bypass temporarily).",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "去掉它后没有可用 L2 的组(用这些组的网站将暂时绕过)。"
     },
     "enabled": {
      "description": "Enabled; a disabled node stays L2 and keeps its cache.",
      "type": "boolean",
      "x-description-zh": "启用;停用时仍是 L2、缓存保留。"
     },
     "feature": {
      "description": "Paid feature l2 level: on; limited when frozen, being revoked, or in the fallback window after the license lapses (still pushed, management only; see GET /l2/revoke-impact); off when not licensed (not pushed).",
      "enum": [
       "on",
       "limited",
       "off"
      ],
      "type": "string",
      "x-description-zh": "付费功能 l2 开通档:on 开通;limited 冻结、即将停用或授权失效后的回落窗口(照常下发,只能停用、暂停等,见 GET /l2/revoke-impact);off 没开通(不下发)。"
     },
     "finished_at": {
      "description": "Finished at.",
      "type": "string",
      "x-description-zh": "结束时间。"
     },
     "groups": {
      "description": "IDs of L2 groups containing it.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "所在 L2 组 id。"
     },
     "hit_rate": {
      "description": "Hit rate 0-1; 0 when there were no origin requests.",
      "type": "number",
      "x-description-zh": "命中率 0–1;没有回源为 0。"
     },
     "host": {
      "description": "Primary domain of the site.",
      "type": "string",
      "x-description-zh": "网站主域名。"
     },
     "id": {
      "description": "Group ID.",
      "type": "integer",
      "x-description-zh": "组 id。"
     },
     "ip": {
      "description": "Public IP.",
      "type": "string",
      "x-description-zh": "公网 IP。"
     },
     "is_region_default": {
      "description": "Region default group (one per region; cannot be deleted, only its distribution can change).",
      "type": "boolean",
      "x-description-zh": "区域默认组(每区域一个,不能删,只能改分配方式)。"
     },
     "items": {
      "description": "L2 groups.",
      "items": {
       "type": "object",
       "x-gocdn-type": "L2Group"
      },
      "type": "array",
      "x-description-zh": "L2 组。"
     },
     "kind": {
      "description": "Task kind: enable adds L2, revert returns to edge.",
      "enum": [
       "enable",
       "revert"
      ],
      "type": "string",
      "x-description-zh": "任务种类:enable 加 L2,revert 改回边缘。"
     },
     "l2_group_id": {
      "description": "L2 group chosen by the site; null means region default.",
      "type": "integer",
      "x-description-zh": "网站选的 L2 组;null = 区域默认。"
     },
     "l2_group_name": {
      "description": "L2 group name; empty for region default.",
      "type": "string",
      "x-description-zh": "L2 组名;区域默认时为空串。"
     },
     "l2_hit_requests": {
      "description": "Origin requests served by L2 (hit rate numerator).",
      "type": "integer",
      "x-description-zh": "L2 接住的回源请求数(命中率分子)。"
     },
     "l2_pick": {
      "description": "Effective L2 pick method (site value, else the default): region or near.",
      "enum": [
       "region",
       "near"
      ],
      "type": "string",
      "x-description-zh": "网站生效的选 L2 方式(网站单独设的,否则默认设置):region 跟边缘同区域;near 离源站最近。"
     },
     "low_hit": {
      "description": "Hit rate below 30% with at least 1000 origin requests (mostly dynamic content; consider turning L2 off).",
      "type": "boolean",
      "x-description-zh": "命中率低于 30% 且源站请求不少于 1000 次(动态内容多,建议关)。"
     },
     "manual_off_sites": {
      "description": "Sites whose tiered origin was turned off manually (left alone when enabling on existing sites; IP sites excluded).",
      "type": "integer",
      "x-description-zh": "手动关过分层回源的网站数(一键启用勾「给现有网站也开」时不动它们;IP 站不计)。"
     },
     "name": {
      "description": "Group name, unique platform-wide.",
      "type": "string",
      "x-description-zh": "组名,全平台唯一。"
     },
     "node_id": {
      "description": "Node ID.",
      "type": "integer",
      "x-description-zh": "节点 id。"
     },
     "node_ids": {
      "description": "Edge node IDs to turn into L2.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要改做 L2 的边缘节点 id。"
     },
     "nodes_pending": {
      "description": "L2 nodes awaiting origin allowlisting.",
      "type": "integer",
      "x-description-zh": "待放行的 L2 数。"
     },
     "nodes_serving": {
      "description": "L2 nodes serving (enabled and not reverting).",
      "type": "integer",
      "x-description-zh": "在接回源的 L2 数(启用且没在改回)。"
     },
     "nodes_total": {
      "description": "Total L2 nodes (including disabled and reverting).",
      "type": "integer",
      "x-description-zh": "L2 节点总数(含停用、改回中)。"
     },
     "online": {
      "description": "Online (heartbeat within 2 minutes).",
      "type": "boolean",
      "x-description-zh": "在线(最近 2 分钟有心跳)。"
     },
     "only_block": {
      "description": "Some sites allow only L2 at the origin (revoke its allowlisting after revert).",
      "type": "boolean",
      "x-description-zh": "有网站开了「源站只允许 L2 访问」(改回后源站要撤掉它的放行)。"
     },
     "only_block_sites": {
      "description": "Sites with origin allowing only L2 (greater than 0 when only_block is true).",
      "type": "integer",
      "x-description-zh": "开了「源站只允许 L2 访问」的网站数(only_block 为真时大于 0)。"
     },
     "origin_l2_only": {
      "description": "Origin allows only L2; after the window ends the site goes down unless the origin allows edge nodes.",
      "type": "boolean",
      "x-description-zh": "开了「源站只允许 L2 访问」:回落窗口满后源站没放行边缘节点就会整站不可用。"
     },
     "origin_requests": {
      "description": "Requests that reached the origin.",
      "type": "integer",
      "x-description-zh": "实际到源站的请求数。"
     },
     "origin_requests_est": {
      "description": "Estimate without tiering (= edge origin requests).",
      "type": "integer",
      "x-description-zh": "未开分层时的估算(= 边缘回源请求数)。"
     },
     "owner_id": {
      "description": "Owner user ID.",
      "type": "integer",
      "x-description-zh": "所属用户 ID。"
     },
     "owner_name": {
      "description": "Owner username.",
      "type": "string",
      "x-description-zh": "所属用户名。"
     },
     "paused": {
      "description": "Paused network-wide.",
      "type": "boolean",
      "x-description-zh": "全网暂停中。"
     },
     "paused_at": {
      "description": "Paused at.",
      "type": "string",
      "x-description-zh": "暂停时刻。"
     },
     "progress": {
      "description": "Progress 0-100.",
      "type": "integer",
      "x-description-zh": "进度 0–100。"
     },
     "reason": {
      "description": "Reason for disabling.",
      "type": "string",
      "x-description-zh": "停用原因。"
     },
     "region_id": {
      "description": "Region of a region default group; 0 for custom groups.",
      "type": "integer",
      "x-description-zh": "区域默认组所属区域;自建组 0。"
     },
     "region_last": {
      "description": "It is the last enabled L2 in its region.",
      "type": "boolean",
      "x-description-zh": "它是本区域最后一台启用中的 L2。"
     },
     "regions": {
      "description": "Served region IDs; ignored when all_regions is true.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "服务区域 id;all_regions 为真时忽略。"
     },
     "revert_at": {
      "description": "Revert started at.",
      "type": "string",
      "x-description-zh": "开始改回的时刻。"
     },
     "role": {
      "description": "Primary or backup: backups stand by while a primary in the same group is up.",
      "enum": [
       "primary",
       "backup"
      ],
      "type": "string",
      "x-description-zh": "主备:同组有主可用时备只待命,主全挂才用备(在组内成员间比较)。"
     },
     "rules": {
      "description": "Group rules (saved with the group).",
      "items": {
       "type": "object",
       "x-gocdn-type": "L2Rule"
      },
      "type": "array",
      "x-description-zh": "组内规则(随组保存)。"
     },
     "saved_bytes": {
      "description": "Origin traffic saved (bytes served from L2 cache).",
      "type": "integer",
      "x-description-zh": "省的回源流量(L2 命中字节)。"
     },
     "site_id": {
      "description": "Site ID.",
      "type": "integer",
      "x-description-zh": "网站 ID。"
     },
     "sites": {
      "description": "Number of sites using this group; for a region default group, the sites with L2 enabled and no group chosen (same number for every region default group).",
      "type": "integer",
      "x-description-zh": "用这个组的网站数;区域默认组为开着 L2 且没指定组的网站数(各区域默认组同数)。"
     },
     "sites_only_l2": {
      "description": "Sites with origin allowing only L2 (shown in the pause and add-node warnings).",
      "type": "integer",
      "x-description-zh": "开了「源站只允许 L2 访问」的网站数(暂停、新加节点时写进提醒)。"
     },
     "state": {
      "description": "State: active, or reverting to edge.",
      "enum": [
       "active",
       "reverting"
      ],
      "type": "string",
      "x-description-zh": "状态:active 正常,reverting 改回边缘中。"
     },
     "thresholds": {
      "description": "Detection thresholds (read-only).",
      "type": "object",
      "x-description-zh": "判定阈值(只读)。",
      "x-gocdn-type": "L2Thresholds"
     },
     "updated_at": {
      "description": "Last modified time.",
      "type": "string",
      "x-description-zh": "最后修改时间。"
     },
     "weight": {
      "description": "Weight 1-100; multiple primaries share URLs by weight.",
      "type": "integer",
      "x-description-zh": "权重 1–100,多台主按权重分网址。"
     }
    },
    "type": "object"
   },
   "ledger-entries": {
    "properties": {
     "amount_cents": {
      "description": "Signed: positive for credit, negative for debit.",
      "type": "integer",
      "x-description-zh": "带符号:正为入账,负为扣款。"
     },
     "balance_after_cents": {
      "description": "Balance snapshot after this entry.",
      "type": "integer",
      "x-description-zh": "记这一笔后的余额快照。"
     },
     "created_at": {
      "description": "Created at",
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "kind": {
      "description": "Entry kind, such as recharge or deduction.",
      "type": "string",
      "x-description-zh": "流水类型,如充值、扣款。"
     },
     "order_id": {
      "description": "Related order ID; empty if none.",
      "type": "integer",
      "x-description-zh": "关联订单 ID;没有为空。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     }
    },
    "type": "object"
   },
   "lines": {
    "properties": {
     "backup_default_on": {
      "description": "Whether this backup default line is currently in effect and resolved on the default line (read-only, maintained by the scheduled job).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "备用默认解析当前已启用、正按默认线路解析(只读,由定时任务维护)。"
     },
     "backup_on": {
      "description": "Whether this backup IP is currently in DNS (read-only, maintained by the scheduled job).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "备用 IP 当前已启用进解析(只读,由定时任务维护)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "disable_by": {
      "description": "Disable source (manual by admin, monitor by node monitoring, bandwidth for bandwidth limit, etc.); empty when enabled.",
      "type": "string",
      "x-description-zh": "停用来源(manual 管理员手工、monitor 节点监控、bandwidth 带宽超限等);启用时为空。"
     },
     "dns_line": {
      "description": "DNS resolution line code (default = default line; carrier/region line codes are mapped by the DNS domain).",
      "type": "string",
      "x-description-zh": "DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "force": {
      "description": "Force the write and skip two safeguards (requires a second confirmation): when the line becomes an enabled primary line, its node must have applied its configuration and be at most one release behind (otherwise 422 node_config_behind); disabling the last enabled primary line of the node group or making it a backup (otherwise 422 last_primary_line).",
      "type": "boolean",
      "x-description-zh": "强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "is_backup": {
      "description": "Backup IP; kept out of DNS normally and brought in or taken out automatically according to the node group's backup IP switch mode.",
      "type": "boolean",
      "x-description-zh": "备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。"
     },
     "is_backup_default": {
      "description": "Backup default line; when the node group has no default line in use, this line is automatically resolved on the default line instead, and switched back once one is in use again.",
      "type": "boolean",
      "x-description-zh": "备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。"
     },
     "node_group_id": {
      "description": "ID of the node group this line belongs to.",
      "type": "integer",
      "x-description-zh": "所属节点组的 id。"
     },
     "node_id": {
      "description": "Node ID",
      "type": "integer",
      "x-description-zh": "节点 ID"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "weight": {
      "description": "Weight, 1 to 100; a larger weight receives a larger share of resolutions.",
      "type": "integer",
      "x-description-zh": "权重,1 到 100,越大分到的解析越多。"
     }
    },
    "type": "object"
   },
   "login-policy": {
    "properties": {
     "email": {
      "description": "Masked email",
      "type": "string",
      "x-description-zh": "打码后的邮箱。"
     },
     "login_verify": {
      "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
      "enum": [
       "none",
       "email",
       "sms"
      ],
      "type": "object",
      "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
      "x-gocdn-type": "LoginVerify"
     },
     "phone": {
      "description": "Masked phone number",
      "type": "string",
      "x-description-zh": "打码后的手机号。"
     }
    },
    "type": "object"
   },
   "me": {
    "properties": {
     "balance_cents": {
      "description": "Account balance in cents, same as balance_cents of GET /users/{user_id}/account (0 when there is no account). Only present in the GET /users list, not in single-user responses",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。"
     },
     "certified": {
      "description": "Whether real-name verification has passed",
      "type": "boolean",
      "x-description-zh": "是否已通过实名认证。"
     },
     "client_ip": {
      "description": "Source IP of this request, derived the same way as the login IP allowlist check (what the allowlist compares is what is shown). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "delegated_session": {
      "description": "Whether the current session was issued by superadmin sign-in or switch-to-user (if so, password, email, phone, login allowlist, login verification and real-name are read-only). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。"
     },
     "email": {
      "description": "Email",
      "type": "string",
      "x-description-zh": "邮箱"
     },
     "email_code": {
      "description": "Code sent to the new email (POST /verify-codes, purpose=bind); required when changing the email",
      "type": "string",
      "x-description-zh": "发到新邮箱的验证码(POST /verify-codes,purpose=bind);改邮箱时必填。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "id_number": {
      "description": "Masked ID number",
      "type": "string",
      "x-description-zh": "打码后的证件号。"
     },
     "login_ip_allow": {
      "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
     },
     "login_verify": {
      "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
      "enum": [
       "none",
       "email",
       "sms"
      ],
      "type": "object",
      "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
      "x-gocdn-type": "LoginVerify"
     },
     "phone": {
      "description": "Phone number",
      "type": "string",
      "x-description-zh": "手机号"
     },
     "phone_code": {
      "description": "Code sent to the new phone number (POST /verify-codes, purpose=bind); required when changing the phone number",
      "type": "string",
      "x-description-zh": "发到新手机号的验证码(POST /verify-codes,purpose=bind);改手机号时必填。"
     },
     "provider": {
      "description": "Real-name verification provider",
      "type": "string",
      "x-description-zh": "实名认证通道。"
     },
     "real_name": {
      "description": "Masked real name",
      "type": "string",
      "x-description-zh": "打码后的姓名。"
     },
     "reason": {
      "description": "Reason for failure",
      "type": "string",
      "x-description-zh": "未通过的原因。"
     },
     "role": {
      "description": "Account role: admin or tenant",
      "enum": [
       "admin",
       "tenant"
      ],
      "type": "string",
      "x-description-zh": "账号角色:admin 管理员,tenant 租户。"
     },
     "status": {
      "description": "Verification status: none, pending, verified or failed",
      "enum": [
       "none",
       "pending",
       "verified",
       "failed"
      ],
      "type": "string",
      "x-description-zh": "实名状态:none 未认证,pending 待认证,verified 已通过,failed 未通过。"
     },
     "totp_enabled": {
      "description": "Whether TOTP is enabled",
      "type": "boolean",
      "x-description-zh": "是否已启用动态口令。"
     },
     "totp_recovery_left": {
      "description": "Number of unused TOTP recovery codes. Only present in GET /me and PUT /me when TOTP is enabled",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "url": {
      "description": "Verification URL the user must visit while pending (returned only on submission)",
      "type": "string",
      "x-description-zh": "待认证时用户要去的认证地址(仅提交时返回)。"
     },
     "username": {
      "description": "Username",
      "type": "string",
      "x-description-zh": "用户名"
     }
    },
    "type": "object"
   },
   "message-channels": {
    "properties": {
     "channel": {
      "description": "Channel to test (email or sms).",
      "enum": [
       "email",
       "sms"
      ],
      "type": "string",
      "x-description-zh": "要测试的通道(email 邮件、sms 短信)。"
     },
     "draft": {
      "description": "Unsaved channel settings; same shape as the save endpoint, omitted fields and blank secrets fall back to the stored values.",
      "type": "object",
      "x-description-zh": "未保存的通道设置草稿;字段形状同保存接口,没给的字段、留空的密钥沿用已存值。",
      "x-gocdn-type": "ChannelTestDraft"
     },
     "error": {
      "description": "Error message when the test failed.",
      "type": "string",
      "x-description-zh": "失败时的错误信息。"
     },
     "ok": {
      "description": "Whether the test send succeeded.",
      "type": "boolean",
      "x-description-zh": "测试发送是否成功。"
     },
     "sms": {
      "description": "SMS channel settings.",
      "type": "object",
      "x-description-zh": "短信通道配置。",
      "x-gocdn-type": "SmsChannel"
     },
     "smtp": {
      "description": "SMTP email channel settings.",
      "type": "object",
      "x-description-zh": "SMTP 邮件通道配置。",
      "x-gocdn-type": "SmtpChannel"
     },
     "template_id": {
      "description": "An approved template id is required for the Tencent Cloud SMS channel (not needed for SMSBao).",
      "type": "string",
      "x-description-zh": "腾讯云短信须给已审核的模板 id(短信宝不需要)。"
     },
     "to": {
      "description": "Recipient address or phone number.",
      "type": "string",
      "x-description-zh": "收件邮箱或手机号。"
     }
    },
    "type": "object"
   },
   "message-subscriptions": {
    "properties": {
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "SubscriptionItem"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     }
    },
    "type": "object"
   },
   "message-webhooks": {
    "properties": {
     "chat_id": {
      "description": "Telegram chat (numeric id or @channel name).",
      "type": "string",
      "x-description-zh": "Telegram 会话(数字 id 或 @频道名)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "enabled": {
      "description": "Whether it is enabled; disabled ones are skipped. Enabled by default.",
      "type": "boolean",
      "x-description-zh": "是否启用;停用的不发。缺省启用。"
     },
     "error": {
      "description": "Error message when the test failed.",
      "type": "string",
      "x-description-zh": "失败时的错误信息。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "kind": {
      "description": "Kind: dingtalk, feishu, wecom, telegram or generic JSON.",
      "enum": [
       "dingtalk",
       "feishu",
       "wecom",
       "telegram",
       "generic"
      ],
      "type": "string",
      "x-description-zh": "类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。"
     },
     "last4": {
      "description": "Last 4 characters of the address (the token for Telegram), for recognition only.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "地址(Telegram 为 Token)的末 4 位,仅用于辨认。"
     },
     "name": {
      "description": "Name, unique across all webhooks.",
      "type": "string",
      "x-description-zh": "名称,全局唯一。"
     },
     "ok": {
      "description": "Whether the test send succeeded.",
      "type": "boolean",
      "x-description-zh": "测试发送是否成功。"
     },
     "secret": {
      "description": "Bot token for Telegram (required); signing secret for the others (optional). Write-only, never echoed.",
      "type": "string",
      "x-description-zh": "Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "url": {
      "description": "Bot URL (https, public; required for DingTalk, Feishu, WeCom and generic; unused for Telegram). Write-only, never echoed.",
      "type": "string",
      "x-description-zh": "机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。"
     }
    },
    "type": "object"
   },
   "messages": {
    "properties": {
     "content": {
      "description": "Message body.",
      "type": "string",
      "x-description-zh": "消息正文。"
     },
     "count": {
      "description": "Number of unread messages.",
      "type": "integer",
      "x-description-zh": "未读消息数。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "Empty means all messages sent to you.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "为空表示发给自己的全部已读。"
     },
     "is_bold": {
      "description": "Whether to show the title in bold.",
      "type": "boolean",
      "x-description-zh": "标题是否加粗。"
     },
     "is_external": {
      "description": "When true, clicking jumps to url and url is required; otherwise content is required.",
      "type": "boolean",
      "x-description-zh": "为真时点击跳 url,url 必填;否则 content 必填。"
     },
     "is_popup": {
      "description": "Whether to show it as a pop-up.",
      "type": "boolean",
      "x-description-zh": "是否弹窗显示。"
     },
     "is_red": {
      "description": "Whether to show the title in red.",
      "type": "boolean",
      "x-description-zh": "标题是否标红。"
     },
     "is_show": {
      "description": "Whether the message is visible.",
      "type": "boolean",
      "x-description-zh": "是否显示。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "Message"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "read": {
      "description": "Whether the message has been read.",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "是否已读。"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "sort": {
      "description": "Display order (smaller first).",
      "type": "integer",
      "x-description-zh": "排序值(小的在前)。"
     },
     "tenant_id": {
      "description": "Recipient tenant; empty for announcements.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "收件租户;公告为空。"
     },
     "title": {
      "description": "Message title.",
      "type": "string",
      "x-description-zh": "消息标题。"
     },
     "title_args": {
      "description": "Arguments of the title key: name → string, number, or a clause {key, args} (a clause is looked up in the dictionary and filled the same way, and may nest).",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "标题键的参数:名字 → 字符串、数字,或子句 {key, args}(子句同样先查词典再填占位,可嵌套)。"
     },
     "title_key": {
      "description": "Title key (the Chinese sentence with {name} placeholders). When set, the panel looks it up in the UI-language dictionary and fills the placeholders from title_args; when null (old messages, announcements, edited titles) the panel shows title as is.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "标题键(中文原句,{名字} 占位)。有值时面板拿它查界面语言的词典、用 title_args 填占位来显示标题;为空(旧消息、公告、标题被改过)显示 title 原文。"
     },
     "type": {
      "description": "announcement = announcement; others are notification types (such as cert-expire, package-expire).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "announcement = 公告;其余为通知类型(如 cert-expire、package-expire)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "url": {
      "description": "Link opened on click when is_external is true.",
      "type": "string",
      "x-description-zh": "is_external 为真时点击跳转的链接。"
     }
    },
    "type": "object"
   },
   "monitor-logs": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "detail": {
      "description": "Why it was unreachable or undeterminable.",
      "type": "string",
      "x-description-zh": "不通/判不了的原因。"
     },
     "id": {
      "description": "Record ID",
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ip": {
      "description": "Probed IP.",
      "type": "string",
      "x-description-zh": "被探测的 IP。"
     },
     "node_id": {
      "description": "Node ID",
      "type": "integer",
      "x-description-zh": "节点 ID"
     },
     "result": {
      "description": "1: reachable; 0: unreachable; -1: undeterminable (http 5xx, whole round unreachable, etc.; not counted).",
      "enum": [
       -1,
       0,
       1
      ],
      "type": "integer",
      "x-description-zh": "1 通;0 不通;-1 判不了(http 5xx、整轮全不通等,不参与判定)。"
     },
     "round_id": {
      "description": "Probe round (same value within one round).",
      "type": "integer",
      "x-description-zh": "探测轮次(同一轮同值)。"
     },
     "type": {
      "description": "aval: availability probe (by the control plane or the external probe service); bw: bandwidth sample (one per minute, 0 when outbound is at or above the limit).",
      "enum": [
       "aval",
       "bw"
      ],
      "type": "string",
      "x-description-zh": "aval 可用性探测(主控或外部探测服务);bw 带宽采样(每分钟一条,出站不低于上限记 0)。"
     }
    },
    "type": "object"
   },
   "node-enroll-tokens": {
    "properties": {
     "command": {
      "description": "One-line node install command (includes the asset site URL, the control plane URL, the token and the trust root); a short notice if no asset site is configured or the control plane key is not initialized.",
      "type": "string",
      "x-description-zh": "节点一行安装命令;没配物料站或主控钥未初始化时为一句说明。"
     },
     "expires_at": {
      "description": "Expires at",
      "type": "string",
      "x-description-zh": "过期时间"
     },
     "token": {
      "description": "Plain text of the one-time enrollment token; shown only in this response.",
      "type": "string",
      "x-description-zh": "一次性注册令牌原文,只在本次响应里出现。"
     }
    },
    "type": "object"
   },
   "node-groups": {
    "properties": {
     "backup_active": {
      "description": "Automatically switched to the backup group by monitoring (switches back once usable lines recover to the threshold).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "已被监控自动切到备用组(可用线路回到阈值后自动切回)。"
     },
     "backup_interval_s": {
      "description": "Rotation interval in seconds in interval mode.",
      "type": "integer",
      "x-description-zh": "interval 方式的轮换间隔(秒)。"
     },
     "backup_ip_num": {
      "description": "Number of backup IPs in use per rotation in interval mode.",
      "type": "integer",
      "x-description-zh": "interval 方式每轮在用的备用 IP 数。"
     },
     "backup_min_online": {
      "description": "When usable lines in the group drop below this, access names referencing the group are switched to their own backup groups; 0 = never switch automatically, default 1 (switch when none is usable).",
      "type": "integer",
      "x-description-zh": "组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。"
     },
     "backup_switch_order": {
      "description": "Rotation order in interval mode: seq picks the least recently used first; rand picks at random.",
      "enum": [
       "seq",
       "rand"
      ],
      "type": "object",
      "x-description-zh": "interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。",
      "x-gocdn-type": "BackupSwitchOrder"
     },
     "backup_switch_type": {
      "description": "Backup IP switch mode. master_down: bring in as many backup IPs as there are unavailable primary IPs on the same DNS line; gt_online_ip: when online primary IPs are fewer than backup IPs, bring in backups to make up the difference (at most the number of unavailable primary IPs); interval: every IP in the group is a backup and they rotate on a timer (the group must have no primary IPs before switching to interval).",
      "enum": [
       "master_down",
       "gt_online_ip",
       "interval"
      ],
      "type": "object",
      "x-description-zh": "备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。",
      "x-gocdn-type": "BackupSwitchType"
     },
     "backup_switched": {
      "description": "Time of the most recent automatic switch or switch-back.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "最近一次自动切换/切回的时刻。"
     },
     "cname_domains": {
      "description": "Access names (host record.root domain) pointing to this group, in alphabetical order; empty array if none reference it.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "指向本组的接入名(主机记录.根域),按字母序;没有被引用为空数组。"
     },
     "cname_hostname": {
      "description": "Host record part of the access name (for example www); lowercase letters, digits, hyphens, dot-separated labels; unique across groups (409 cname_hostname_taken); empty on create generates 8 random characters, empty on update keeps the current value.",
      "type": "string",
      "x-description-zh": "接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_count": {
      "description": "Number of distinct node IPs referenced by the lines in this group.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "组里线路引用的不同节点 IP 数。"
     },
     "region_id": {
      "description": "Region ID",
      "type": "integer",
      "x-description-zh": "区域 ID"
     },
     "site_count": {
      "description": "Number of sites whose access name points to this group.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "接入名指向本组的网站数。"
     },
     "stream_count": {
      "description": "Number of TCP/UDP forwarding rules whose access name points to this group.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "接入名指向本组的四层转发数。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "nodes": {
    "properties": {
     "area": {
      "description": "Area (display only, never sent to nodes); empty = not set. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。"
     },
     "bandwidth_mbps": {
      "description": "Node bandwidth in Mbps (display only, unrelated to monitor.bw_limit_mbps); 0 = not set. Sub-IPs take the primary node's value.",
      "type": "integer",
      "x-description-zh": "节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。"
     },
     "capacity": {
      "description": "Node memory capacity (read-only, only returned by GET /nodes/{id}?capacity=true): per-site resident cost = locations × 28.1KB + HTTPS ratio × 25.5KB, budget = memory MiB × 0.25 / 2 − 28MiB, limit = budget / per-site cost. null = no system info for the node or memory total missing.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "节点内存容量(只读,只在 GET /nodes/{id}?capacity=true 给出):单站常驻 = location 数 × 28.1KB + https 占比 × 25.5KB,预算 = 内存 MiB × 0.25 / 2 − 28MiB,上限 = 预算 / 单站。null = 没有该节点的系统信息或缺内存总量。",
      "x-gocdn-type": "NodeCapacity"
     },
     "cert_expiry": {
      "description": "Expiry time of the most recently issued certificate; null = no certificate issued yet (or a sub-IP).",
      "type": "string",
      "x-description-zh": "最近一次签发证书的到期时刻;null = 还没领过证(或子 IP)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "disable_by": {
      "description": "Disable source (manual = admin; monitor = auto-disabled by node monitoring and re-enabled once probes recover; bandwidth = auto-disabled when outbound bandwidth exceeds monitor.bw_limit_mbps and re-enabled when it drops back); empty when enabled.",
      "type": "string",
      "x-description-zh": "停用来源(manual = 管理员;monitor = 节点监控自动停用,探测恢复后自动启用;bandwidth = 出站带宽超过 monitor.bw_limit_mbps 自动停用,回落后自动启用);启用时为空。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "enrolled_at": {
      "description": "Time the node enrolled; null for a manually added sub-IP.",
      "type": "string",
      "x-description-zh": "节点注册时刻;手工添加的子 IP 为 null。"
     },
     "hints": {
      "description": "Hints (e.g. NIC addresses could not be obtained).",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "提示(如取不到网卡地址)。"
     },
     "hostname": {
      "description": "Node hostname, reported at enrollment.",
      "type": "string",
      "x-description-zh": "节点主机名,注册时上报。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ip": {
      "description": "Node IP address (IPv4 or IPv6).",
      "type": "string",
      "x-description-zh": "节点 IP 地址(IPv4 或 IPv6)。"
     },
     "monitor": {
      "description": "Node monitor probe settings (the control plane probes this IP at the interval configured in monitor.node).",
      "type": "object",
      "x-description-zh": "节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。",
      "x-gocdn-type": "NodeMonitor"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "ops": {
      "description": "Node operations status (read-only, from heartbeats): online, whether the config lags behind the latest published version, and clock sync. Sub-IPs follow their primary node.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "节点运维状态(只读,来自心跳):在线、配置是否落后于最新已发布版本、时钟是否同步。子 IP 跟随主节点。",
      "x-gocdn-type": "NodeOps"
     },
     "parent_id": {
      "description": "Primary node that owns this sub-IP; null = primary node.",
      "type": "integer",
      "x-description-zh": "子 IP 所属主节点;null = 主节点。"
     },
     "region_id": {
      "description": "Region ID",
      "type": "integer",
      "x-description-zh": "区域 ID"
     },
     "role": {
      "description": "Node role: edge for an edge node, l2 for a second-tier cache node.",
      "enum": [
       "edge",
       "l2"
      ],
      "type": "string",
      "x-description-zh": "节点角色:edge 边缘节点;l2 二级缓存节点。"
     },
     "service_expire": {
      "description": "Server service expiry date YYYY-MM-DD (used for the home-page expiry reminder; never auto-disables); null = not set, no reminder. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。"
     },
     "service_start": {
      "description": "Server service start date YYYY-MM-DD (display only); null = not set. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。"
     },
     "status": {
      "description": "ok = result available; pending = command queued, fetch again later; unknown = node offline.",
      "enum": [
       "ok",
       "pending",
       "unknown"
      ],
      "type": "string",
      "x-description-zh": "ok = 有结果;pending = 已排指令,稍后再取;unknown = 节点不在线。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "v4": {
      "description": "IPv4 addresses on the node's NICs.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "节点网卡上的 IPv4 地址。"
     },
     "v6": {
      "description": "IPv6 addresses on the node's NICs.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "节点网卡上的 IPv6 地址。"
     }
    },
    "type": "object"
   },
   "orders": {
    "properties": {
     "amount_cents": {
      "description": "Amount in cents; negative for deductions.",
      "type": "integer",
      "x-description-zh": "金额(分),扣款单为负。"
     },
     "archived": {
      "description": "Moved into the archive table by the archiving task (read-only).",
      "type": "boolean",
      "x-description-zh": "已被归档任务搬进档案表(只读)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "data": {
      "description": "Extra data (such as package purchase details).",
      "type": "object",
      "x-description-zh": "附加数据(如套餐购买明细)。"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "group_by": {
      "description": "Aggregation granularity: day, month or year.",
      "enum": [
       "day",
       "month",
       "year"
      ],
      "type": "string",
      "x-description-zh": "汇总粒度:day、month 或 year。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "OrderStatsItem"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "ledger_id": {
      "description": "ID of the linked ledger entry; null if none.",
      "type": "integer",
      "x-description-zh": "关联的账户流水 ID;没有则为空。"
     },
     "mch_order_no": {
      "description": "Merchant order number (the gateway-side order number); null for non-online payments.",
      "type": "string",
      "x-description-zh": "商户订单号(网关侧订单号);非在线支付为空。"
     },
     "paid_at": {
      "description": "Payment time; null if unpaid.",
      "type": "string",
      "x-description-zh": "付款时间;未付款为空。"
     },
     "pay_type": {
      "description": "admin/balance/alipay/wxpay, etc.; empty = unpaid.",
      "type": "string",
      "x-description-zh": "admin/balance/alipay/wxpay 等;空 = 未付款。"
     },
     "status": {
      "description": "Order status: unpaid or paid.",
      "enum": [
       "unpaid",
       "paid"
      ],
      "type": "string",
      "x-description-zh": "订单状态:unpaid 待付款、paid 已付款。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "transaction_id": {
      "description": "Gateway-side transaction ID; empty if unpaid.",
      "type": "string",
      "x-description-zh": "网关侧交易号;未付款为空。"
     },
     "type": {
      "description": "recharge (admin recharge) / deduct (admin deduction) / payment (online payment) / package (package purchase), etc.",
      "type": "string",
      "x-description-zh": "recharge(管理员充值)/deduct(管理员扣款)/payment(在线支付)/package(套餐)等。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "package-catalog": {
    "properties": {
     "groups": {
      "description": "Package groups.",
      "items": {
       "type": "object",
       "x-gocdn-type": "PackageGroup"
      },
      "type": "array",
      "x-description-zh": "套餐分组。"
     },
     "packages": {
      "description": "Base packages on sale.",
      "items": {
       "type": "object",
       "x-gocdn-type": "Package"
      },
      "type": "array",
      "x-description-zh": "在售的基础套餐。"
     },
     "upgrades": {
      "description": "Upgrade packs on sale.",
      "items": {
       "type": "object",
       "x-gocdn-type": "PackageUpgrade"
      },
      "type": "array",
      "x-description-zh": "在售的升级包。"
     }
    },
    "type": "object"
   },
   "package-groups": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "sort": {
      "description": "Display order (smaller first).",
      "type": "integer",
      "x-description-zh": "排序值(小的在前)。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "package-monitor": {
    "properties": {
     "bandwidth_bps": {
      "description": "Sum of outbound bandwidth across nodes over the last minute (bit/s).",
      "type": "integer",
      "x-description-zh": "最近 1 分钟各节点出站带宽之和(bit/s)。"
     },
     "bandwidth_limit_mbps": {
      "description": "Effective bandwidth quota (including upgrade packs); -1 means unlimited.",
      "type": "integer",
      "x-description-zh": "有效带宽额度(含升级包);-1 不限。"
     },
     "connections": {
      "description": "Sum of per-node peak connection counts over the last minute.",
      "type": "integer",
      "x-description-zh": "最近 1 分钟各节点连接数峰值之和。"
     },
     "connections_limit": {
      "description": "Effective connection quota (including upgrade packs); -1 means unlimited.",
      "type": "integer",
      "x-description-zh": "有效连接数额度(含升级包);-1 不限。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "PackageMonitorNode"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "user_package_id": {
      "description": "Purchased package ID.",
      "type": "integer",
      "x-description-zh": "已购套餐 ID。"
     }
    },
    "type": "object"
   },
   "package-upgrades": {
    "properties": {
     "amount": {
      "description": "Amount added per unit; always 1 for feature items (custom_cc_rule/websocket).",
      "type": "integer",
      "x-description-zh": "每份加多少;功能类(custom_cc_rule/websocket)恒为 1"
     },
     "bind_packages": {
      "description": "Only these base packages may buy it; empty = no restriction.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "只许这些基础套餐加购;空 = 不限"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "price_cents": {
      "description": "Price per unit per month, in cents.",
      "type": "integer",
      "x-description-zh": "每份每月价格,分"
     },
     "type": {
      "description": "Add-on item: traffic GB, domains, non-standard ports, TCP/UDP forwarding ports, custom CC, bandwidth Mbps, connections, WebSocket, dedicated IPs.",
      "enum": [
       "traffic",
       "domain",
       "http_port",
       "stream_port",
       "custom_cc_rule",
       "bandwidth",
       "connection",
       "websocket",
       "ip_num"
      ],
      "type": "string",
      "x-description-zh": "加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "packages": {
    "properties": {
     "backup_group_id": {
      "description": "Backup node group; null = none.",
      "type": "integer",
      "x-description-zh": "备用线路分组;null = 没有"
     },
     "bandwidth_mbps": {
      "description": "Bandwidth in Mbps, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "带宽 Mbps,-1 不限"
     },
     "buy_limit": {
      "description": "Maximum copies a tenant may hold, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "每租户最多持有几份,-1 不限"
     },
     "cname_domain_id": {
      "description": "CNAME root domain; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "接入根域(CNAME 域名);null = 套餐不绑线路"
     },
     "cname_host_suffix": {
      "description": "Suffix for newly generated host records; empty = only the 8-character random name.",
      "type": "string",
      "x-description-zh": "新生成主机记录的后缀;空 = 只有 8 位随机名"
     },
     "cname_mode": {
      "description": "CNAME mode. site = one access name per site or stream; package = sites and streams of a purchased package share one access name.",
      "enum": [
       "site",
       "package"
      ],
      "type": "object",
      "x-description-zh": "CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。",
      "x-gocdn-type": "PackageCnameMode"
     },
     "connections": {
      "description": "Concurrent connections, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "并发连接数,-1 不限"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "custom_cc_rule": {
      "description": "Allows custom CC rules.",
      "type": "boolean",
      "x-description-zh": "可自定义 CC 规则"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "domains": {
      "description": "Number of domains (each IP site counts as 1), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "域名数(IP 站每站占 1),-1 不限"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "errors": {
      "description": "Why each remaining item was not changed; field is /ids/\u003cindex\u003e, code as in the single-item update (not_found, readonly and so on).",
      "items": {
       "type": "object",
       "x-gocdn-type": "FieldError"
      },
      "type": "array",
      "x-description-zh": "没改的逐条原因;field 为 /ids/\u003c下标\u003e,code 同单条修改接口(not_found、readonly 等)。"
     },
     "group_ids": {
      "description": "Package groups it belongs to.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "所属套餐分组"
     },
     "http_ports": {
      "description": "Number of non-standard HTTP/HTTPS ports (other than 80/443), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "HTTP/HTTPS 非标端口数(80/443 之外),-1 不限"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "IDs of the objects to change, at most 100.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要改的对象 id,至多 100 个。"
     },
     "ip_num": {
      "description": "Number of selectable IPs (\"My IPs\"), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "可选 IP 数(「我的 IP」),-1 不限"
     },
     "ip_pool_id": {
      "description": "IP pool used to provision IP sites (IP product line); null = not provisioned.",
      "type": "integer",
      "x-description-zh": "开通 IP 站点用的 IP 池(IP 产品线);null = 不开通"
     },
     "ip_site_port": {
      "description": "IP-site ports: distinct ports across all IP sites of the package (80/443 included), -1 = unlimited; IP-site ports do not count toward non-standard ports.",
      "type": "integer",
      "x-description-zh": "IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数"
     },
     "items": {
      "description": "Fields to sync.",
      "items": {
       "type": "object",
       "x-gocdn-type": "PackageSyncField"
      },
      "type": "array",
      "x-description-zh": "要同步的字段"
     },
     "l2": {
      "description": "Includes tiered origin (tenant switch of the paid feature l2): tenants can turn on tiered origin for sites, and nodes use it, only while the master license l2 is active; existing packages are false (on upgrade, purchased packages of tenants already using tiered origin are set to true).",
      "type": "boolean",
      "x-description-zh": "含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true)"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_group_id": {
      "description": "Primary node group; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "主线路分组;null = 套餐不绑线路"
     },
     "origin_ip_limit": {
      "description": "Allowed origin IPs or CIDR ranges; empty = any. When set, origins of sites under the package must fall inside them and domain origins are rejected.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许"
     },
     "owners": {
      "description": "Tenant ids allowed to buy; empty = no restriction.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "限定可购买的租户 id;空 = 不限"
     },
     "price_month_cents": {
      "description": "Monthly price in cents.",
      "type": "integer",
      "x-description-zh": "月价,分"
     },
     "price_quarter_cents": {
      "description": "Quarterly price in cents.",
      "type": "integer",
      "x-description-zh": "季价,分"
     },
     "price_year_cents": {
      "description": "Yearly price in cents.",
      "type": "integer",
      "x-description-zh": "年价,分"
     },
     "region_id": {
      "description": "Region; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "区域;null = 套餐不绑线路"
     },
     "renew_before_days": {
      "description": "Renewal is only allowed within this many days before expiry, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "到期前几天内才许续费,-1 不限"
     },
     "require_verified": {
      "description": "Real-name verification is required to purchase.",
      "type": "boolean",
      "x-description-zh": "须实名认证才能购买"
     },
     "sale_until": {
      "description": "Not sold after this time; omitted/null = no limit.",
      "type": "string",
      "x-description-zh": "过了此刻不再出售;不给/null = 不限"
     },
     "skipped": {
      "description": "Number skipped because they do not follow the base package or individually edited at least one changed field (other fields are still synced).",
      "type": "integer",
      "x-description-zh": "不跟随或至少一个改动字段单独改过而跳过的个数(其余字段照常同步)"
     },
     "skipped_ids": {
      "description": "Ids of the skipped purchased packages.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "被跳过的已购套餐 id"
     },
     "sort": {
      "description": "Display order (smaller first).",
      "type": "integer",
      "x-description-zh": "排序值(小的在前)。"
     },
     "stream_ports": {
      "description": "Number of TCP/UDP forwarding ports, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "四层转发端口数,-1 不限"
     },
     "sync": {
      "description": "Sync result.",
      "type": "object",
      "x-description-zh": "同步结果。",
      "x-gocdn-type": "PackageSyncResult"
     },
     "synced": {
      "description": "Number of purchased packages synced (for automatic sync, those where every changed field was synced).",
      "type": "integer",
      "x-description-zh": "已同步的已购套餐数(自动同步时 = 本次改动的字段全部同步了的个数)"
     },
     "traffic_gb": {
      "description": "Traffic in GB per billing cycle, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "每计费周期流量 GB,-1 不限"
     },
     "updated": {
      "description": "IDs that were set (including those already in the target state), in request order.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "已改好的 id(含本来就是目标状态的),按请求顺序。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "waf_enhanced": {
      "description": "Includes WAF Enhanced (tenant switch of the paid feature waf_enhanced): tenants can use standard/strict levels, big screen, deep Bot, anti-tamper and so on only while the master license WAF Enhanced is not degraded; existing packages are false.",
      "type": "boolean",
      "x-description-zh": "含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false"
     },
     "websocket": {
      "description": "Allows WebSocket.",
      "type": "boolean",
      "x-description-zh": "可开 WebSocket"
     }
    },
    "type": "object"
   },
   "panel-cert": {
    "properties": {
     "acme": {
      "description": "Automatic issuance state (state, challenge type, renewal and the last failure reason).",
      "type": "object",
      "x-description-zh": "自动签发状态(状态、验证方式、续签与最近一次失败原因)。",
      "x-gocdn-type": "CertAcme"
     },
     "cert": {
      "description": "Certificate (responses carry the chain, names, expiry and status but never the private key; export the key via the export endpoint).",
      "type": "object",
      "x-description-zh": "证书(响应带证书链、域名、到期时间与状态,不带私钥;私钥只能经导出接口取回)。",
      "x-gocdn-type": "Cert"
     },
     "cert_id": {
      "description": "panel.tls.cert_id; 0 when no panel certificate is configured.",
      "type": "integer",
      "x-description-zh": "panel.tls.cert_id;0 = 没配面板证书。"
     },
     "domain": {
      "description": "Panel domain; empty when not set.",
      "type": "string",
      "x-description-zh": "面板域名(panel.access.domain);空 = 没填。"
     },
     "https": {
      "description": "Current state of panel HTTPS. on = the panel certificate is usable and the controller listens for HTTPS; no_domain = no panel domain set (no certificate is requested); no_cert = a domain is set but there is no usable panel certificate; issuing = the certificate is being issued; failed = issuance failed (see acme.last_error; automatic requests retry at intervals); no_listen = the certificate exists but the controller config file has no HTTPS listener (listen_tls); expired = the panel certificate has expired (not_after has passed and renewal has not succeeded).",
      "enum": [
       "on",
       "no_domain",
       "no_cert",
       "issuing",
       "failed",
       "no_listen",
       "expired"
      ],
      "type": "string",
      "x-description-zh": "面板 HTTPS 的现状。on = 面板证书可用且主控开了 HTTPS 监听;no_domain = 没填面板域名(不申请证书);no_cert = 填了域名但没有可用的面板证书;issuing = 证书正在签发;failed = 证书签发失败(原因见 acme.last_error,自动申请的会按间隔重试);no_listen = 证书已有,但主控配置文件没开 HTTPS 监听(listen_tls);expired = 面板证书已过期(not_after 已过,续签没成功)。"
     }
    },
    "type": "object"
   },
   "payment-channels": {
    "properties": {
     "alipay": {
      "description": "Merchant parameters of the Alipay gateway.",
      "type": "object",
      "x-description-zh": "支付宝网关的商户参数。",
      "x-gocdn-type": "AlipayGateway"
     },
     "codepay": {
      "description": "Merchant parameters of the Codepay gateway.",
      "type": "object",
      "x-description-zh": "码支付网关的商户参数。",
      "x-gocdn-type": "CodepayGateway"
     },
     "default_method": {
      "description": "The method selected by default on the recharge page; transfer = bank transfer (transfer must be enabled).",
      "enum": [
       "",
       "alipay",
       "wxpay",
       "transfer"
      ],
      "type": "string",
      "x-description-zh": "充值页默认选中的方式;transfer = 转账汇款(须已开启转账)。"
     },
     "epay": {
      "description": "Merchant parameters of the Epay gateway.",
      "type": "object",
      "x-description-zh": "易支付网关的商户参数。",
      "x-gocdn-type": "EpayGateway"
     },
     "methods": {
      "description": "Enable switch and gateway for each online payment method.",
      "type": "object",
      "x-description-zh": "各在线支付方式的开关与所走网关。",
      "x-gocdn-type": "PaymentMethodSet"
     },
     "notify_base": {
      "description": "Root URL of the panel reachable by the gateways (for example https://panel.example.com); callback URLs are built from it, and empty = orders cannot be placed.",
      "type": "string",
      "x-description-zh": "面板对网关可达的根地址(如 https://panel.example.com);回调地址由它拼出,空 = 不能下单。"
     },
     "return_url": {
      "description": "Page to return to after payment (used by Alipay desktop website payment and Epay); empty = no redirect.",
      "type": "string",
      "x-description-zh": "付款后跳回的页面(支付宝电脑网站支付、易支付用);空 = 不跳。"
     },
     "transfer": {
      "description": "Offline transfer settings.",
      "type": "object",
      "x-description-zh": "线下转账设置。",
      "x-gocdn-type": "PaymentTransfer"
     },
     "wxpay": {
      "description": "Merchant parameters of the WeChat Pay gateway.",
      "type": "object",
      "x-description-zh": "微信支付网关的商户参数。",
      "x-gocdn-type": "WxpayGateway"
     }
    },
    "type": "object"
   },
   "payment-methods": {
    "properties": {
     "default_method": {
      "description": "Default selected payment method; empty means none.",
      "type": "string",
      "x-description-zh": "默认选中的支付方式;空表示未指定。"
     },
     "methods": {
      "description": "Enabled online payment methods.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "已开启的在线支付方式。"
     },
     "transfer": {
      "description": "Offline transfer settings.",
      "type": "object",
      "x-description-zh": "线下转账设置。",
      "x-gocdn-type": "PaymentTransfer"
     }
    },
    "type": "object"
   },
   "payment-notifications": {
    "properties": {},
    "type": "object"
   },
   "payments": {
    "properties": {
     "amount_cents": {
      "description": "Recharge amount in cents.",
      "type": "integer",
      "x-description-zh": "充值金额(分)。"
     },
     "gateway": {
      "description": "The payment gateway the order was placed with.",
      "enum": [
       "alipay",
       "wxpay",
       "codepay",
       "epay"
      ],
      "type": "string",
      "x-description-zh": "实际下单的支付网关。"
     },
     "mch_order_no": {
      "description": "Merchant order number (the gateway-side order number).",
      "type": "string",
      "x-description-zh": "商户订单号(网关侧的订单号)。"
     },
     "order_id": {
      "description": "ID of the unpaid order.",
      "type": "integer",
      "x-description-zh": "待支付订单 ID。"
     },
     "pay_url": {
      "description": "Payment address: a redirect URL, or a QR code string for weixin:// and Alipay face-to-face payment.",
      "type": "string",
      "x-description-zh": "付款地址:跳转网址,或微信 weixin:// 与支付宝当面付的二维码串。"
     }
    },
    "type": "object"
   },
   "pending-nodes": {
    "properties": {
     "area": {
      "description": "Area (display only, never sent to nodes); empty = not set. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。"
     },
     "bandwidth_mbps": {
      "description": "Node bandwidth in Mbps (display only, unrelated to monitor.bw_limit_mbps); 0 = not set. Sub-IPs take the primary node's value.",
      "type": "integer",
      "x-description-zh": "节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。"
     },
     "capacity": {
      "description": "Node memory capacity (read-only, only returned by GET /nodes/{id}?capacity=true): per-site resident cost = locations × 28.1KB + HTTPS ratio × 25.5KB, budget = memory MiB × 0.25 / 2 − 28MiB, limit = budget / per-site cost. null = no system info for the node or memory total missing.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "节点内存容量(只读,只在 GET /nodes/{id}?capacity=true 给出):单站常驻 = location 数 × 28.1KB + https 占比 × 25.5KB,预算 = 内存 MiB × 0.25 / 2 − 28MiB,上限 = 预算 / 单站。null = 没有该节点的系统信息或缺内存总量。",
      "x-gocdn-type": "NodeCapacity"
     },
     "cert_expiry": {
      "description": "Expiry time of the most recently issued certificate; null = no certificate issued yet (or a sub-IP).",
      "type": "string",
      "x-description-zh": "最近一次签发证书的到期时刻;null = 还没领过证(或子 IP)。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "disable_by": {
      "description": "Disable source (manual = admin; monitor = auto-disabled by node monitoring and re-enabled once probes recover; bandwidth = auto-disabled when outbound bandwidth exceeds monitor.bw_limit_mbps and re-enabled when it drops back); empty when enabled.",
      "type": "string",
      "x-description-zh": "停用来源(manual = 管理员;monitor = 节点监控自动停用,探测恢复后自动启用;bandwidth = 出站带宽超过 monitor.bw_limit_mbps 自动停用,回落后自动启用);启用时为空。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "enrolled_at": {
      "description": "Time the node registered.",
      "type": "string",
      "x-description-zh": "节点注册时间。"
     },
     "hostname": {
      "description": "Host name reported by the node.",
      "type": "string",
      "x-description-zh": "节点上报的主机名。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ip": {
      "description": "Source address of the registration connection.",
      "type": "string",
      "x-description-zh": "注册连接的来源地址。"
     },
     "monitor": {
      "description": "Node monitor probe settings (the control plane probes this IP at the interval configured in monitor.node).",
      "type": "object",
      "x-description-zh": "节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。",
      "x-gocdn-type": "NodeMonitor"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "ops": {
      "description": "Node operations status (read-only, from heartbeats): online, whether the config lags behind the latest published version, and clock sync. Sub-IPs follow their primary node.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "节点运维状态(只读,来自心跳):在线、配置是否落后于最新已发布版本、时钟是否同步。子 IP 跟随主节点。",
      "x-gocdn-type": "NodeOps"
     },
     "parent_id": {
      "description": "Primary node that owns this sub-IP; null = primary node.",
      "type": "integer",
      "x-description-zh": "子 IP 所属主节点;null = 主节点。"
     },
     "region_id": {
      "description": "Region ID",
      "type": "integer",
      "x-description-zh": "区域 ID"
     },
     "replace_node_id": {
      "description": "Replace an existing primary node (new machine takes over the old one): the new node inherits the old node's lines, IP pool IP, region (when region_id is omitted), monitor settings, service period and area/bandwidth; the old node is disabled and removed from DNS, all in the approval transaction. The old node's sub IPs move to the new node by default (lines, pool IPs and monitor settings kept); see replace_sub_ips for new addresses or opting out. The old node must be an approved primary node with the same role; 409 ip_in_use when its pool IP is bound to IP sites and the IP changes.",
      "type": "integer",
      "x-description-zh": "替换已有主节点(新机顶替旧机):新节点继承旧节点的线路、IP 池里的 IP、区域(没给 region_id 时)、监控设置、服务期与地区/带宽,旧节点停用并从解析摘除,与审核同一事务。旧节点的子 IP 默认一并改挂新节点(线路、池内 IP、监控设置不变),地址与不迁见 replace_sub_ips。旧节点须是已审主节点、角色相同;池内 IP 被 IP 站点绑定且 IP 变了时 409 ip_in_use。"
     },
     "replace_sub_ips": {
      "description": "Per-sub-IP handling of the old node when replacing (only with replace_node_id); unlisted sub IPs move to the new node keeping their address. ip switches to a new address (422 conflict if another node uses it); skip=true leaves the sub IP and its lines on the old node, disabled.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ReplaceSubIp"
      },
      "type": "array",
      "x-description-zh": "替换时逐条指定旧节点子 IP 的去向(只在给了 replace_node_id 时有效);没列出的子 IP 沿用原地址改挂新节点。ip 给了就改用新地址(已被别的节点用 422 conflict),skip 为 true 的不迁:该子 IP 及其线路随旧节点停用。"
     },
     "role": {
      "description": "Node role: edge or l2.",
      "enum": [
       "edge",
       "l2"
      ],
      "type": "string",
      "x-description-zh": "节点角色:edge 边缘;l2 二级。"
     },
     "service_expire": {
      "description": "Server service expiry date YYYY-MM-DD (used for the home-page expiry reminder; never auto-disables); null = not set, no reminder. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。"
     },
     "service_start": {
      "description": "Server service start date YYYY-MM-DD (display only); null = not set. Sub-IPs take the primary node's value.",
      "type": "string",
      "x-description-zh": "服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "pki-validations": {
    "properties": {
     "content": {
      "description": "Validation file content.",
      "type": "string",
      "x-description-zh": "验证文件内容。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "expires_at": {
      "description": "Expires at",
      "type": "string",
      "x-description-zh": "过期时间"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "ttl_s": {
      "description": "Seconds after which the file is no longer served; 0 or omitted = never expires.",
      "type": "integer",
      "x-description-zh": "多少秒后不再代答;0 或不给 = 不过期。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "protect-schemes": {
    "properties": {
     "action": {
      "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
      "enum": [
       "block",
       "challenge"
      ],
      "type": "object",
      "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
      "x-gocdn-type": "ReplayGuardAction"
     },
     "app_salt": {
      "description": "Signing salt (app key, 32-byte hex); with app_sign on but no salt, signed headers are never accepted.",
      "example": "0000000000000000000000000000000000000000000000000000000000000000",
      "type": "string",
      "x-description-zh": "签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。"
     },
     "app_sign": {
      "description": "App signed-header mode - requests carrying the signature headers are checked by signature, no token needed.",
      "type": "boolean",
      "x-description-zh": "App 签名头模式:请求带签名头即按签名校验,不需要令牌。"
     },
     "applied": {
      "description": "Sites written (to be written on dry_run).",
      "type": "integer",
      "x-description-zh": "写入(dry_run 时为将写入)的网站数。"
     },
     "auto_join": {
      "description": "The rule that sites newly entering the range join the scheme automatically; omitted when off.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "「以后新加入范围的网站自动加入方案」的规则;没开时不返回。"
     },
     "bind_ip": {
      "description": "Also bind the token to the client IP (a new IP invalidates it).",
      "type": "boolean",
      "x-description-zh": "令牌再绑客户端 IP(换 IP 即失效)。"
     },
     "counts": {
      "description": "Site counts among the sites visible to the caller: total, turned on, following the scheme, and set alone.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点计数:调用方看得到的站点里,开着的、按方案的、单独设置的各几个。",
      "x-gocdn-type": "ProtectSchemeCounts"
     },
     "custom": {
      "description": "Custom regular expressions, at most 16.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteLeakGuardCustom"
      },
      "type": "array",
      "x-description-zh": "自定义正则,最多 16 条。"
     },
     "demoted_sites": {
      "description": "Sites switched to their own settings with values kept because their owner lacks WAF Enhanced (only in the save response).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "本次保存因属主没开通 WAF 增强、改为单独设置并保留原值的站点数(只在保存的回包里有)。"
     },
     "detect": {
      "description": "Action per built-in pattern; omit a pattern to not check it.",
      "type": "object",
      "x-description-zh": "内置识别各类的处置;不写 = 不查这一类。",
      "x-gocdn-type": "SiteLeakGuardDetect"
     },
     "domain": {
      "description": "Primary domain (the site name when there is none).",
      "type": "string",
      "x-description-zh": "网站主域名(没有域名时为站点名)。"
     },
     "dry_run": {
      "default": false,
      "description": "When true, only return the counts of what would happen; nothing is written.",
      "type": "boolean",
      "x-description-zh": "为 true 只返回会发生什么的计数,不写任何东西。"
     },
     "enabled": {
      "description": "Whether it is on.",
      "type": "boolean",
      "x-description-zh": "是否开着。"
     },
     "exclude": {
      "description": "Path prefixes that are not checked (a trailing * is optional), at most 32.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "不检测的路径前缀(末尾 * 可省),最多 32 条。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never saved, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "failed": {
      "description": "Sites that could not be handled, with the reason; at most 100.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ProtectSchemeFailure"
      },
      "type": "array",
      "x-description-zh": "没能处理的网站及原因,最多 100 条。"
     },
     "failed_total": {
      "description": "Total sites that could not be handled (larger than failed when truncated).",
      "type": "integer",
      "x-description-zh": "没能处理的网站总数(failed 被截断时大于其长度)。"
     },
     "filter": {
      "description": "The same filters as the list; expanded to a set of sites by the server.",
      "type": "object",
      "x-description-zh": "与列表同样的过滤条件,服务端展开成网站集合。",
      "x-gocdn-type": "ProtectSchemeSiteFilter"
     },
     "gate": {
      "description": "WAF Enhanced status of the scheme owner (the tenant or the platform): full = editable; readonly and basic = may only be reduced.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "方案属主(租户本人或平台)的 WAF 增强判定档:full 可改;readonly、basic 只许减不许增。",
      "x-gocdn-type": "ProtectSchemeGate"
     },
     "ids": {
      "description": "Site ids.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "网站 id 列表。"
     },
     "matched": {
      "description": "Sites in the range the caller can see.",
      "type": "integer",
      "x-description-zh": "范围内调用方看得到的网站数。"
     },
     "methods": {
      "description": "Protected methods; omitted = POST/PUT/PATCH/DELETE.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ReplayGuardMethod"
      },
      "type": "array",
      "x-description-zh": "受保护方法;不写 = POST/PUT/PATCH/DELETE。"
     },
     "mode": {
      "description": "What counts as tampering: structure = structural changes only; full = any change to the page.",
      "enum": [
       "structure",
       "full"
      ],
      "type": "string",
      "x-description-zh": "检查范围:structure 仅结构变化;full 整页任意变化。"
     },
     "observe_days": {
      "description": "Days a site observes when turned on by the scheme (record only, no action); 0 = act right away.",
      "type": "integer",
      "x-description-zh": "站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。"
     },
     "observe_until": {
      "description": "End of the observation period (Unix milliseconds); set only for leak protection that is on and still observing, null when expired, never observing, off, or for other protections.",
      "type": "integer",
      "x-description-zh": "观察期截止(Unix 毫秒时间戳);只有防泄露开着且仍在观察期内才有值,已过期、没有观察期、关着或其余方案为空。"
     },
     "override_custom": {
      "default": false,
      "description": "When true, sites with their own settings are switched to the scheme too; by default they are left alone and counted in skipped_custom.",
      "type": "boolean",
      "x-description-zh": "为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。"
     },
     "owner": {
      "description": "Owner username.",
      "type": "string",
      "x-description-zh": "属主用户名。"
     },
     "paths": {
      "description": "Protected API paths, at most 64; empty = nothing protected.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ReplayGuardPath"
      },
      "type": "array",
      "x-description-zh": "保护接口路径表,最多 64 条;空 = 不保护。"
     },
     "scopes": {
      "description": "Protected scopes, at most 50.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteTamperScope"
      },
      "type": "array",
      "x-description-zh": "保护范围,最多 50 条。"
     },
     "selection": {
      "description": "The range of sites to apply to.",
      "type": "object",
      "x-description-zh": "要应用的网站范围。",
      "x-gocdn-type": "ProtectSchemeSelection"
     },
     "site_id": {
      "description": "Site id.",
      "type": "integer",
      "x-description-zh": "网站 id。"
     },
     "skipped_custom": {
      "description": "Sites left alone because they have their own settings (override_custom is false).",
      "type": "integer",
      "x-description-zh": "因单独设置而没覆盖的网站数(override_custom 为 false)。"
     },
     "skipped_gate": {
      "description": "Sites not written because their owner's WAF Enhanced is not full.",
      "type": "integer",
      "x-description-zh": "因属主 WAF 增强不是 full 而没写的网站数。"
     },
     "source": {
      "description": "Where the site's setting comes from: scheme = follows the scheme (changes when the scheme is saved); custom = set for this site alone (including turned off and rows migrated from before).",
      "enum": [
       "scheme",
       "custom"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。",
      "x-gocdn-type": "ProtectSiteSource"
     },
     "status": {
      "description": "Status of the site's setting: enabled; disabled; pending = on but the tamper baseline is still queued; capture_failed = on but baseline capture failed repeatedly and stopped retrying (the last two exist for web tamper protection only).",
      "enum": [
       "enabled",
       "disabled",
       "pending",
       "capture_failed"
      ],
      "type": "object",
      "x-description-zh": "站点这一项的状态:enabled 开着;disabled 关着;pending 开着但防篡改基准还在排队采集;capture_failed 开着但基准采集多次失败、已停止重试(只有防篡改有后两种)。",
      "x-gocdn-type": "ProtectSchemeSiteStatus"
     },
     "tenant_id": {
      "description": "Owner user id.",
      "type": "integer",
      "x-description-zh": "属主用户 id。"
     },
     "today_blocked": {
      "description": "Block and error-page count today (UTC), excluding hits during the observation period (leak protection only, same basis as counts.today_blocked in the scheme response); null for other protections, or when ClickHouse is unavailable or the query fails.",
      "type": "integer",
      "x-description-zh": "今日(UTC)拦截与换错误页次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_blocked 同口径);其余方案、没接 ClickHouse 或查询失败为空。"
     },
     "today_hits": {
      "description": "Hits today (data leak protection = masked plus blocked outside the observation period, i.e. today_masked + today_blocked; web tamper protection = pages found tampered today); null for replay protection.",
      "type": "integer",
      "x-description-zh": "今日命中数(防泄露为今日 UTC 非观察期的打码与拦截次数之和,即 today_masked + today_blocked,防篡改为今日检出篡改的页数);防重放为空。"
     },
     "today_masked": {
      "description": "Masking count today (UTC), excluding hits during the observation period (leak protection only, same basis as counts.today_masked in the scheme response); null for other protections, or when ClickHouse is unavailable or the query fails.",
      "type": "integer",
      "x-description-zh": "今日(UTC)打码次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_masked 同口径);其余方案、没接 ClickHouse 或查询失败为空。"
     },
     "ttl_s": {
      "description": "Token lifetime in seconds, also used for signed-header timestamps; omitted = 120.",
      "type": "integer",
      "x-description-zh": "令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。"
     },
     "updated_at": {
      "description": "Version (null if never saved); use expected_updated_at on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "版本(没保存过为空);修改时用 expected_updated_at。"
     },
     "updated_sites": {
      "description": "Sites following the scheme that this save updated (only in the save response).",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "本次保存一并改到的按方案站点数(只在保存的回包里有)。"
     }
    },
    "type": "object"
   },
   "regions": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "registration-info": {
    "properties": {
     "agreement_body": {
      "description": "User agreement body",
      "type": "string",
      "x-description-zh": "用户协议正文。"
     },
     "agreement_title": {
      "description": "User agreement title",
      "type": "string",
      "x-description-zh": "用户协议标题。"
     },
     "allow_register": {
      "description": "Whether registration is open",
      "type": "boolean",
      "x-description-zh": "是否开放注册。"
     },
     "fields": {
      "description": "Requirements for each registration form field (required or not, whether a code is needed)",
      "type": "object",
      "x-description-zh": "注册表单各字段的要求(是否必填、是否要验证码)。"
     },
     "login_verify_allowed": {
      "description": "Second-factor login methods the platform lets users turn on",
      "items": {
       "type": "object",
       "x-gocdn-type": "LoginVerify"
      },
      "type": "array",
      "x-description-zh": "平台允许用户开启的登录二次验证方式。"
     }
    },
    "type": "object"
   },
   "registrations": {
    "properties": {
     "accept_agreement": {
      "description": "Must be true",
      "type": "boolean",
      "x-description-zh": "须为 true。"
     },
     "balance_cents": {
      "description": "Account balance in cents, same as balance_cents of GET /users/{user_id}/account (0 when there is no account). Only present in the GET /users list, not in single-user responses",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。"
     },
     "certified": {
      "description": "Whether real-name verification has passed",
      "type": "boolean",
      "x-description-zh": "是否已通过实名认证。"
     },
     "client_ip": {
      "description": "Source IP of this request, derived the same way as the login IP allowlist check (what the allowlist compares is what is shown). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "delegated_session": {
      "description": "Whether the current session was issued by superadmin sign-in or switch-to-user (if so, password, email, phone, login allowlist, login verification and real-name are read-only). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。"
     },
     "email": {
      "description": "Email",
      "type": "string",
      "x-description-zh": "邮箱"
     },
     "email_code": {
      "description": "Code sent to the email (POST /verify-codes, purpose=bind); required when the email must be verified",
      "type": "string",
      "x-description-zh": "发到该邮箱的验证码(POST /verify-codes,purpose=bind);邮箱要验证时必填。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "login_ip_allow": {
      "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
     },
     "login_verify": {
      "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
      "enum": [
       "none",
       "email",
       "sms"
      ],
      "type": "object",
      "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
      "x-gocdn-type": "LoginVerify"
     },
     "password": {
      "description": "Login password, 8 to 128 characters",
      "type": "string",
      "x-description-zh": "登录口令,8 到 128 个字符。"
     },
     "phone": {
      "description": "Phone number",
      "type": "string",
      "x-description-zh": "手机号"
     },
     "phone_code": {
      "description": "Code sent to the phone number (POST /verify-codes, purpose=bind); required when the phone number must be verified",
      "type": "string",
      "x-description-zh": "发到该手机号的验证码(POST /verify-codes,purpose=bind);手机号要验证时必填。"
     },
     "role": {
      "description": "Account role: admin or tenant",
      "enum": [
       "admin",
       "tenant"
      ],
      "type": "string",
      "x-description-zh": "账号角色:admin 管理员,tenant 租户。"
     },
     "totp_enabled": {
      "description": "Whether TOTP is enabled",
      "type": "boolean",
      "x-description-zh": "是否已启用动态口令。"
     },
     "totp_recovery_left": {
      "description": "Number of unused TOTP recovery codes. Only present in GET /me and PUT /me when TOTP is enabled",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "username": {
      "description": "Required if registration info demands it, otherwise generated automatically. Must not look like a phone number (all digits)",
      "type": "string",
      "x-description-zh": "须注册须知要求时必填;不填则自动生成。不能像手机号(纯数字)。"
     }
    },
    "type": "object"
   },
   "reports": {
    "properties": {
     "action": {
      "description": "Protection action: pass, challenge or block.",
      "type": "string",
      "x-description-zh": "防护处置:pass 放行、challenge 验证、block 拦截。"
     },
     "advice": {
      "description": "Number of suggestions.",
      "type": "integer",
      "x-description-zh": "建议数。"
     },
     "app": {
      "description": "Detected application; empty when none was recognised.",
      "type": "string",
      "x-description-zh": "识别到的程序名;空串 = 没识别出。"
     },
     "app_manual": {
      "description": "The application was overridden by hand.",
      "type": "boolean",
      "x-description-zh": "程序是用户人工改写的。"
     },
     "app_version": {
      "description": "Application version; empty when it could not be read.",
      "type": "string",
      "x-description-zh": "程序版本;读不到时为空串。"
     },
     "approx": {
      "description": "The ranking comes from each node's per-minute top K (ip, prefix, url, referer); nodes report only their own top K, so totals are approximate. False when read from access logs (action or server_port given).",
      "type": "boolean",
      "x-description-zh": "本榜取自节点每分钟前 K(ip、prefix、url、referer),各节点只上报自己的前 K,合计为近似值;带 action 或 server_port 改读访问日志时为 false。"
     },
     "at": {
      "description": "Time it happened (the last hit inside the window).",
      "type": "string",
      "x-description-zh": "发生时刻(窗口内最后一次命中)。"
     },
     "attack_types": {
      "description": "Attack type distribution (sqli, xss, scanner, rce, traversal, other and semantic, bot, upload, tamper, leak), by rows descending; adds up to total.",
      "items": {
       "type": "object",
       "x-gocdn-type": "WafEventCount"
      },
      "type": "array",
      "x-description-zh": "攻击类型分布(sqli、xss、scanner、rce、traversal、other 与 semantic、bot、upload、tamper、leak),按行数降序;之和等于 total。"
     },
     "attacked_sites": {
      "description": "Distinct attacked sites.",
      "type": "integer",
      "x-description-zh": "被攻击网站去重数。"
     },
     "ban_hits": {
      "description": "Revisits stopped by banned IPs - the sum of the auto_ban and status_ban items of blocked_by_feature. Always 0 until nodes tag ban blocks.",
      "type": "integer",
      "x-description-zh": "封禁 IP 挡下的复访次数:blocked_by_feature 里 auto_ban 与 status_ban 两项之和。节点开始给封禁拦截打标之前恒为 0。"
     },
     "block": {
      "description": "Blocks in block mode (action = block, not observe).",
      "type": "integer",
      "x-description-zh": "拦截模式的拦截(action = block 且非观察)。"
     },
     "block_reason": {
      "description": "Block reason: region = blocked by region limit, region_log = region limit log-only hit (not blocked), acl = blocked by ACL, other = blocked by other protection; omitted when neither blocked nor a region-limit hit.",
      "enum": [
       "region",
       "region_log",
       "acl",
       "other"
      ],
      "type": "string",
      "x-description-zh": "拦截原因:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截;没拦也没命中地区限制不回。"
     },
     "blocked": {
      "description": "Blocked requests (action = block).",
      "type": "integer",
      "x-description-zh": "被拦截(action = block)的请求数。"
     },
     "blocked_acl": {
      "description": "Requests blocked by ACLs (including ACLs without location conditions).",
      "type": "integer",
      "x-description-zh": "被 ACL 拦截的请求数(含不带地区条件的 ACL)。"
     },
     "blocked_by_feature": {
      "description": "Blocked requests per protection feature (blocked requests scaled by sampling weight, challenges excluded). Always 12 items (genuine blocks only; leak and tamper protection replace the response body and are not listed here, see handled_by_feature), descending by count then in a fixed order; the counts add up to summary.blocked for the same window and site scope. A feature is derived from the rule_ref the node writes into the access log; blocks from nodes that do not tag them are counted under waf_rule.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityFeatureCount"
      },
      "type": "array",
      "x-description-zh": "按防护功能的拦截次数(被拦截请求按采样权重折算,不含挑战验证)。固定 12 项(只含真拦截类,防泄露、防篡改是换体不在此列,见 handled_by_feature),次数降序、同次数按固定顺序;各项 count 之和等于同一时间窗、同一网站范围的 summary.blocked。功能归类看节点写进访问日志的 rule_ref,旧节点没打标的拦截记在 waf_rule。"
     },
     "blocked_region": {
      "description": "Requests blocked by the region limit.",
      "type": "integer",
      "x-description-zh": "被地区限制拦截的请求数。"
     },
     "body_trunc": {
      "description": "The request body exceeded the inspection limit and only the head was checked.",
      "type": "boolean",
      "x-description-zh": "请求体超过检查上限,只查了前一段。"
     },
     "bot_score": {
      "description": "Bot behaviour score 0–100; only on Bot events (type = bot), absent for other types (score is the WAF anomaly score and means something else).",
      "type": "integer",
      "x-description-zh": "Bot 行为评分 0–100;仅 Bot 事件(type = bot)有,其余类型没有此字段(score 是 WAF 异常分,含义不同)。"
     },
     "bytes_sent": {
      "description": "Raw downstream bytes.",
      "type": "integer",
      "x-description-zh": "原始下行字节。"
     },
     "cache_status": {
      "description": "Cache status, such as HIT, MISS or BYPASS.",
      "type": "string",
      "x-description-zh": "缓存状态,如 HIT、MISS、BYPASS。"
     },
     "category": {
      "description": "Rule category (sqli, xss, scanner, rce, php, nodejs, java, lfi, rfi, protocol, ...); empty when unknown.",
      "type": "string",
      "x-description-zh": "规则分类(sqli xss scanner rce php nodejs java lfi rfi protocol 等);查不到为空。"
     },
     "challenge": {
      "description": "Challenges outside observe mode (action = challenge).",
      "type": "integer",
      "x-description-zh": "非观察的验证(action = challenge)。"
     },
     "checked_at": {
      "description": "Time of the checkup.",
      "type": "string",
      "x-description-zh": "体检时刻。"
     },
     "checkup": {
      "description": "Site checkup feed; the protection score (site checkup scores weighted by traffic) and the to-do suggestions. Follows site_id but not the time window.",
      "type": "object",
      "x-description-zh": "网站体检接入:防护评分(各网站体检分按流量加权)与待处理建议;随 site_id 过滤,不随时间窗。"
     },
     "client_ip": {
      "description": "Client IP; IPv4 as is.",
      "type": "string",
      "x-description-zh": "客户端 IP;IPv4 按原样。"
     },
     "combo": {
      "description": "Distribution of HTTP/2 and HTTP/3 combinations (number of sites).",
      "type": "object",
      "x-description-zh": "HTTP/2 与 HTTP/3 的组合分布(站点数)。"
     },
     "compare": {
      "description": "The previous period (compare=prev) with its window [start, end), per-bucket points and totals; points align one-to-one with the current period. h3_ratio, backend_resp_time_p95 and noconfig_req are always null.",
      "type": "object",
      "x-description-zh": "上一周期(compare=prev):窗口 [start, end) 与按桶点列、合计;点列与当前周期逐点对齐。不含 h3_ratio、backend_resp_time_p95、noconfig_req(恒为 null)。",
      "x-gocdn-type": "SitesOverviewCompare"
     },
     "content_encoding": {
      "description": "Response Content-Encoding.",
      "type": "string",
      "x-description-zh": "响应的 Content-Encoding。"
     },
     "count": {
      "description": "530 count within the time window (sum across nodes).",
      "type": "integer",
      "x-description-zh": "时间窗内 530 次数(各节点之和)。"
     },
     "countries": {
      "description": "Attack source countries (blocked and challenged requests scaled by sampling weight), descending; an empty country means unknown.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityCountryCount"
      },
      "type": "array",
      "x-description-zh": "攻击来源国(被拦截与被挑战的请求数,按采样权重折算),次数降序;country 为空串 = 归属地未识别。"
     },
     "country": {
      "description": "Client country (ISO 3166-1 alpha-2); omitted when unknown.",
      "type": "string",
      "x-description-zh": "客户端归属国家(ISO 3166-1 两位码);未识别不回。"
     },
     "covered": {
      "description": "Known vulnerabilities of the recognised program already covered by built-in rules, from the protection list; 0 when no program is recognised or the list has no such product.",
      "type": "integer",
      "x-description-zh": "按识别到的程序对照防护清单,节点内置规则已防护的已知漏洞数;没有识别到程序或清单里没有该产品为 0。"
     },
     "created_at": {
      "description": "Created at",
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "critical": {
      "description": "Number of critical problems (ignored and locked ones excluded).",
      "type": "integer",
      "x-description-zh": "严重问题数(不含已忽略与未开通)。"
     },
     "ctype": {
      "description": "Response Content-Type (parameters removed, lowercase).",
      "type": "string",
      "x-description-zh": "响应的 Content-Type(去参数小写)。"
     },
     "current_site_id": {
      "description": "Id of the site whose result is being saved; only present in stage 5 (stages 1-4 run on the whole batch and have no single current site), omitted otherwise.",
      "type": "integer",
      "x-description-zh": "正在保存结果的网站 id;只在阶段 5 有值(阶段 1-4 是整批执行,没有单个当前站),没有时缺省。"
     },
     "cves": {
      "description": "CVEs hit in the last 7 days (matched against the rule pack meta section), descending by hits, at most 50; empty when no rule pack is connected.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityCve"
      },
      "type": "array",
      "x-description-zh": "最近 7 天命中的 CVE(规则包 meta 节对照),按命中次数降序,最多 50 条;没接入规则包时为空。"
     },
     "dims": {
      "description": "Result of a dims request, mapping each dimension name to its ranking (which has no dims of its own); absent for a single-dimension request.",
      "type": "object",
      "x-description-zh": "dims 请求的结果:键为维度名,值为该维度的排行(其中不再有 dims);单维度请求不带。"
     },
     "domain": {
      "description": "First domain.",
      "type": "string",
      "x-description-zh": "第一个域名。"
     },
     "done_rows": {
      "description": "Rows written to the file so far.",
      "type": "integer",
      "x-description-zh": "已写入文件的行数。"
     },
     "done_site_ids": {
      "description": "Ids of the sites whose checkup results this batch has saved (ascending); sites not listed are not finished yet (or failed). Cleared when the batch is retried.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "本批次已保存体检结果的网站 id(升序);不在其中的网站还没体检完(或没体检成功)。重试时清空重来。"
     },
     "done_sites": {
      "description": "Number of sites with saved results; below total_sites after completion means some sites failed.",
      "type": "integer",
      "x-description-zh": "已保存结果的网站数;完成后小于 total_sites 表示有网站没体检成功。"
     },
     "error": {
      "description": "Reason of the latest failure (kept while retrying, cleared once the export succeeds; the final reason when failed).",
      "type": "string",
      "x-description-zh": "最近一次失败的原因(重试期间保留,导出成功后清空;failed 时即最终失败原因)。"
     },
     "exception": {
      "description": "The site exception written by this allow-list action (or already present on the site).",
      "type": "object",
      "x-description-zh": "这次加白写入(或本站已有)的站点例外。",
      "x-gocdn-type": "WafEventAllowException"
     },
     "expires_at": {
      "description": "When the file is removed (completion time plus the retention hours).",
      "type": "string",
      "x-description-zh": "文件到期被清理的时刻(完成时刻 + 保留小时数)。"
     },
     "extra": {
      "description": "Known vulnerabilities on the same basis that can additionally be covered once WAF rule updates are enabled.",
      "type": "integer",
      "x-description-zh": "同上口径下,开通 WAF 规则更新后可再防护的已知漏洞数。"
     },
     "facets": {
      "description": "Facet counts for the filter buttons.",
      "type": "object",
      "x-description-zh": "筛选按钮上的分面计数。"
     },
     "file_bytes": {
      "description": "Compressed file size in bytes (set once done).",
      "type": "integer",
      "x-description-zh": "压缩后文件大小(字节,完成后才有)。"
     },
     "file_count": {
      "description": "Number of uploaded files scanned in this request.",
      "type": "integer",
      "x-description-zh": "本请求已扫的上传文件数。"
     },
     "file_ctype": {
      "description": "Content-Type of the uploaded file as given by the client.",
      "type": "string",
      "x-description-zh": "上传文件的 Content-Type(客户端给的)。"
     },
     "file_field": {
      "description": "Form field name of the uploaded file.",
      "type": "string",
      "x-description-zh": "上传文件的表单字段名。"
     },
     "file_magic": {
      "description": "Type recognised from the file header; empty when unknown.",
      "type": "string",
      "x-description-zh": "按文件头识别的类型;认不出为空。"
     },
     "file_name": {
      "description": "Uploaded file name as given by the client; only on upload events (type = upload).",
      "type": "string",
      "x-description-zh": "上传文件名(客户端给的原名);仅上传事件(type = upload)有。"
     },
     "file_sha256": {
      "description": "SHA-256 of the uploaded file; empty when not computed.",
      "type": "string",
      "x-description-zh": "上传文件 sha256;没算为空。"
     },
     "file_size": {
      "description": "Uploaded file size in bytes; only on upload events (type = upload).",
      "type": "integer",
      "x-description-zh": "上传文件大小(字节);仅上传事件(type = upload)有。"
     },
     "filter": {
      "description": "Filters given with the request (same as the list query parameters).",
      "type": "object",
      "x-description-zh": "申请时的筛选条件(同列表查询参数)。",
      "x-gocdn-type": "AccessLogExportFilter"
     },
     "findings": {
      "description": "Checks with problems (passed checks are not listed), in check order.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CheckupFinding"
      },
      "type": "array",
      "x-description-zh": "有问题的检查项(通过的项不列出),按检查项顺序。"
     },
     "finished_at": {
      "description": "Completion time.",
      "type": "string",
      "x-description-zh": "完成时刻。"
     },
     "first_seen": {
      "description": "When this problem began in its current run; omitted for the first checkup and for results saved before this was recorded.",
      "type": "string",
      "x-description-zh": "该问题本轮连续出现的起点;首次体检、旧结果没记的不返回。"
     },
     "first_seen_at": {
      "description": "Time of the earliest access log in the retention period; absent when there is none.",
      "type": "string",
      "x-description-zh": "保留期内最早一条访问日志的时间;没有记录时不回。"
     },
     "flows": {
      "description": "Attack flows top 50 (source country to the country and city of the node that took the traffic, blocked and challenged requests scaled by sampling weight), descending; the rest and nodes at unknown locations are merged into one trailing row with an empty node_country (not drawn); the total equals the total of countries. Part of WAF Enhanced, an empty array when it is off; only data written after the flow table was created is counted, so older windows are empty.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityFlow"
      },
      "type": "array",
      "x-description-zh": "攻击流向 Top 50(来源国 → 节点所在国家/城市,被拦截与被挑战的请求数,按采样权重折算),次数降序;其余与位置未知的节点合并成排在最后的一条 node_country 为空串的「其他」行(不画);总和等于 countries 的总和。属 WAF 增强,未开通时为空数组;只收流向表建好之后写入的数据,更早的时间窗为空。"
     },
     "foreign": {
      "description": "Requests from outside mainland China (known country other than CN); excluded from the ISP breakdown.",
      "type": "integer",
      "x-description-zh": "中国大陆以外(已识别国家且不是 CN)的请求数;运营商分布不含这部分。"
     },
     "frequency": {
      "description": "Frequency: daily at 03:00, weekly on Monday at 03:00, or manual only.",
      "enum": [
       "daily",
       "weekly",
       "manual"
      ],
      "type": "string",
      "x-description-zh": "检查频率:每天 03:00、每周一 03:00、仅手动。"
     },
     "geo_summary": {
      "description": "Summary for the region dimensions (country, prov, isp) over the whole time window and the same filters, not limited by the number of ranked rows.",
      "type": "object",
      "x-description-zh": "地区维度(country、prov、isp)的汇总,按整个时间窗与同样的筛选条件统计,不受榜单行数限制。",
      "x-gocdn-type": "TopGeoSummary"
     },
     "handled_by_feature": {
      "description": "Requests handled by replacing content - leak and tamper protection rewrite the response body, keep the status code and are recorded as pass, so they are not blocks and are in neither blocked_by_feature nor summary.blocked, and should not enter block percentages. Only features with a count above 0 are listed, descending by count then leak before tamper; an empty array when there is no data (including before nodes tag body replacement), which the UI uses to hide it. Scaled by sampling weight and follows the time window and site scope.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityHandledCount"
      },
      "type": "array",
      "x-description-zh": "已处理(替换内容)次数:防泄露、防篡改在响应体上替换内容,状态码不变、记为放行,不算拦截,所以不进 blocked_by_feature 也不进 summary.blocked,也不应算拦截百分比。只列次数大于 0 的功能,次数降序、同次数先 leak 后 tamper;没有数据(含节点尚未给换体打标)返回空数组,前端据此隐藏。同样按采样权重折算,随时间窗与网站范围。"
     },
     "headers": {
      "description": "First 20 request headers as \"lowercase-name: value\", values cut to 256 bytes; Cookie and Authorization values are masked.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "前 20 个请求头,每个「小写名: 值」,值截取 256 字节;Cookie 与 Authorization 类只留名。"
     },
     "history": {
      "description": "Scores of this site over the last 8 weeks.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CheckupHistoryPoint"
      },
      "type": "array",
      "x-description-zh": "该网站近 8 周得分。"
     },
     "hit_layer": {
      "description": "Upload scan layer that matched; empty when nothing matched.",
      "type": "string",
      "x-description-zh": "上传扫描命中层;没命中为空。"
     },
     "host": {
      "description": "Requested Host.",
      "type": "string",
      "x-description-zh": "请求的 Host。"
     },
     "http2": {
      "description": "Number of sites by switch state of a protocol (on, off, unset).",
      "type": "object",
      "x-description-zh": "某项协议开关的站点数分布(开启、关闭、未设置)。",
      "x-gocdn-type": "ProtocolSwitch"
     },
     "http3": {
      "description": "Number of sites by switch state of a protocol (on, off, unset).",
      "type": "object",
      "x-description-zh": "某项协议开关的站点数分布(开启、关闭、未设置)。",
      "x-gocdn-type": "ProtocolSwitch"
     },
     "http_ver": {
      "description": "HTTP protocol version (HTTP/x.y normalized to 1.0, 1.1, 2, 3).",
      "type": "string",
      "x-description-zh": "HTTP 协议版本(HTTP/x.y 归一为 1.0、1.1、2、3)。"
     },
     "https_off": {
      "description": "Number of sites with HTTPS disabled.",
      "type": "integer",
      "x-description-zh": "未开启 HTTPS 的站点数。"
     },
     "https_on": {
      "description": "Number of sites with HTTPS enabled.",
      "type": "integer",
      "x-description-zh": "开启 HTTPS 的站点数。"
     },
     "id": {
      "description": "Record ID",
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "intel_hit": {
      "description": "Whether the IP is currently in the platform high-risk IP library (looked up against the current library); null = the library is not being served, not judged.",
      "type": "boolean",
      "x-description-zh": "该 IP 当前是否在平台高危 IP 库(按当前库现查);null = 库没在下发,未判定。"
     },
     "interval": {
      "description": "Bucket width in seconds.",
      "type": "integer",
      "x-description-zh": "桶宽(秒)。"
     },
     "invalid": {
      "description": "Number of sites whose configuration cannot be parsed or whose switch value is not a boolean.",
      "type": "integer",
      "x-description-zh": "配置解不开或开关取值不是布尔的站点数。"
     },
     "ip": {
      "description": "The address looked up (canonical form).",
      "type": "string",
      "x-description-zh": "查询的地址(规范写法)。"
     },
     "isp": {
      "description": "Client ISP code; omitted when unknown.",
      "type": "string",
      "x-description-zh": "客户端运营商编号;未识别不回。"
     },
     "isps": {
      "description": "Requests per ISP in mainland China, descending (empty key = ISP unknown).",
      "items": {
       "type": "object",
       "x-gocdn-type": "GeoCount"
      },
      "type": "array",
      "x-description-zh": "中国大陆各运营商请求数,从多到少(key 为空 = 运营商未识别)。"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "CheckupHistoryPoint"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "ja4": {
      "description": "Client TLS fingerprint JA4 (computed by the node during the TLS handshake, same for all requests on a connection); omitted for plain HTTP or when unavailable.",
      "type": "string",
      "x-description-zh": "客户端 TLS 指纹 JA4(节点在 TLS 握手时算,同连接各请求相同);明文 HTTP 或取不到不回。"
     },
     "keys": {
      "description": "Check keys.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "检查项键。"
     },
     "kind": {
      "description": "Site kind: domain (domain site) or ip (IP site); they have different edit pages.",
      "enum": [
       "domain",
       "ip"
      ],
      "type": "string",
      "x-description-zh": "站点类型:domain 域名站、ip IP 站(编辑页不同)。"
     },
     "last_seen": {
      "description": "Most recent minute it appeared.",
      "type": "string",
      "x-description-zh": "最近出现的分钟。"
     },
     "last_seen_at": {
      "description": "Time of the latest access log in the retention period; absent when there is none.",
      "type": "string",
      "x-description-zh": "保留期内最近一条访问日志的时间;没有记录时不回。"
     },
     "level": {
      "description": "Protection level of the site at the time: basic, standard or strict.",
      "type": "string",
      "x-description-zh": "命中时站点的防护等级:basic / standard / strict。"
     },
     "limit": {
      "description": "Requests allowed per day (reports.access_log_export_daily; 0 = downloads not allowed).",
      "type": "integer",
      "x-description-zh": "每天可申请的次数(reports.access_log_export_daily;0 = 不许下载)。"
     },
     "max": {
      "description": "bandwidth, backend_bandwidth: peak 5-minute bandwidth in the time window.",
      "type": "number",
      "x-description-zh": "bandwidth、backend_bandwidth:时间窗内 5 分钟带宽峰值。"
     },
     "medium": {
      "description": "Number of medium problems.",
      "type": "integer",
      "x-description-zh": "中等问题数。"
     },
     "message": {
      "description": "Legacy note (action and score) kept for older clients; build texts from type, action and category instead.",
      "type": "string",
      "x-description-zh": "兼容旧版的说明串(处置与累计分),新界面用 type/action/category 自行组文案。"
     },
     "method": {
      "description": "HTTP request method.",
      "type": "string",
      "x-description-zh": "HTTP 请求方法。"
     },
     "metrics": {
      "description": "Curves of each metric, in request order.",
      "items": {
       "type": "object",
       "x-gocdn-type": "NodeRealtimeMetric"
      },
      "type": "array",
      "x-description-zh": "各指标的曲线,顺序同请求。"
     },
     "name": {
      "description": "Site name.",
      "type": "string",
      "x-description-zh": "网站名称。"
     },
     "next_retry_at": {
      "description": "When the next retry starts (only for pending requests waiting to retry after a failure).",
      "type": "string",
      "x-description-zh": "下次重试时刻(失败后等退避重试的 pending 申请才有)。"
     },
     "node_city": {
      "description": "City of the node that reported it; empty when only the country is known or the location is unknown.",
      "type": "string",
      "x-description-zh": "上报的节点所在城市名;只知道国家、没有城市或位置未知时为空串。"
     },
     "node_id": {
      "description": "ID of the node that served the request.",
      "type": "integer",
      "x-description-zh": "处理该请求的节点 ID。"
     },
     "node_ids": {
      "description": "Nodes that reported it (up to 50, ascending).",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "上报过它的节点(最多 50 个,升序)。"
     },
     "node_ips": {
      "description": "Public addresses of the nodes in the site's own line groups (deduplicated and sorted, at most 500; private or management egress addresses are never listed); allow-listing them on the origin firewall restricts access to the CDN. Returned only when the origin-direct problem exists, otherwise an empty array.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "该网站实际调度到的线路分组内节点的对外地址(去重排序,最多 500 个;内网/管理出口地址不出),源站防火墙放行它们即可只允许经 CDN 访问;仅在有「源站可被直连」问题时返回,否则为空数组。"
     },
     "node_lat": {
      "description": "Latitude of the node's landing point, as for node_lon.",
      "type": "number",
      "x-description-zh": "节点落点纬度,含义同 node_lon。"
     },
     "node_lon": {
      "description": "Longitude of the node's landing point (the city, or the country centroid when there is no city); absent when the location is unknown.",
      "type": "number",
      "x-description-zh": "节点落点经度(城市坐标,没有城市时为国家质心);位置未知时没有此字段。"
     },
     "node_names": {
      "description": "Node names in the same order as node_ids; \"#\u003cid\u003e\" if a node has no name or was deleted.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "与 node_ids 同序的节点名;节点没名字或已删为 \"#\u003cid\u003e\"。"
     },
     "node_spots": {
      "description": "Node landing points (country and city to the number of nodes in use), administrators only and always an empty array for tenants; same basis as the flows landing points (enabled primary nodes, nodes at unknown locations are not counted); independent of whether WAF Enhanced is on, the time window and site_id; descending by node count, then by country and city.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityNodeSpot"
      },
      "type": "array",
      "x-description-zh": "节点落点分布(落点国家/城市 → 在用节点台数),仅管理员返回,租户恒为空数组;口径同 flows 的落点(启用的主节点、位置未知的不计),不随 WAF 增强开通与否、时间窗或 site_id 变化;台数降序,同台数按国家、城市升序。"
     },
     "node_unknown": {
      "description": "Number of nodes in use whose location is unknown (enabled primary nodes whose country cannot be determined, not counted in node_spots); administrators only, the field is absent from tenant responses; independent of whether WAF Enhanced is on, the time window and site_id.",
      "type": "integer",
      "x-description-zh": "位置未知的在用节点台数(启用的主节点里国家定不下来的,不在 node_spots 中),仅管理员返回,租户响应不含该字段;不随 WAF 增强开通与否、时间窗或 site_id 变化。"
     },
     "nodes": {
      "description": "Number of nodes that reported it.",
      "type": "integer",
      "x-description-zh": "上报过它的节点数。"
     },
     "notify_critical": {
      "description": "Raise an alert when a critical problem appears (uses the channels in alert settings).",
      "type": "boolean",
      "x-description-zh": "出现严重问题时告警(用告警设置里的渠道)。"
     },
     "observe": {
      "description": "The site was in observe mode at the time (record only).",
      "type": "boolean",
      "x-description-zh": "站点当时在观察期(只记录不处置)。"
     },
     "observe_rule": {
      "description": "true = the hit was a new rule still in its observation period, recorded only and not blocked (observe is then also true); emergency rules have no observation period, so always false.",
      "type": "boolean",
      "x-description-zh": "true = 命中的是观察期内的新规则,只记录没有拦(此时 observe 也为 true);应急规则无观察期,恒为 false。"
     },
     "op": {
      "description": "add puts keys on the ignore list (existing ones are untouched); remove takes them off.",
      "enum": [
       "add",
       "remove"
      ],
      "type": "string",
      "x-description-zh": "add 补上 keys(已有的不动);remove 去掉 keys。"
     },
     "open_url": {
      "description": "Clickable address of this request (the log's own scheme + host + non-default port + path and query); only http/https with a valid domain or IP and shorter than 2048 characters, otherwise omitted.",
      "type": "string",
      "x-description-zh": "这条请求的可点开地址(该条日志自己的协议 + 域名 + 非默认端口 + 路径与查询串);只放 http/https、域名或 IP 合法、长度不到 2048 的,否则不回。"
     },
     "other": {
      "description": "The rest: log, mask or replace outside observe mode.",
      "type": "integer",
      "x-description-zh": "其余(非观察的 log、mask、replace)。"
     },
     "p95": {
      "description": "bandwidth, backend_bandwidth: 95th percentile (5-minute samples for interval=5m, hourly peaks otherwise; only samples with data; the (n×5/100+1)-th largest, equal to the peak when n=1).",
      "type": "number",
      "x-description-zh": "bandwidth、backend_bandwidth:95 值(interval=5m 按 5 分钟带宽、否则按小时峰值;只算有数据的样本,降序第 n×5/100+1 个,n=1 时等于峰值)。"
     },
     "param": {
      "description": "Name of the matched parameter, header or cookie; empty for unnamed locations.",
      "type": "string",
      "x-description-zh": "命中的参数名/请求头名/Cookie 名;无名部位为空。"
     },
     "params": {
      "description": "Numbers and names for display, same as params of this check in the checkup result (including open_url).",
      "type": "object",
      "x-description-zh": "展示用的数字与名称,同体检结果里该项的 params(含 open_url)。"
     },
     "path": {
      "description": "Limit to this path prefix; must equal the event URL path or be a prefix ending in / (e.g. /api/); a bare / must be combined with a rule or parameter. Omit for any path.",
      "type": "string",
      "x-description-zh": "仅限该路径前缀;须等于事件 URL 路径,或是以 / 结尾的前缀(如 /api/);单独的 / 须同时选规则号或参数。不给 = 不限路径。"
     },
     "points": {
      "description": "Attack trend; the bucket width follows the time span (about 288 points at most) and empty buckets are zero.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityPoint"
      },
      "type": "array",
      "x-description-zh": "攻击趋势;桶宽随时间跨度自动取(约 288 个点以内),空桶补 0。"
     },
     "prefix_len": {
      "description": "32 (IPv4) or 64 (IPv6).",
      "type": "integer",
      "x-description-zh": "32(IPv4)或 64(IPv6)。"
     },
     "prev_score": {
      "description": "Score of the previous checkup; null for the first checkup.",
      "type": "integer",
      "x-description-zh": "上一次体检得分;第一次体检为 null。"
     },
     "previous": {
      "description": "Comparison with the previous window of the same length.",
      "type": "object",
      "x-description-zh": "上一同长时间窗的对照。"
     },
     "probes": {
      "description": "Rows of the last 7 days of probing that do not come from WAF events (CC cut, origin 404); blocked / logged rows are aggregated by the panel from WAF events.",
      "items": {
       "type": "object",
       "x-gocdn-type": "CheckupProbeExtra"
      },
      "type": "array",
      "x-description-zh": "近 7 天被探测里 WAF 事件之外的行(CC 已断开、源站返回 404);已拦截 / 只记录行由面板按 WAF 事件聚合。"
     },
     "progress": {
      "description": "Progress percentage (rows written / total rows).",
      "type": "integer",
      "x-description-zh": "进度百分比(已写行数 / 总行数)。"
     },
     "protocol": {
      "description": "HTTP version, e.g. HTTP/2.0.",
      "type": "string",
      "x-description-zh": "HTTP 版本,如 HTTP/2.0。"
     },
     "prov": {
      "description": "Client province (first two digits of GB/T 2260, mainland China only); omitted when unknown.",
      "type": "string",
      "x-description-zh": "客户端归属省份(GB/T 2260 前两位,仅中国大陆);未识别不回。"
     },
     "province": {
      "description": "Province; empty when unknown.",
      "type": "string",
      "x-description-zh": "省份;未识别时为空。"
     },
     "provinces": {
      "description": "Attack source provinces in mainland China (blocked and challenged requests scaled by sampling weight), descending; requests with an unknown province are left out.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityProvinceCount"
      },
      "type": "array",
      "x-description-zh": "中国大陆攻击来源省份(被拦截与被挑战的请求数,按采样权重折算),次数降序;省份未识别的不列。"
     },
     "provs": {
      "description": "Requests per mainland China province, descending (empty key = province unknown).",
      "items": {
       "type": "object",
       "x-gocdn-type": "GeoCount"
      },
      "type": "array",
      "x-description-zh": "中国大陆各省请求数,从多到少(key 为空 = 省份未识别)。"
     },
     "publish_seq": {
      "description": "Publish sequence number triggered (when result = added).",
      "type": "integer",
      "x-description-zh": "触发的重发布序号(result = added 时)。"
     },
     "reason_args": {
      "description": "Parameters of the basis text (id site/cert id, at deletion time, domain the similar site domain, n differing characters, names node names, cname, ip, nodes, count).",
      "type": "object",
      "x-description-zh": "依据文案的参数(id 站点/证书 id、at 删除时间、domain 近似的站点域名、n 相差字符数、names 节点名、cname、ip、nodes、count)。"
     },
     "reason_code": {
      "description": "Basis of the kind (message code; the panel renders the text per language): site_unsynced the site still",
      "enum": [
       "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"
      ],
      "type": "string",
      "x-description-zh": "判定依据(文案码,面板按语言出文案):site_unsynced 站点仍在但节点没有它的配置、site_disabled 站点已停用、"
     },
     "recent": {
      "description": "Events from the same IP in the past hour (total, rule breakdown, latest items).",
      "type": "object",
      "x-description-zh": "同一 IP 近 1 小时的事件(总数、命中规则分布、最近若干条)。",
      "x-gocdn-type": "WafEventRecent"
     },
     "referer": {
      "description": "Request Referer header.",
      "type": "string",
      "x-description-zh": "请求的 Referer。"
     },
     "referer_open_url": {
      "description": "Clickable address of the Referer; omitted when it is not an http/https page (such as javascript: or android-app://), is malformed, or is 2048 characters or longer.",
      "type": "string",
      "x-description-zh": "来源页的可点开地址;来源不是 http/https 页面(如 javascript:、android-app://)、地址不合法或长达 2048 字符以上时不回。"
     },
     "region_logged": {
      "description": "Requests matching a log-only region limit (not blocked).",
      "type": "integer",
      "x-description-zh": "命中「只记录」地区限制(未拦截)的请求数。"
     },
     "remaining": {
      "description": "Requests still available today.",
      "type": "integer",
      "x-description-zh": "今天还能申请的次数。"
     },
     "request_id": {
      "description": "Request ID.",
      "type": "string",
      "x-description-zh": "请求 ID。"
     },
     "request_length": {
      "description": "Request length in bytes.",
      "type": "integer",
      "x-description-zh": "请求长度,字节。"
     },
     "request_time_ms": {
      "description": "Request processing time in milliseconds.",
      "type": "integer",
      "x-description-zh": "请求处理耗时,毫秒。"
     },
     "reset": {
      "description": "true clears the override and returns to automatic detection (name and version are ignored).",
      "type": "boolean",
      "x-description-zh": "true = 撤销人工改写、回到自动识别(此时忽略 name 与 version)。"
     },
     "result": {
      "description": "added; exists = the site already has the same exception, nothing added; full = the exception list is full, nothing added.",
      "enum": [
       "added",
       "exists",
       "full"
      ],
      "type": "string",
      "x-description-zh": "added 已添加;exists 本站已有相同例外,未重复添加;full 本站例外已满,未添加。"
     },
     "retries": {
      "description": "Number of failed attempts; when pending or running and above 0 the request is on retry N.",
      "type": "integer",
      "x-description-zh": "已失败次数;pending/running 且大于 0 即在第 N 次重试。"
     },
     "rule": {
      "default": false,
      "description": "Skip only the matched rule (rule_ids); not allowed for non-rule events (rule id 0) or semantic events.",
      "type": "boolean",
      "x-description-zh": "仅跳过事件命中的这条规则(rule_ids);非规则类事件(规则号 0)与语义事件不能勾。"
     },
     "rule_id": {
      "description": "ID of the rule that matched.",
      "type": "integer",
      "x-description-zh": "命中的规则 ID。"
     },
     "rule_name": {
      "description": "Short rule name.",
      "type": "string",
      "x-description-zh": "规则短名。"
     },
     "rules_ver": {
      "description": "Rule pack version; empty means the built-in rules.",
      "type": "string",
      "x-description-zh": "规则库版本;空 = 节点内置规则。"
     },
     "run": {
      "description": "The batch in progress; omitted when there is none.",
      "type": "object",
      "x-description-zh": "进行中的批次;没有时缺省。"
     },
     "sample_factor": {
      "description": "Sampling factor N (the largest sample_weight in the access logs read); 1 when not sampled.",
      "type": "integer",
      "x-description-zh": "采样倍数 N(所读访问日志的最大 sample_weight);未采样为 1。"
     },
     "sample_weight": {
      "description": "Sampling weight (1 means not sampled).",
      "type": "integer",
      "x-description-zh": "采样权重(1 = 未采样)。"
     },
     "sampled": {
      "description": "The access logs read contain sampled rows (sample_weight \u003e 1); counts are scaled by weight and incomplete.",
      "type": "boolean",
      "x-description-zh": "所读访问日志里有采样行(sample_weight \u003e 1),计数按权重折算、结果不完整。"
     },
     "saved_bytes": {
      "description": "Origin traffic saved (bytes) - bytes sent to clients by requests served from cache and not blocked in the window, scaled by sampling weight.",
      "type": "integer",
      "x-description-zh": "省下的回源流量(字节):时间窗内命中缓存、未被拦截的请求发给客户端的字节数,按采样权重折算。"
     },
     "scan_status": {
      "description": "Upload scan result (type = upload); empty for other types.",
      "type": "string",
      "x-description-zh": "上传扫描结果(type = upload);其他类型为空。"
     },
     "scan_steps": {
      "description": "Upload scan steps in order, one \"layer:result\" per layer.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "上传扫描过程,按序每层一项「层:结果」。"
     },
     "scheme": {
      "description": "Request scheme (http or https).",
      "type": "string",
      "x-description-zh": "请求协议(http 或 https)。"
     },
     "score": {
      "description": "Checkup score (100 at most).",
      "type": "integer",
      "x-description-zh": "体检得分(满分 100)。"
     },
     "series": {
      "description": "Time series grouped by sub-object.",
      "items": {
       "type": "object",
       "x-gocdn-type": "LabeledLine"
      },
      "type": "array",
      "x-description-zh": "按子对象分组的时间序列。"
     },
     "server_port": {
      "description": "Port the request arrived on.",
      "type": "integer",
      "x-description-zh": "请求到达的端口。"
     },
     "severity": {
      "description": "Severity of this problem on this site.",
      "enum": [
       "critical",
       "medium",
       "advice"
      ],
      "type": "string",
      "x-description-zh": "该问题在这个网站上的严重程度。"
     },
     "site_deleted": {
      "description": "true when the site this log belongs to has been deleted; omitted when the site still exists (or there is none).",
      "type": "boolean",
      "x-description-zh": "这条日志所属的网站已被删除时为 true;网站仍在(或没有所属网站)不回。"
     },
     "site_id": {
      "description": "Site ID",
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "site_ids": {
      "description": "Sites to process, at most 500.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要处理的网站,最多 500 个。"
     },
     "site_name": {
      "description": "Name of the site it belongs to (primary domain, or the site name when it has none); for a deleted site the domain recorded when it was deleted, else the most common host in the last 7 days of access logs, omitted when none is found.",
      "type": "string",
      "x-description-zh": "所属站点名称(主域名,没有域名用站点名);站点已删取删除时审计里的域名,审计里没有再取近 7 天访问日志里最常见的域名,都没有则不回。"
     },
     "snippet": {
      "description": "Matched snippet (masked on the node; the value of the matched parameter or header). The list cuts it to the first 200 characters and the detail returns it whole. It carries no match offset, so it cannot be used to locate a highlight. For Bot events it is the triggering signal names.",
      "type": "string",
      "x-description-zh": "命中片段(节点已脱敏,命中参数或请求头的值);列表截取前 200 个字符,详情给完整。片段不带命中位置,不能据此定位高亮。Bot 事件为触发的信号名。"
     },
     "source_ips": {
      "description": "Distinct source addresses.",
      "type": "integer",
      "x-description-zh": "来源 IP 去重数。"
     },
     "stage": {
      "description": "Current stage: 0 queued, 1 reading configuration, 2 counting logs, 3 direct probe, 4 per-check evaluation, 5 saving and alerting. With more than 200 sites the stage restarts for every batch of 200; evaluation is instantaneous on the server.",
      "type": "integer",
      "x-description-zh": "当前阶段:0 排队,1 读取配置,2 统计日志,3 直连探测,4 逐项判定,5 保存并告警。站点多于 200 个时每 200 个一批,阶段号随批循环;逐项判定在后端是瞬时的。"
     },
     "started_at": {
      "description": "Time the batch was created.",
      "type": "string",
      "x-description-zh": "批次建立时刻。"
     },
     "state": {
      "description": "State: pending, running, done, or failed after retries are exhausted.",
      "enum": [
       "pending",
       "running",
       "done",
       "failed"
      ],
      "type": "string",
      "x-description-zh": "状态:pending 排队,running 运行,done 完成,failed 重试耗尽失败。"
     },
     "status": {
      "description": "Status: pending, running, done (downloadable), failed, or expired (file removed after the retention period).",
      "enum": [
       "pending",
       "running",
       "done",
       "failed",
       "expired"
      ],
      "type": "string",
      "x-description-zh": "状态:pending 排队、running 导出中、done 可下载、failed 失败、expired 文件已过保留期被清理。"
     },
     "step": {
      "description": "Bucket width of series, in seconds.",
      "type": "integer",
      "x-description-zh": "series 的桶宽(秒)。"
     },
     "summary": {
      "description": "Per-stage volume summary; a stage's key is absent until it is reached. Multi-batch tasks add up across batches.",
      "type": "object",
      "x-description-zh": "各阶段的处理量摘要;某阶段还没走到时该键缺省。多批任务按批累加。",
      "x-gocdn-type": "CheckupRunSummary"
     },
     "target": {
      "description": "Where it matched: uri, query_string, args, args_names, cookies, headers, body, ...",
      "type": "string",
      "x-description-zh": "命中位置:uri / query_string / args / args_names / cookies / headers / body 等。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID of the site.",
      "type": "integer",
      "x-description-zh": "站点所属租户(用户)ID。"
     },
     "top_rules": {
      "description": "Top 10 matched rules (by hits, descending).",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityRuleCount"
      },
      "type": "array",
      "x-description-zh": "命中规则 Top 10(按命中次数降序)。"
     },
     "top_sites": {
      "description": "Top 10 attacked sites (by blocked and challenged requests, descending).",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecuritySiteCount"
      },
      "type": "array",
      "x-description-zh": "被攻击网站 Top 10(按拦截与挑战数降序)。"
     },
     "total": {
      "description": "Requests in the time window (scaled by sampling weight).",
      "type": "integer",
      "x-description-zh": "时间窗内请求数(按采样权重折算)。"
     },
     "total_rows": {
      "description": "Total matching rows (counted when the export starts).",
      "type": "integer",
      "x-description-zh": "符合筛选的总行数(开始导出时统计)。"
     },
     "total_sites": {
      "description": "Number of sites in this batch; may still be 0 while queued.",
      "type": "integer",
      "x-description-zh": "本批次要体检的网站数;排队中可能还是 0。"
     },
     "totals": {
      "description": "Totals over the time window.",
      "type": "object",
      "x-description-zh": "时间窗内合计。",
      "x-gocdn-type": "SitesOverviewTotals"
     },
     "traffic_month": {
      "description": "Month-to-date outbound bytes, from the 1st of the month containing end (Asia/Shanghai) up to end; sealed hours come from the 5-minute summary, later ones from live data.",
      "type": "integer",
      "x-description-zh": "本月累计流量(出口字节):end 所在月 1 日 0 点(Asia/Shanghai)到 end;已封账的小时取 5 分钟汇总,其后取实时数据。"
     },
     "traffic_today": {
      "description": "Today's outbound bytes, from midnight (Asia/Shanghai) of the day containing end up to end; same scope as totals.traffic.",
      "type": "integer",
      "x-description-zh": "今日流量(出口字节):end 所在日的 0 点(Asia/Shanghai)到 end;口径同 totals.traffic(含不含未配置流量随 include_noconfig)。"
     },
     "ts": {
      "description": "Request time.",
      "type": "string",
      "x-description-zh": "请求时刻。"
     },
     "type": {
      "description": "Event type: rule, semantic, bot, upload scan, tamper protection or leak protection.",
      "enum": [
       "waf",
       "semantic",
       "bot",
       "upload",
       "tamper",
       "leak"
      ],
      "type": "string",
      "x-description-zh": "事件类型:规则 / 语义 / Bot / 上传扫描 / 防篡改 / 防泄露。"
     },
     "types": {
      "description": "Attack type distribution (WAF event hits by type), descending by count.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SecurityTypeCount"
      },
      "type": "array",
      "x-description-zh": "攻击类型分布(WAF 事件按类型折算命中次数),次数降序。"
     },
     "unavailable": {
      "description": "Supplementary items that could not be loaded this time (only present when the rule store or ClickHouse failed briefly; everything else is returned as usual and the missing items come back empty). coverage = covered / extra, probes = probes, node_ips = node_ips. Absent when everything loaded.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "本次没取到的补充项(规则库或 ClickHouse 暂时读失败时才有;其余内容照常返回,取不到的项按空值给)。coverage = covered / extra,probes = probes,node_ips = node_ips。缺省 = 全部取到。"
     },
     "unknown": {
      "description": "Requests whose country is unknown (no database, private address or not in the database).",
      "type": "integer",
      "x-description-zh": "归属国家未识别的请求数(无库、内网或库里没有)。"
     },
     "unlimited": {
      "description": "true = no daily cap (administrators); limit and remaining are then absent.",
      "type": "boolean",
      "x-description-zh": "true = 不限次数(管理员),此时不给 limit / remaining。"
     },
     "upid": {
      "description": "Origin (upstream) ID the request went to.",
      "type": "integer",
      "x-description-zh": "回源的源站 ID。"
     },
     "upstream_addr": {
      "description": "Origin address:port actually used; comma-separated hops when retried on another origin; empty when not fetched from origin.",
      "type": "string",
      "x-description-zh": "回源实际连的源站「地址:端口」;换源站重试时逗号分隔多跳;未回源为空。"
     },
     "upstream_bytes": {
      "description": "Bytes received from the origin.",
      "type": "integer",
      "x-description-zh": "从源站收到的字节数。"
     },
     "upstream_status": {
      "description": "Status code returned by each origin hop, matching upstream_addr; empty when not fetched from origin.",
      "type": "string",
      "x-description-zh": "各跳源站回的状态码,与 upstream_addr 逐跳对应;未回源为空。"
     },
     "upstream_time_ms": {
      "description": "Origin response time in milliseconds; null when not fetched from origin.",
      "type": "integer",
      "x-description-zh": "源站响应耗时,毫秒;未回源为 null。"
     },
     "uri": {
      "description": "Request URI including the query string.",
      "type": "string",
      "x-description-zh": "请求 URI(含查询串)。"
     },
     "url": {
      "description": "Request path and query string (masked).",
      "type": "string",
      "x-description-zh": "请求路径 + 查询串(已脱敏)。"
     },
     "used": {
      "description": "Requests created today.",
      "type": "integer",
      "x-description-zh": "今天已建成的申请数。"
     },
     "user_agent": {
      "description": "Request User-Agent header.",
      "type": "string",
      "x-description-zh": "请求的 User-Agent。"
     },
     "version": {
      "description": "Application version; may be left empty.",
      "type": "string",
      "x-description-zh": "程序版本;不知道可留空。"
     },
     "window_min": {
      "description": "Averaging window used, in minutes.",
      "type": "integer",
      "x-description-zh": "本次取均值的窗口(分钟)。"
     },
     "window_s": {
      "description": "Window length in seconds.",
      "type": "integer",
      "x-description-zh": "统计窗口秒数。"
     }
    },
    "type": "object"
   },
   "site-groups": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "site-ip-lists": {
    "properties": {
     "added": {
      "description": "Entries added.",
      "type": "integer",
      "x-description-zh": "新增条数。"
     },
     "applied": {
      "description": "Whether the import was saved (false for dry_run or when blocking issues exist).",
      "type": "boolean",
      "x-description-zh": "是否已保存(dry_run 或有挡导入的问题时为 false)。"
     },
     "black": {
      "description": "Permanent blacklist (a match = connection dropped); the count is limited by protect.black_ip_max.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "永久黑名单(命中 = 断开);条数受 protect.black_ip_max 约束。"
     },
     "black_items": {
      "description": "Blacklist entries with expiry, reason and source; expired entries are not returned.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListItem"
      },
      "type": "array",
      "x-description-zh": "黑名单条目(含到期时间、原因、来源);已到期的不返回。"
     },
     "block_denied": {
      "description": "Why it cannot be blacklisted: private (private/loopback/link-local), node (a node IP; admins only), self (the caller's own IP), other (any other reason; tenants get this for node IPs so node addresses are not revealed); omitted when allowed.",
      "enum": [
       "private",
       "node",
       "self",
       "other"
      ],
      "type": "string",
      "x-description-zh": "不能拉黑的原因:private 内网/回环/链路本地、node 节点 IP(只回管理员)、self 调用者自己的 IP、other 其他原因(租户遇到节点 IP 回这个,不暴露节点地址);能拉黑不回。"
     },
     "dry_run": {
      "default": false,
      "description": "true only checks the file and saves nothing.",
      "type": "boolean",
      "x-description-zh": "true 只预检,不保存。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (when the read updated_at is null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "expires_at": {
      "description": "Expiry time; empty = permanent. Must be in the future.",
      "type": "string",
      "x-description-zh": "到期时间;空 = 永久。须晚于当前时刻。"
     },
     "geo": {
      "description": "IP geolocation lookup result.",
      "type": "object",
      "x-description-zh": "IP 归属地查询结果。",
      "x-gocdn-type": "GeoipLookup"
     },
     "global_black": {
      "description": "IP list entry (in IP details, the entry that matches the IP; omitted when none matches).",
      "type": "object",
      "x-description-zh": "IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。",
      "x-gocdn-type": "IpListItem"
     },
     "global_white": {
      "description": "IP list entry (in IP details, the entry that matches the IP; omitted when none matches).",
      "type": "object",
      "x-description-zh": "IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。",
      "x-gocdn-type": "IpListItem"
     },
     "ip": {
      "description": "Normalized address (IPv4-mapped addresses shown as IPv4).",
      "type": "string",
      "x-description-zh": "规范化后的地址(IPv4 映射地址还原成 IPv4)。"
     },
     "issues": {
      "description": "Per-line issues (at most 1000, ascending by line).",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListImportIssue"
      },
      "type": "array",
      "x-description-zh": "逐行问题(最多 1000 条,按行号升序)。"
     },
     "lines": {
      "description": "Number of valid entries (after de-duplication).",
      "type": "integer",
      "x-description-zh": "有效条目数(去重后)。"
     },
     "list": {
      "description": "Which list to import into.",
      "enum": [
       "black",
       "white"
      ],
      "type": "string",
      "x-description-zh": "导入到哪张名单。"
     },
     "mode": {
      "default": "merge",
      "description": "merge adds to the current list (the imported row wins for the same IP); replace swaps the whole list for the imported rows.",
      "enum": [
       "merge",
       "replace"
      ],
      "type": "string",
      "x-description-zh": "merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。"
     },
     "reason": {
      "description": "Reason (note), at most 200 characters.",
      "type": "string",
      "x-description-zh": "原因(备注),最长 200 个字符。"
     },
     "removed": {
      "description": "In replace mode, existing entries that are not in the new list (entries with the same IP count as updated, not removed).",
      "type": "integer",
      "x-description-zh": "replace 模式下原有、新名单里没有的条数(同 IP 的算「更新」,不算在内)。"
     },
     "scope": {
      "description": "site = this site's list; global = the global list (admins only).",
      "enum": [
       "site",
       "global"
      ],
      "type": "string",
      "x-description-zh": "site 本站名单;global 全局名单(仅管理员)。"
     },
     "site_black": {
      "description": "IP list entry (in IP details, the entry that matches the IP; omitted when none matches).",
      "type": "object",
      "x-description-zh": "IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。",
      "x-gocdn-type": "IpListItem"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "site_white": {
      "description": "IP list entry (in IP details, the entry that matches the IP; omitted when none matches).",
      "type": "object",
      "x-description-zh": "IP 名单条目(IP 详情里是命中该 IP 的那一条,没命中不回)。",
      "x-gocdn-type": "IpListItem"
     },
     "task_id": {
      "description": "Id of the background task that pushes the change to nodes (poll progress with GET /tasks/{id}).",
      "type": "integer",
      "x-description-zh": "下发节点的后台任务 id(GET /tasks/{id} 查进度)。"
     },
     "text": {
      "description": "File content (txt/csv), one entry per line: IP/CIDR[,expiry][,reason].",
      "type": "string",
      "x-description-zh": "文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。"
     },
     "updated": {
      "description": "Entries already in the list that were updated by the import.",
      "type": "integer",
      "x-description-zh": "已在名单里、被导入行更新的条数。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "white": {
      "description": "Permanent whitelist (a match = CC and other protections are skipped); the count is limited by protect.white_ip_max.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "永久白名单(命中 = 跳过 CC 等防护);条数受 protect.white_ip_max 约束。"
     },
     "white_items": {
      "description": "Whitelist entries with expiry, reason and source; expired entries are not returned.",
      "items": {
       "type": "object",
       "x-gocdn-type": "IpListItem"
      },
      "type": "array",
      "x-description-zh": "白名单条目(含到期时间、原因、来源);已到期的不返回。"
     }
    },
    "type": "object"
   },
   "site-leak-guards": {
    "properties": {
     "custom": {
      "description": "Custom regular expressions, at most 16.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteLeakGuardCustom"
      },
      "type": "array",
      "x-description-zh": "自定义正则,最多 16 条。"
     },
     "detect": {
      "description": "Action per built-in pattern; omit a pattern to not check it.",
      "type": "object",
      "x-description-zh": "内置识别各类的处置;不写 = 不查这一类。",
      "x-gocdn-type": "SiteLeakGuardDetect"
     },
     "enabled": {
      "description": "Whether enabled.",
      "type": "boolean",
      "x-description-zh": "是否开启。"
     },
     "exclude": {
      "description": "Path prefixes that are not checked, at most 32.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "不检测的路径前缀,最多 32 条。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "gate": {
      "description": "WAF Enhanced status of the site's tenant: full = editable; readonly = expired but within the read-only buffer (License.readonly_days, 7 days by default), still in effect but read-only; basic = not subscribed or past the buffer, nothing checked and settings kept.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不检测、设置保留。"
     },
     "gate_expired_at": {
      "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
     },
     "gate_owner": {
      "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
      "x-gocdn-type": "WafGateOwner"
     },
     "gate_packages": {
      "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
     },
     "gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     },
     "observe_days": {
      "description": "Days observed after turning on.",
      "type": "integer",
      "x-description-zh": "新开启时观察的天数。"
     },
     "observe_until": {
      "description": "End of the observation period; null = not observing (never on, or 0 days chosen).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "观察期截止;为空 = 不在观察期(没开过或开时选了 0 天)。"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "source": {
      "description": "Where the site's setting comes from: scheme = follows the scheme (changes when the scheme is saved); custom = set for this site alone (including turned off and rows migrated from before).",
      "enum": [
       "scheme",
       "custom"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。",
      "x-gocdn-type": "ProtectSiteSource"
     },
     "updated_at": {
      "description": "Version (null if never set); use expected_updated_at on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "版本(没设过为空);修改时用 expected_updated_at。"
     }
    },
    "type": "object"
   },
   "site-replay-guards": {
    "properties": {
     "action": {
      "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
      "enum": [
       "block",
       "challenge"
      ],
      "type": "object",
      "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
      "x-gocdn-type": "ReplayGuardAction"
     },
     "app_salt": {
      "description": "Signing salt (app key, 32-byte hex); with app_sign on but no salt, signed headers are never accepted.",
      "example": "0000000000000000000000000000000000000000000000000000000000000000",
      "type": "string",
      "x-description-zh": "签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。"
     },
     "app_sign": {
      "description": "App signed-header mode - requests carrying the signature headers are checked by signature, no token needed.",
      "type": "boolean",
      "x-description-zh": "App 签名头模式:请求带签名头即按签名校验,不需要令牌。"
     },
     "bind_ip": {
      "description": "Also bind the token to the client IP (a new IP invalidates it).",
      "type": "boolean",
      "x-description-zh": "令牌再绑客户端 IP(换 IP 即失效)。"
     },
     "enabled": {
      "description": "Whether enabled.",
      "type": "boolean",
      "x-description-zh": "是否开启。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "gate": {
      "description": "WAF Enhanced status of the site's tenant: full = editable; readonly = expired but within the read-only buffer (License.readonly_days, 7 days by default), still in effect but read-only; basic = not subscribed or past the buffer, not in effect and settings kept.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不生效、设置保留。"
     },
     "gate_expired_at": {
      "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
     },
     "gate_owner": {
      "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
      "x-gocdn-type": "WafGateOwner"
     },
     "gate_packages": {
      "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
     },
     "gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     },
     "methods": {
      "description": "Protected methods; omitted = POST/PUT/PATCH/DELETE.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ReplayGuardMethod"
      },
      "type": "array",
      "x-description-zh": "受保护方法;不写 = POST/PUT/PATCH/DELETE。"
     },
     "paths": {
      "description": "Protected API paths, at most 64; empty = nothing protected.",
      "items": {
       "type": "object",
       "x-gocdn-type": "ReplayGuardPath"
      },
      "type": "array",
      "x-description-zh": "保护接口路径表,最多 64 条;空 = 不保护。"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "source": {
      "description": "Where the site's setting comes from: scheme = follows the scheme (changes when the scheme is saved); custom = set for this site alone (including turned off and rows migrated from before).",
      "enum": [
       "scheme",
       "custom"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。",
      "x-gocdn-type": "ProtectSiteSource"
     },
     "ttl_s": {
      "description": "Token lifetime in seconds, also used for signed-header timestamps; omitted = 120.",
      "type": "integer",
      "x-description-zh": "令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。"
     },
     "updated_at": {
      "description": "Version (null if never set); use expected_updated_at on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "版本(没设过为空);修改时用 expected_updated_at。"
     }
    },
    "type": "object"
   },
   "site-tamper-guards": {
    "properties": {
     "action": {
      "description": "Action on tampering.",
      "enum": [
       "restore",
       "log"
      ],
      "type": "string",
      "x-description-zh": "篡改时的处置。"
     },
     "assets": {
      "description": "JS/CSS whose fingerprint differs (recorded only, not replaced).",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteTamperAsset"
      },
      "type": "array",
      "x-description-zh": "指纹不符的 JS/CSS(只记录,不替换)。"
     },
     "base_at": {
      "description": "Baseline time (the last baseline update).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "基准时间(最近一次更新基准)。"
     },
     "base_ver": {
      "description": "Baseline version, +1 on every baseline update; 0 = no baseline yet.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "基准版本,每次更新基准 +1;0 = 还没有基准。"
     },
     "changes": {
      "description": "Structural changes (removed links and text changes are not listed).",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteTamperChange"
      },
      "type": "array",
      "x-description-zh": "结构变化(删掉的链接与正文变化不列)。"
     },
     "enabled": {
      "description": "Whether enabled.",
      "type": "boolean",
      "x-description-zh": "是否开启。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "fetch_error": {
      "description": "Why the page could not be fetched now (changes is then empty): fetch_failed = the origin did not return 200 or could not be reached; not_html = not a web page; too_large = over 1 MB. Absent when fetched.",
      "enum": [
       "fetch_failed",
       "not_html",
       "too_large"
      ],
      "type": "string",
      "x-description-zh": "现抓这一页没成的原因(此时 changes 为空):fetch_failed 源站非 200 或连不上;not_html 不是网页;too_large 超 1MB。抓到时不出。"
     },
     "gate": {
      "description": "WAF Enhanced status of the site's tenant: full = editable; readonly = expired but within the read-only buffer (License.readonly_days, 7 days by default), still in effect but read-only; basic = not subscribed or past the buffer, nothing checked and settings kept.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "站点租户的 WAF 增强判定档:full 可改;readonly 到期只读缓冲内(License.readonly_days,缺省 7 天)照常生效、设置只读;basic 没开通或缓冲已过,不检测、设置保留。"
     },
     "gate_expired_at": {
      "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
     },
     "gate_owner": {
      "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
      "x-gocdn-type": "WafGateOwner"
     },
     "gate_packages": {
      "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
     },
     "gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     },
     "mode": {
      "description": "What counts as tampering.",
      "enum": [
       "structure",
       "full"
      ],
      "type": "string",
      "x-description-zh": "检查范围。"
     },
     "observe_days": {
      "description": "Days observed after turning on.",
      "type": "integer",
      "x-description-zh": "新开启时观察的天数。"
     },
     "observe_until": {
      "description": "End of the observation period; null = not observing (never on, or 0 days chosen).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "观察期截止;为空 = 不在观察期(没开过或开时选了 0 天)。"
     },
     "pages": {
      "description": "Baseline pages (sorted by path), including scopes that were not included and why.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteTamperPage"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "基准页(按路径排序),含没纳入的保护范围与原因。"
     },
     "path": {
      "description": "Page path.",
      "type": "string",
      "x-description-zh": "页面路径。"
     },
     "scopes": {
      "description": "Protected scopes.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteTamperScope"
      },
      "type": "array",
      "x-description-zh": "保护范围。"
     },
     "site_id": {
      "description": "Site ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "网站 ID"
     },
     "source": {
      "description": "Where the site's setting comes from: scheme = follows the scheme (changes when the scheme is saved); custom = set for this site alone (including turned off and rows migrated from before).",
      "enum": [
       "scheme",
       "custom"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。",
      "x-gocdn-type": "ProtectSiteSource"
     },
     "tampered": {
      "description": "Whether this counts as tampering under the site's mode.",
      "type": "boolean",
      "x-description-zh": "按站点检查范围算不算篡改。"
     },
     "updated_at": {
      "description": "Version (null if never set); use expected_updated_at on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "版本(没设过为空);修改时用 expected_updated_at。"
     }
    },
    "type": "object"
   },
   "sites": {
    "properties": {
     "action": {
      "description": "Batch action: set_enabled, delete, set_groups, update_config or create.",
      "enum": [
       "set_enabled",
       "delete",
       "set_groups",
       "update_config",
       "create"
      ],
      "type": "string",
      "x-description-zh": "批量动作:set_enabled(启停)、delete(删除)、set_groups(设置分组)、update_config(合并配置)、create(批量新建)。"
     },
     "added_at": {
      "description": "When the entry was added; early manual entries have none.",
      "type": "string",
      "x-description-zh": "加入时间;早期手工条目没有。"
     },
     "affected": {
      "description": "Number of affected records",
      "type": "integer",
      "x-description-zh": "受影响的条数"
     },
     "app": {
      "description": "Filter by the application identified by the checkup (exact match).",
      "type": "string",
      "x-description-zh": "按体检识别出的程序精确过滤。"
     },
     "batch": {
      "description": "rec_type only - pass the batch returned by the first segment so all segments share one undo batch; omit to start a new batch.",
      "type": "string",
      "x-description-zh": "只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。"
     },
     "capacity_warnings": {
      "description": "Only in the responses of creating a site (POST /sites) and moving it to another line group (PUT /sites/{id}), when a node of the target line group has reached its memory capacity limit; a warning only, never blocks. Omitted when no node is over the limit.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteCapacityWarning"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "只在建站(POST /sites)与改到别的线路分组(PUT /sites/{id})的响应里、目标线路分组有节点站数已达内存容量上限时给出;只提示不拦截,没有超限节点时不给这个字段。"
     },
     "checked_at": {
      "description": "Time the details were requested from the nodes.",
      "type": "string",
      "x-description-zh": "本次向节点要明细的时间。"
     },
     "cname": {
      "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
      "type": "object",
      "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
      "x-gocdn-type": "CnameBinding"
     },
     "config": {
      "description": "Node config fields (top-level fields of schema/site.json, without id, uid, upid, domains, origins, enabled, stop_code and rulesets).",
      "type": "object",
      "x-description-zh": "节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。"
     },
     "country": {
      "description": "Country/region code, omitted if unknown.",
      "type": "string",
      "x-description-zh": "国家/地区编号,没有不给。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "default_pick": {
      "description": "The current default method (applies when l2_pick is null).",
      "enum": [
       "region",
       "near"
      ],
      "type": "string",
      "x-description-zh": "默认设置当前的方式(l2_pick 为 null 时生效)。"
     },
     "domain": {
      "description": "Filter by domain substring (case-insensitive).",
      "type": "string",
      "x-description-zh": "按域名子串过滤(不分大小写)。"
     },
     "domains": {
      "description": "Domains served by the site.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "站点绑定的域名。"
     },
     "edge_origin_requests": {
      "description": "Edge origin requests (hit rate denominator).",
      "type": "integer",
      "x-description-zh": "边缘回源请求数(命中率分母)。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "end": {
      "description": "Window end (exclusive, rounded to 5 minutes).",
      "type": "string",
      "x-description-zh": "窗口右端(不含,取整到 5 分钟)。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "found": {
      "description": "The IP was found in the database (otherwise judged as an unidentified visitor).",
      "type": "boolean",
      "x-description-zh": "库里查到了这个 IP(否则按未识别的访客判)。"
     },
     "gate_reasons": {
      "description": "The sites in ids whose WAF Enhanced is not in effect, grouped by reason (only sites with a reason are listed; the whole field is omitted when all are in effect). The picker uses package to mark sites as not covered by the plan and disable them.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "ids 里 WAF 增强没生效的站点按原因分组(只列有原因的;全都生效时整个字段不给)。选择器据此给 package 的站点标「套餐不含」并禁勾。",
      "x-gocdn-type": "SiteGateReasonIds"
     },
     "group_id": {
      "description": "Only sites in this group.",
      "type": "integer",
      "x-description-zh": "只取该分组里的站点。"
     },
     "group_ids": {
      "description": "Ids of the site groups the site belongs to.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "站点所属分组的 id。"
     },
     "group_options": {
      "description": "Custom L2 groups available.",
      "items": {
       "type": "object",
       "x-gocdn-type": "L2SiteRefGroup"
      },
      "type": "array",
      "x-description-zh": "可选的自建 L2 组。"
     },
     "hit_rate": {
      "description": "Hit rate 0-1; 0 when there were no origin requests.",
      "type": "number",
      "x-description-zh": "命中率 0–1;没有回源为 0。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
     },
     "ip": {
      "description": "The caller's IP.",
      "type": "string",
      "x-description-zh": "调用者的 IP。"
     },
     "isp": {
      "description": "ISP code, omitted if unknown.",
      "type": "string",
      "x-description-zh": "运营商编号,没有不给。"
     },
     "items": {
      "description": "Used by create: the sites to create (up to 100), each shaped like the POST /sites request body.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteWrite"
      },
      "type": "array",
      "x-description-zh": "create 用:要新建的站点(最多 100 个),每条同 POST /sites 的请求体。"
     },
     "key": {
      "description": "Key of the checkup problem to fix, same meaning as the single-site fix.",
      "enum": [
       "no_https",
       "tls_old",
       "sec_headers",
       "waf_block",
       "cc_mid",
       "rec_type"
      ],
      "type": "string",
      "x-description-zh": "要修复的体检项键,含义同单站一键修复。"
     },
     "l2_group_id": {
      "description": "L2 group used; null for region default.",
      "type": "integer",
      "x-description-zh": "使用的 L2 组;null = 区域默认。"
     },
     "l2_hit_requests": {
      "description": "Origin requests served by L2 (hit rate numerator).",
      "type": "integer",
      "x-description-zh": "L2 接住的回源请求数(命中率分子)。"
     },
     "l2_pick": {
      "description": "How L2 is picked for this site; null to follow the defaults.",
      "enum": [
       "region",
       "near"
      ],
      "type": "string",
      "x-description-zh": "本站选 L2 的方式;null = 跟默认设置。"
     },
     "log": {
      "description": "Protocol split, origin time percentiles, sampled cache-miss URLs and edge response times from the raw access log (weighted by sample weight), same window as totals.",
      "type": "object",
      "x-description-zh": "按原始访问日志(按采样权重折算)统计的协议分布、回源耗时分位、未命中地址抽样与边缘响应耗时,窗口同 totals。",
      "x-gocdn-type": "SiteSpeedLog"
     },
     "log_keep_days": {
      "description": "Raw access log retention in days (reports.access_log_days); when the window is longer, log only covers what is still kept.",
      "type": "integer",
      "x-description-zh": "原始访问日志保留天数(reports.access_log_days);窗口超出它时 log 只统计还留着的部分。"
     },
     "missing": {
      "description": "Selected fields the current database has no data for (those selections never match).",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "选了但当前库不含数据的字段(这些选择不会命中)。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_issues": {
      "description": "Ports or reasons for which the site is not fully in effect on online nodes (in the list and the detail); omitted when everything is in effect.",
      "items": {
       "type": "object",
       "x-gocdn-type": "NodeIssue"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "在线节点上站点没完全生效的口或原因(列表与详情里给);都正常时不给这个字段。"
     },
     "nodes": {
      "description": "Details from each active node, ordered by node id.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteHealthNode"
      },
      "type": "array",
      "x-description-zh": "各在用节点的明细(按节点 id 升序)。"
     },
     "observe_days": {
      "description": "Overrides the observe-first days of waf_mode in the table (0 blocks immediately); defaults to the table value.",
      "type": "integer",
      "x-description-zh": "覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。"
     },
     "origin": {
      "description": "Filter by origin host substring.",
      "type": "string",
      "x-description-zh": "按源站主机子串过滤。"
     },
     "origin_l2_only": {
      "description": "Origin allows only L2: dynamic requests also go via L2, borrowing other regions when needed.",
      "type": "boolean",
      "x-description-zh": "源站只允许 L2 访问:动态请求也经 L2,本区域没 L2 时借用其他区域。"
     },
     "origin_max_conns": {
      "description": "Max origin concurrency per node; 0 for unlimited. Excess requests queue instead of failing with 503.",
      "type": "integer",
      "x-description-zh": "源站最大并发(每节点在途);0 = 不限,超了排队不报 503。"
     },
     "origin_requests": {
      "description": "Requests that reached the origin.",
      "type": "integer",
      "x-description-zh": "实际到源站的请求数。"
     },
     "origin_requests_est": {
      "description": "Estimate without tiering (= edge origin requests).",
      "type": "integer",
      "x-description-zh": "未开分层时的估算(= 边缘回源请求数)。"
     },
     "origins": {
      "description": "Origin servers.",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteOrigin"
      },
      "type": "array",
      "x-description-zh": "源站列表。"
     },
     "path": {
      "description": "Path prefix (starting with /); defaults to /.",
      "type": "string",
      "x-description-zh": "路径前缀(以 / 开头);不给取 /。"
     },
     "points": {
      "description": "Per-bucket details (only buckets with traffic are listed).",
      "items": {
       "type": "object",
       "x-gocdn-type": "SiteSpeedPoint"
      },
      "type": "array",
      "x-description-zh": "按桶的明细(只列有流量的桶)。"
     },
     "prov": {
      "description": "Province code, omitted if unknown.",
      "type": "string",
      "x-description-zh": "省份编号,没有不给。"
     },
     "publish_seq": {
      "description": "Only in the responses of creating and updating a site: the sequence number of this write (same as the Publish-Seq response header); pass it to GET /config-publish/applied?seq= to check whether it has reached the nodes.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "只在建站、改站的响应里给:这次写操作的序号(同响应头 Publish-Seq),拿它调 GET /config-publish/applied?seq= 查是否已推到节点。"
     },
     "range": {
      "description": "Statistics window (1h, 24h or 7d).",
      "type": "string",
      "x-description-zh": "统计窗口(1h、24h 或 7d)。"
     },
     "rec_ver": {
      "description": "Version of the recommendation table used.",
      "type": "integer",
      "x-description-zh": "本次用的推荐表版本。"
     },
     "region_limit": {
      "description": "The region limit to check (same as Site.config.region_limit).",
      "type": "object",
      "x-description-zh": "要检查的地区限制(同 Site.config.region_limit)。"
     },
     "region_names": {
      "description": "Names of the regions with a serving L2, ordered by region ID; as many as regions.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "有可用 L2 的区域名,按区域 id 排;个数等于 regions。"
     },
     "regions": {
      "description": "Regions with a serving L2.",
      "type": "integer",
      "x-description-zh": "有可用 L2 的区域数。"
     },
     "revoked": {
      "description": "Revoked paths.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "已撤销的路径。"
     },
     "saved_bytes": {
      "description": "Origin traffic saved (bytes served from L2 cache).",
      "type": "integer",
      "x-description-zh": "省的回源流量(L2 命中字节)。"
     },
     "sha256": {
      "description": "sha256 of the hit file (lowercase hex); a tenant's value must appear in the site's upload hit events; if given, intelligence sharing is on and sig is not empty, a false-positive intelligence item is queued in the same transaction.",
      "type": "string",
      "x-description-zh": "命中文件的 sha256(小写十六进制);租户提交时须是本站上传命中事件里出现过的指纹;给了且情报共享开着、sig 非空时同事务内记一条误报情报待上报。"
     },
     "sig": {
      "description": "Signature name of the false positive (the rule name in the event); empty = the whole path is not scanned (path is then required).",
      "type": "string",
      "x-description-zh": "误报的特征名(事件规则名,如 webshell.php.eval);空 = 该路径整段不扫描(此时必须给 path)。"
     },
     "site_id": {
      "description": "Site id; 0 = all sites.",
      "type": "integer",
      "x-description-zh": "网站 id;0 = 所有网站。"
     },
     "skip": {
      "description": "Recommended items the user unticked and that must not be applied this time.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "用户取消勾选、本次不套用的推荐项。"
     },
     "source": {
      "description": "user chosen manually; auto detected from traffic.",
      "enum": [
       "user",
       "auto"
      ],
      "type": "string",
      "x-description-zh": "user 手选;auto 按流量自动判定。"
     },
     "start": {
      "description": "Window start.",
      "type": "string",
      "x-description-zh": "窗口起点。"
     },
     "state": {
      "description": "Effective state: on, off, not_open, paused, no_l2, or revoking.",
      "enum": [
       "on",
       "off",
       "not_open",
       "paused",
       "no_l2",
       "revoking"
      ],
      "type": "string",
      "x-description-zh": "生效状态:on 生效;off 网站没开;not_open 没开通(含网站所属租户的套餐不含分层回源);paused 全网暂停;no_l2 没有可用的 L2;revoking 生效中但即将停用。"
     },
     "status": {
      "description": "disabled = active health checks are off; unknown = no node returned details; healthy = all origins up on the nodes that answered; unhealthy = some origin is removed.",
      "type": "string",
      "x-description-zh": "disabled 没开主动健康检查;unknown 没有节点回明细;healthy 回了明细的节点上源站全部在线;unhealthy 有源站被摘除。"
     },
     "stop_code": {
      "description": "0 = normal; non-zero = every request is answered with this status code (set by admin or billing).",
      "type": "integer",
      "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "text": {
      "description": "Text in the requested format, ready to paste on the origin.",
      "type": "string",
      "x-description-zh": "按 fmt 排好的文本,可直接粘贴到源站。"
     },
     "total": {
      "description": "Actual number of matches (may exceed the length of ids).",
      "type": "integer",
      "x-description-zh": "真实命中数(可能大于 ids 的长度)。"
     },
     "totals": {
      "description": "Totals over the whole window.",
      "type": "object",
      "x-description-zh": "整个窗口的合计。",
      "x-gocdn-type": "SiteSpeedTotals"
     },
     "truncated": {
      "description": "True when more than 100000 sites matched and ids holds only the first 100000.",
      "type": "boolean",
      "x-description-zh": "命中数超过 100000,ids 只含前 100000 个。"
     },
     "type": {
      "description": "Site type - corporate, shop, content, api, admin or download.",
      "enum": [
       "corporate",
       "shop",
       "content",
       "api",
       "admin",
       "download"
      ],
      "type": "string",
      "x-description-zh": "网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "upid": {
      "description": "User package id (may be empty before the package domain goes live; falls back to tenant_id in the snapshot when empty).",
      "type": "integer",
      "x-description-zh": "用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。"
     },
     "verdict": {
      "description": "Result for the caller visiting the home page: pass, block (blocked) or log (logged only).",
      "enum": [
       "pass",
       "block",
       "log"
      ],
      "type": "string",
      "x-description-zh": "调用者访问首页的结果:pass 放行、block 被拦、log 只记录。"
     },
     "waf_gate": {
      "description": "Only in the site detail (GET /sites/{id}): the WAF Enhanced status of the site's owner and why it is not in effect. owner, packages and expired_at are in administrator responses only; tenants get gate and reason only. List rows carry waf_gate_reason alone.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "只在站点详情(GET /sites/{id})里给:站点属主的 WAF 增强状态与没生效的原因。owner、packages、expired_at 仅管理员响应带,租户响应只有 gate 与 reason。列表行只有 waf_gate_reason。",
      "x-gocdn-type": "SiteWafGate"
     },
     "waf_gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     }
    },
    "type": "object"
   },
   "stream-groups": {
    "properties": {
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     }
    },
    "type": "object"
   },
   "streams": {
    "properties": {
     "acl": {
      "description": "Layer-4 access control. Rules match the source IP or CIDR in order and the first hit decides; if none match, default_action applies; deny drops the connection immediately.",
      "type": "object",
      "x-description-zh": "四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。",
      "x-gocdn-type": "StreamAcl"
     },
     "action": {
      "description": "Operation. set_enabled toggles enabled state, delete removes, set_groups replaces groups, update edits fields in bulk, create adds new ones, set_lines changes the CNAME's primary/backup line groups (admin only), set_cname_domain changes the CNAME root domain (admin only, host label kept).",
      "enum": [
       "set_enabled",
       "delete",
       "set_groups",
       "update",
       "create",
       "set_lines",
       "set_cname_domain"
      ],
      "type": "string",
      "x-description-zh": "操作类型:set_enabled 启停、delete 删除、set_groups 换分组、update 批量修改、create 批量新建、 set_lines 改接入名的主/备线路分组(仅管理员)、set_cname_domain 改接入名的根域(仅管理员,主机记录不变)。"
     },
     "affected": {
      "description": "Number of affected records",
      "type": "integer",
      "x-description-zh": "受影响的条数"
     },
     "backup_group_id": {
      "description": "Used by set_lines: backup line group; 0 clears it, omitted leaves it unchanged.",
      "type": "integer",
      "x-description-zh": "set_lines 用:备用线路分组;0 = 清空,不给 = 不动。"
     },
     "balance": {
      "description": "Load balancing method. rr is round robin, ip_hash hashes the source IP, least_conn picks the fewest connections, random picks at random.",
      "enum": [
       "rr",
       "ip_hash",
       "least_conn",
       "random"
      ],
      "type": "object",
      "x-description-zh": "负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。",
      "x-gocdn-type": "StreamBalance"
     },
     "cname": {
      "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
      "type": "object",
      "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
      "x-gocdn-type": "CnameBinding"
     },
     "cname_domain_id": {
      "description": "Used by set_cname_domain: the new CNAME root domain.",
      "type": "integer",
      "x-description-zh": "set_cname_domain 用:新的接入根域。"
     },
     "conn_limit": {
      "description": "Per-IP concurrent connection limit; 0 = unlimited.",
      "type": "integer",
      "x-description-zh": "单 IP 并发连接上限,0 = 不限。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "expected_updated_at": {
      "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
      "type": "string",
      "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
     },
     "group_ids": {
      "description": "IDs of the forwarding groups this rule belongs to.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "所属转发分组 id 列表。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "IDs of the forwarding rules to operate on, at most 100 per call (required by every action except create).",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要操作的转发 id 列表,一次最多 100 条(create 以外的操作必填)。"
     },
     "items": {
      "description": "Used by create: the forwarding rules to create (up to 100), each shaped like the POST /streams request body.",
      "items": {
       "type": "object",
       "x-gocdn-type": "StreamWrite"
      },
      "type": "array",
      "x-description-zh": "create 用:要新建的转发(最多 100 条),每条同 POST /streams 的请求体。"
     },
     "listen": {
      "description": "Listener list. Each item is a port and a protocol.",
      "items": {
       "type": "object",
       "x-gocdn-type": "StreamListen"
      },
      "type": "array",
      "x-description-zh": "监听列表:每项为端口与协议。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_group_id": {
      "description": "Used by set_lines: primary line group (required).",
      "type": "integer",
      "x-description-zh": "set_lines 用:主线路分组(必填)。"
     },
     "node_issues": {
      "description": "Ports or reasons for which the forward is not fully in effect on online nodes (in the list and the detail); omitted when everything is in effect.",
      "items": {
       "type": "object",
       "x-gocdn-type": "NodeIssue"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "在线节点上这条转发没完全生效的口或原因(列表与详情里给);都正常时不给这个字段。"
     },
     "origin_port": {
      "description": "Origin port to connect to.",
      "type": "integer",
      "x-description-zh": "回源端口。"
     },
     "origins": {
      "description": "Origin list. Each item has an origin IP, a weight, and backup/down flags.",
      "items": {
       "type": "object",
       "x-gocdn-type": "StreamOrigin"
      },
      "type": "array",
      "x-description-zh": "源站列表:每项为源站 IP、权重与备用/下线标记。"
     },
     "patch": {
      "description": "For batch update. Fields that are given are applied to every rule, with the same rules as a single update.",
      "type": "object",
      "x-description-zh": "批量 update 用:给了的字段改到每一条上,规则同单条修改。",
      "x-gocdn-type": "StreamPatch"
     },
     "proxy_protocol": {
      "description": "Whether to send a PROXY protocol header to the origin.",
      "type": "boolean",
      "x-description-zh": "是否向源站发送 PROXY protocol 头。"
     },
     "region_id": {
      "description": "Used by set_lines: region; when given, both line groups must belong to it.",
      "type": "integer",
      "x-description-zh": "set_lines 用:区域;给了就校验主/备线路分组都属于它(不给不校验)。"
     },
     "stop_code": {
      "description": "0 = normal; non-zero = new connections are dropped immediately (set by admin or billing; 512 in the snapshot when the user package has expired).",
      "type": "integer",
      "x-description-zh": "0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "udp_responses": {
      "description": "UDP responses. 1-100 = end each UDP session after this many packets from the origin (instead of waiting for the UDP idle timeout); 0 = not set. Only for request/response traffic (DNS, probes); do not set it for games or voice that send many replies per request, or their sessions get cut short.",
      "type": "integer",
      "x-description-zh": "UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "upid": {
      "description": "User package ID (empty = no quota check; empty falls back to tenant_id in the snapshot).",
      "type": "integer",
      "x-description-zh": "用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。"
     }
    },
    "type": "object"
   },
   "tamper-guard": {
    "properties": {
     "base_at": {
      "description": "When the site's baseline was last updated (whole site); null if never.",
      "type": "string",
      "x-description-zh": "站点整体基准时间;还没更新过基准为 null。"
     },
     "domain": {
      "description": "Primary domain of the site (first in its domain list; the site name when it has none).",
      "type": "string",
      "x-description-zh": "网站主域名(站点域名列表第一个;没有域名时为站点名)。"
     },
     "enabled": {
      "description": "Whether tamper protection is switched on for the site; when off the pages are only a kept baseline and nothing is checked.",
      "type": "boolean",
      "x-description-zh": "该站防篡改开关是否开着;关着时页面状态只是保留的基准,不检测。"
     },
     "gate": {
      "description": "WAF Enhanced status of the site's tenant: full = baseline can be updated; readonly and basic = cannot.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "type": "string",
      "x-description-zh": "该站租户的 WAF 增强判定档:full 可更新基准;readonly 与 basic 不可。"
     },
     "gate_expired_at": {
      "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
     },
     "gate_owner": {
      "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
      "x-gocdn-type": "WafGateOwner"
     },
     "gate_packages": {
      "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
     },
     "gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     },
     "kind": {
      "description": "Which kind of scope the page comes from.",
      "enum": [
       "home",
       "page",
       "dir"
      ],
      "type": "string",
      "x-description-zh": "来自哪类保护范围。"
     },
     "last_change_action": {
      "description": "What the node did the last time: replace = served the baseline page; log = recorded only (including the observation period).",
      "enum": [
       "replace",
       "log"
      ],
      "type": "string",
      "x-description-zh": "最近一次篡改的节点处置:replace 返回了基准页;log 只记录(含观察期)。"
     },
     "last_change_at": {
      "description": "When tampering was last detected; null = none since the baseline.",
      "type": "string",
      "x-description-zh": "最近一次检出篡改的时间;基准以来没有为 null。"
     },
     "last_change_summary": {
      "description": "Summary of the last change, e.g. link=bad.example.net, title.",
      "type": "string",
      "x-description-zh": "最近一次篡改的变化摘要,如 link=bad.example.net, title。"
     },
     "note": {
      "description": "Why the page is not in the baseline, same values as SiteTamperPage.note; absent for included pages.",
      "enum": [
       "too_large",
       "site_limit",
       "fetch_failed",
       "not_html"
      ],
      "type": "string",
      "x-description-zh": "没纳入基准的原因,取值同 SiteTamperPage.note;纳入的页不出。"
     },
     "observe_until": {
      "description": "End of the site's tamper-protection observation period; set only while protection is on and observing (same as SiteTamperGuard.observe_until), null when off or never observing; an already-passed deadline is returned as is, the caller compares it with the current time.",
      "type": "string",
      "x-description-zh": "该站防篡改观察期截止;开着且在观察期内才有值(同 SiteTamperGuard.observe_until),关着或没有观察期为 null;已过期的截止时间照回,由调用方比对当前时间。"
     },
     "path": {
      "description": "Page path.",
      "type": "string",
      "x-description-zh": "页面路径。"
     },
     "site_id": {
      "description": "Site id.",
      "type": "integer",
      "x-description-zh": "网站 id。"
     },
     "size": {
      "description": "Size of the baseline page in bytes.",
      "type": "integer",
      "x-description-zh": "基准页字节数。"
     },
     "state": {
      "description": "Page state: normal; tampered = tampering detected since the baseline; excluded = not in the baseline (see note).",
      "enum": [
       "normal",
       "tampered",
       "excluded"
      ],
      "type": "string",
      "x-description-zh": "页面状态:normal 正常;tampered 基准以来检出过篡改;excluded 没纳入基准(原因见 note)。"
     }
    },
    "type": "object"
   },
   "upload-scan-settings": {
    "properties": {
     "action": {
      "description": "On a hit - block, log only, or observe for 3 days (log only, then block); dangerous files have no observation period.",
      "enum": [
       "block",
       "log",
       "observe"
      ],
      "type": "string",
      "x-description-zh": "命中后:block 拦截、log 只记录、observe 先观察 3 天(期间只记录,之后拦截);危险文件不设观察期。"
     },
     "disguise": {
      "description": "Disguised file detection (image extension but the magic bytes are a script or an executable).",
      "type": "boolean",
      "x-description-zh": "伪装文件检测(扩展名为图片、文件头魔数为脚本或可执行程序)。"
     },
     "double_ext": {
      "description": "Double extension detection (e.g. a.php.jpg, a.asp;.jpg).",
      "type": "boolean",
      "x-description-zh": "双扩展名检测(如 a.php.jpg、a.asp;.jpg)。"
     },
     "enabled": {
      "description": "Master switch; false = no site is scanned.",
      "type": "boolean",
      "x-description-zh": "总开关;false = 所有站点都不扫描。"
     },
     "enhanced": {
      "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; enhanced items are off, settings kept); ignored on update.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(增强项不生效,设置保留);修改时忽略。"
     },
     "exceptions": {
      "description": "Exceptions - skip the signature when the site and path prefix match (empty sig = the path is not scanned). Entries that tenants added by marking false positives (source=false_positive) must be sent back unchanged on replace, otherwise they are overwritten.",
      "items": {
       "type": "object",
       "x-gocdn-type": "UploadScanException"
      },
      "type": "array",
      "x-description-zh": "例外:网站与路径前缀命中时跳过该特征(sig 空 = 该路径不扫描)。租户标记误报加的条目(source=false_positive)整体替换时请原样带回,否则被覆盖。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "exts": {
      "description": "Dangerous extensions (lowercase, without the dot); defaults to php phtml jsp jspx asp aspx ashx cer war sh cgi when omitted. A site may override with waf.upload_exts.",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "危险扩展名(小写、不带点);没带回缺省 php phtml jsp jspx asp aspx ashx cer war sh cgi。站点 waf.upload_exts 可覆盖。"
     },
     "max_file_mb": {
      "description": "Per-file scan limit in MB (default 20); larger files only get the extension check and are handled per oversize.",
      "type": "integer",
      "x-description-zh": "单个文件扫描上限(MB,缺省 20);超出的只查扩展名,按 oversize 处置。"
     },
     "observe_until": {
      "description": "End of the observation period (set when action is observe); ignored on update, written by the server.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "观察期截止(action 为 observe 时有值);修改时忽略,由服务端写。"
     },
     "on_parse_error": {
      "description": "On multipart parse errors (bad delimiter, oversized header, truncated body, too many parts) - block or allow (pass and log); default block.",
      "enum": [
       "allow",
       "block"
      ],
      "type": "string",
      "x-description-zh": "multipart 解析出错(定界符不对、头过大、体被截断、段数超限等)时:block 拦截、allow 放行并记录(缺省 block)。"
     },
     "on_timeout": {
      "description": "On scan timeout (or failure to read the body) - allow (pass and log) or block (default allow).",
      "enum": [
       "allow",
       "block"
      ],
      "type": "string",
      "x-description-zh": "扫描超时(或读请求体失败)时:allow 放行并记录、block 拦截(缺省 allow)。"
     },
     "oversize": {
      "description": "Files over the limit - allow (pass and log) or block.",
      "enum": [
       "allow",
       "block"
      ],
      "type": "string",
      "x-description-zh": "超过单文件上限:allow 放行并记录、block 拦截。"
     },
     "sha256": {
      "description": "Local sha256 blocklist (WAF enhanced).",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "本主控 sha256 黑名单(WAF 增强)。"
     },
     "sig": {
      "description": "Webshell signatures (WAF enhanced).",
      "type": "boolean",
      "x-description-zh": "木马 / Webshell 特征(WAF 增强)。"
     },
     "timeout_s": {
      "description": "Scan timeout per request in seconds (default 2).",
      "type": "integer",
      "x-description-zh": "每个请求的扫描超时(秒,缺省 2)。"
     },
     "updated_at": {
      "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。"
     },
     "virus": {
      "description": "Antivirus (ClamAV, WAF enhanced) - off, mem4g (nodes with at least 4 GB memory) or all nodes.",
      "enum": [
       "off",
       "mem4g",
       "all"
      ],
      "type": "string",
      "x-description-zh": "病毒库(ClamAV,WAF 增强):off 关、mem4g 内存 ≥4GB 的节点、all 所有节点。"
     }
    },
    "type": "object"
   },
   "upload-scan-stats": {
    "properties": {
     "today_blocked": {
      "description": "Uploads blocked by a scan hit today (excluding blocks caused by oversize, timeout or errors); null when the log database is unavailable.",
      "type": "integer",
      "x-description-zh": "今日被上传扫描命中并拦下的次数(不含超上限、超时、出错的拦截);日志库不可用为 null。"
     },
     "today_scanned": {
      "description": "Upload requests scanned today (one request with several files counts once); null when the log database is unavailable.",
      "type": "integer",
      "x-description-zh": "今日扫描的上传请求数(一请求多文件计 1);日志库不可用为 null。"
     },
     "today_unscanned": {
      "description": "Uploads left unscanned today because they exceeded the per-file limit; null when the log database is unavailable.",
      "type": "integer",
      "x-description-zh": "今日因超过单文件上限而未扫描的次数;日志库不可用为 null。"
     },
     "unscanned_sites": {
      "description": "Sites that cannot be scanned, ascending by site id, at most 200; when scanning is globally off, a single summary entry with reason=global_off (site_id 0). Online nodes whose WAF is switched off by the node-local out-of-band killswitch follow (reason=node_kill, site_id 0, name is the node name, at most 200, not counted in unscanned_total); omitted when scanning is globally off.",
      "items": {
       "type": "object",
       "x-gocdn-type": "UploadScanStatsSite"
      },
      "type": "array",
      "x-description-zh": "扫不了的网站,按网站 id 升序,最多 200 条;全局未开时只回一条 reason=global_off 的汇总(site_id 为 0)。其后另附 WAF 被节点本机带外总开关关停的在线节点(reason=node_kill,site_id 为 0、name 为节点名,最多 200 条,不计入 unscanned_total);全局未开时不附。"
     },
     "unscanned_total": {
      "description": "Total number of sites that cannot be scanned (not capped at 200); the number of all enabled sites when scanning is globally off.",
      "type": "integer",
      "x-description-zh": "扫不了的网站总数(不受 200 条上限影响);全局未开时为全部启用网站数。"
     }
    },
    "type": "object"
   },
   "url-guard": {
    "properties": {
     "items": {
      "description": "Rules in effect, newest first.",
      "items": {
       "type": "object",
       "x-gocdn-type": "UrlGuardActive"
      },
      "type": "array",
      "x-description-zh": "生效中的规则,新的在前。"
     }
    },
    "type": "object"
   },
   "url-guard-settings": {
    "properties": {
     "action": {
      "description": "Action on the URL once triggered - challenge, block or per-IP rate limit.",
      "enum": [
       "challenge",
       "block",
       "limit"
      ],
      "type": "string",
      "x-description-zh": "触发后对该 URL 的动作:挑战验证、拦截、每 IP 限速。"
     },
     "baseline_ratio": {
      "description": "Triggering also requires this many times the usual level (usual = the URL's average QPS over the past hour, excluding the last minute). The panel asks for at least 1, default 5; 0 = ignore the multiple (legacy configs lack the field and keep the old rule). Applies to new triggers only - renewing an active rule looks at QPS alone. Omit on update to keep the stored value.",
      "type": "integer",
      "x-description-zh": "触发还须达到平时的这么多倍(平时 = 该 URL 过去 1 小时的平均 QPS,不含最近 1 分钟);面板最小填 1,缺省 5;0 = 不看倍数(旧配置没有该字段,按 0 沿用原判定)。只管新触发,已在途规则续期只看 QPS。修改时不带则保持原值。"
     },
     "enabled": {
      "description": "Global default switch, used by sites that do not set their own.",
      "type": "boolean",
      "x-description-zh": "全局默认开关;站点未单独设置时按它。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "gate": {
      "description": "WAF enhanced (waf_enhanced) gate - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; still effective, settings read-only), basic (not purchased or fallen back, nothing is pushed); ignored on update.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "WAF 增强(waf_enhanced)判定档:full 开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;照常生效、设置只读)、basic 未开通或已回落(不下发);修改时忽略。"
     },
     "gate_expired_at": {
      "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
     },
     "gate_owner": {
      "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
      "x-gocdn-type": "WafGateOwner"
     },
     "gate_packages": {
      "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
      "items": {
       "type": "string"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
     },
     "gate_reason": {
      "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
      "enum": [
       "package",
       "license",
       "expired"
      ],
      "readOnly": true,
      "type": "object",
      "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
      "x-gocdn-type": "WafGateReason"
     },
     "hold_s": {
      "description": "Seconds the rule is held; it is renewed while still over the threshold and lapses once traffic drops.",
      "type": "integer",
      "x-description-zh": "规则保持秒数;到期前仍超阈会自动续期,降下来就到期撤销。"
     },
     "kind": {
      "description": "Challenge type for action=challenge (default js); must be empty for other actions.",
      "enum": [
       "js",
       "redirect",
       "delay_jump",
       "cookie",
       "captcha",
       "slide",
       "click",
       "rotate"
      ],
      "type": "string",
      "x-description-zh": "action=challenge 的挑战类型,缺省 js;其它动作须为空。"
     },
     "max_per_site": {
      "description": "Max rules in effect at the same time per site.",
      "type": "integer",
      "x-description-zh": "同一站点同时生效的规则条数上限。"
     },
     "qps": {
      "description": "Trigger only when the network-wide total QPS of a URL is at least this (and at least baseline_ratio times its usual level).",
      "type": "integer",
      "x-description-zh": "某 URL 全网合计 QPS 不低于它(且达到平时的 baseline_ratio 倍)才触发。"
     },
     "rate": {
      "description": "Max requests per IP per 10 seconds for action=limit; must be 0 for other actions.",
      "type": "integer",
      "x-description-zh": "action=limit 的每 IP 每 10 秒最多请求数;其它动作须为 0。"
     },
     "updated_at": {
      "description": "Version in the response (null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "响应里的版本(没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
     }
    },
    "type": "object"
   },
   "user-packages": {
    "properties": {
     "action": {
      "description": "Operation: buy, renew, change or upgrade.",
      "enum": [
       "buy",
       "renew",
       "change",
       "upgrade"
      ],
      "type": "string",
      "x-description-zh": "操作类型:购买、续费、更换套餐或加购升级包。"
     },
     "added": {
      "description": "IDs of the pool IPs newly selected by this call.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "本次新选中的池内 IP ID。"
     },
     "amount": {
      "description": "Number of units, default 1.",
      "type": "integer",
      "x-description-zh": "份数,默认 1"
     },
     "amount_cents": {
      "description": "Positive = charged, negative = refunded to balance (downgrade), 0 = no charge (including admin operations).",
      "type": "integer",
      "x-description-zh": "正 = 扣款,负 = 退回余额(降级),0 = 不收费(含管理员操作)"
     },
     "backup_group_id": {
      "description": "Backup node group; null = none.",
      "type": "integer",
      "x-description-zh": "备用线路分组;null = 没有"
     },
     "bandwidth_mbps": {
      "description": "Bandwidth in Mbps, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "带宽 Mbps,-1 不限"
     },
     "cert_auto": {
      "description": "Platform IP certificate status.",
      "type": "object",
      "x-description-zh": "平台 IP 证书状态。",
      "x-gocdn-type": "IpCertState"
     },
     "cname_domain_id": {
      "description": "CNAME root domain; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "接入根域(CNAME 域名);null = 套餐不绑线路"
     },
     "cname_hostname": {
      "description": "Host record of the shared access name (used by sites and streams in per-package mode); empty = none yet.",
      "type": "string",
      "x-description-zh": "共用接入名的主机记录(按套餐生成时下属站点/转发共用);空 = 还没有"
     },
     "cname_mode": {
      "description": "CNAME mode. site = one access name per site or stream; package = sites and streams of a purchased package share one access name.",
      "enum": [
       "site",
       "package"
      ],
      "type": "object",
      "x-description-zh": "CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。",
      "x-gocdn-type": "PackageCnameMode"
     },
     "connections": {
      "description": "Concurrent connections, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "并发连接数,-1 不限"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "custom_cc_rule": {
      "description": "Allows custom CC rules.",
      "type": "boolean",
      "x-description-zh": "可自定义 CC 规则"
     },
     "cycle_end": {
      "description": "End of the current billing cycle.",
      "type": "string",
      "x-description-zh": "本计费周期结束时间。"
     },
     "cycle_start": {
      "description": "Start of the current billing cycle.",
      "type": "string",
      "x-description-zh": "本计费周期开始时间。"
     },
     "domains": {
      "description": "Number of domains (each IP site counts as 1), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "域名数(IP 站每站占 1),-1 不限"
     },
     "dry_run": {
      "description": "Quote only, do not save.",
      "type": "boolean",
      "x-description-zh": "只报价不落库"
     },
     "duration": {
      "description": "Duration: month/quarter/year (adds 1/3/12 months; at month end the last day of the target month is used).",
      "enum": [
       "month",
       "quarter",
       "year"
      ],
      "type": "string",
      "x-description-zh": "时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "end_at": {
      "description": "Expiry time of the purchased package.",
      "type": "string",
      "x-description-zh": "套餐到期时间。"
     },
     "follow_base": {
      "description": "Follows the base package; quota changes on the base package are synced here automatically (except fields in overrides).",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "跟随基础套餐:改基础套餐的配额类字段时自动同步到本套餐(overrides 里的字段除外)"
     },
     "http_ports": {
      "description": "Number of non-standard HTTP/HTTPS ports (other than 80/443), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "HTTP/HTTPS 非标端口数(80/443 之外),-1 不限"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "in_pool": {
      "description": "Still in the package's current IP pool.",
      "type": "boolean",
      "x-description-zh": "仍在该套餐当前的 IP 池里。"
     },
     "ip": {
      "description": "IP address.",
      "type": "string",
      "x-description-zh": "IP 地址。"
     },
     "ip_ids": {
      "description": "IDs of the pool IPs to select.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要选的池内 IP ID 列表。"
     },
     "ip_num": {
      "description": "Number of selectable IPs (\"My IPs\"), -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "可选 IP 数(「我的 IP」),-1 不限"
     },
     "ip_pool_id": {
      "description": "IP pool used to provision IP sites (IP product line); null = not provisioned.",
      "type": "integer",
      "x-description-zh": "开通 IP 站点用的 IP 池(IP 产品线);null = 不开通"
     },
     "ip_site_port": {
      "description": "IP-site ports: distinct ports across all IP sites of the package (80/443 included), -1 = unlimited; IP-site ports do not count toward non-standard ports.",
      "type": "integer",
      "x-description-zh": "IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数"
     },
     "items": {
      "description": "Items on this page",
      "items": {
       "type": "object",
       "x-gocdn-type": "UserPackageIp"
      },
      "type": "array",
      "x-description-zh": "本页条目"
     },
     "l2": {
      "description": "Includes tiered origin (tenant switch of the paid feature l2): tenants can turn on tiered origin for sites, and nodes use it, only while the master license l2 is active; existing packages are false (on upgrade, purchased packages of tenants already using tiered origin are set to true).",
      "type": "boolean",
      "x-description-zh": "含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true)"
     },
     "limit": {
      "description": "Number of IPs that can be selected; -1 means unlimited.",
      "type": "integer",
      "x-description-zh": "可选个数,-1 不限。"
     },
     "limits": {
      "description": "Effective limits (package values plus upgrade packs; -1 = unlimited, 0/1 for feature items).",
      "type": "object",
      "x-description-zh": "有效额度(套餐值 + 升级包;-1 不限,功能类 0/1)。",
      "x-gocdn-type": "PackageLimits"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "node_group_id": {
      "description": "Primary node group; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "主线路分组;null = 套餐不绑线路"
     },
     "node_state": {
      "description": "State of the owning primary node: disabled if the node is disabled; otherwise online if a heartbeat arrived in the last 2 minutes, else offline.",
      "enum": [
       "online",
       "offline",
       "disabled"
      ],
      "type": "object",
      "x-description-zh": "持有主节点状态:停用 disabled;否则最近 2 分钟有心跳 online,没有 offline。",
      "x-gocdn-type": "IpNodeState"
     },
     "order_id": {
      "description": "Order id (when a charge or refund happened).",
      "type": "integer",
      "x-description-zh": "订单 id(扣款/退款时)"
     },
     "overrides": {
      "description": "Quota fields edited individually by an admin that differ from the base package; skipped by automatic sync.",
      "items": {
       "type": "object",
       "x-gocdn-type": "PackageQuotaField"
      },
      "readOnly": true,
      "type": "array",
      "x-description-zh": "管理员单独改过且与基础套餐不同的配额类字段,自动同步时跳过"
     },
     "package_id": {
      "description": "Base package id.",
      "type": "integer",
      "x-description-zh": "基础套餐 id"
     },
     "package_name": {
      "description": "Base package name (shown in package lists and orders).",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "基础套餐名(套餐列表与订单展示用)"
     },
     "period": {
      "description": "Price period used for proration when changing package.",
      "enum": [
       "month",
       "quarter",
       "year"
      ],
      "type": "string",
      "x-description-zh": "更换套餐时折算所用的价目"
     },
     "price_month_cents": {
      "description": "Monthly price locked at purchase.",
      "type": "integer",
      "x-description-zh": "购买时锁定的月价"
     },
     "price_quarter_cents": {
      "description": "Quarterly price locked at purchase.",
      "type": "integer",
      "x-description-zh": "锁定季价"
     },
     "price_year_cents": {
      "description": "Yearly price locked at purchase.",
      "type": "integer",
      "x-description-zh": "锁定年价"
     },
     "region": {
      "description": "Name of the region it belongs to.",
      "type": "string",
      "x-description-zh": "所属区域名称。"
     },
     "region_id": {
      "description": "Region; null = the package binds no lines.",
      "type": "integer",
      "x-description-zh": "区域;null = 套餐不绑线路"
     },
     "remain_days": {
      "description": "Remaining days used for proration.",
      "type": "integer",
      "x-description-zh": "折算用的剩余天数"
     },
     "remark": {
      "description": "Remark",
      "type": "string",
      "x-description-zh": "备注"
     },
     "requests": {
      "description": "Number of requests in this billing cycle (sealed hours plus a live count of hours not yet sealed).",
      "type": "integer",
      "x-description-zh": "本计费周期的请求数(已封账小时 + 还没封账的小时现算)。"
     },
     "reset_to_base": {
      "description": "Admin only; true = reset quota fields to the base package values, clear overrides and follow again (cannot be combined with other fields).",
      "type": "boolean",
      "x-description-zh": "仅管理员:true = 配额类字段恢复为基础套餐的值、清空 overrides 并恢复跟随(不能与其它字段同时给)"
     },
     "selected": {
      "description": "Number of IPs already selected.",
      "type": "integer",
      "x-description-zh": "已选 IP 个数。"
     },
     "sites": {
      "description": "IP sites in this package that bind it.",
      "items": {
       "type": "object"
      },
      "type": "array",
      "x-description-zh": "本套餐里绑定它的 IP 站点。"
     },
     "start_at": {
      "description": "Start time of the purchased package.",
      "type": "string",
      "x-description-zh": "套餐生效时间。"
     },
     "status": {
      "description": "expired = expired (the tenant's sites are suspended with 512; renewing restores them).",
      "enum": [
       "active",
       "expired"
      ],
      "type": "string",
      "x-description-zh": "expired = 已到期(名下站点停服 512,续费恢复)"
     },
     "stream_ports": {
      "description": "Number of TCP/UDP forwarding ports, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "四层转发端口数,-1 不限"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "traffic_bytes": {
      "description": "Billable traffic used in this billing cycle (bytes, already multiplied by the compensation factor) — sealed hours plus a live count of hours not yet sealed, the same figure the over-quota stop uses.",
      "type": "integer",
      "x-description-zh": "本计费周期已用计费流量(字节,已乘补偿系数):已封账小时 + 还没封账的小时现算,与流量超额停站同口径。"
     },
     "traffic_gb": {
      "description": "Traffic in GB per billing cycle, -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "每计费周期流量 GB,-1 不限"
     },
     "traffic_limit_gb": {
      "description": "Effective traffic limit (GB, 1 GB = 1024^3 bytes, including upgrade packs); -1 = unlimited.",
      "type": "integer",
      "x-description-zh": "有效流量额度(GB,1 GB = 1024³ 字节,含升级包);-1 不限。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "upgrade_id": {
      "description": "Id of the upgrade pack to buy.",
      "type": "integer",
      "x-description-zh": "要加购的升级包 id。"
     },
     "user_package": {
      "description": "The purchased package after the operation.",
      "type": "object",
      "x-description-zh": "办理后的用户套餐。",
      "x-gocdn-type": "UserPackage"
     },
     "user_package_id": {
      "description": "Id of the purchased package this operation applied to (for a purchase, the newly created one; equals user_package.id). Absent for a dry run, which saves nothing.",
      "type": "integer",
      "x-description-zh": "办理的用户套餐 id(购买时即新建的那一条,等于 user_package.id);试算(dry_run)没落库,不带。"
     },
     "waf_enhanced": {
      "description": "Includes WAF Enhanced (tenant switch of the paid feature waf_enhanced): tenants can use standard/strict levels, big screen, deep Bot, anti-tamper and so on only while the master license WAF Enhanced is not degraded; existing packages are false.",
      "type": "boolean",
      "x-description-zh": "含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false"
     },
     "websocket": {
      "description": "Allows WebSocket.",
      "type": "boolean",
      "x-description-zh": "可开 WebSocket"
     }
    },
    "type": "object"
   },
   "users": {
    "properties": {
     "action": {
      "description": "enable, disable or delete.",
      "enum": [
       "enable",
       "disable",
       "delete"
      ],
      "type": "string",
      "x-description-zh": "enable 启用、disable 停用、delete 删除。"
     },
     "affected": {
      "description": "Number of users processed.",
      "type": "integer",
      "x-description-zh": "处理的用户数。"
     },
     "allow_ips": {
      "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
      "type": "object",
      "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
      "x-gocdn-type": "ApiKeyAllowIps"
     },
     "amount_cents": {
      "description": "Amount in cents; must be a positive integer.",
      "type": "integer",
      "x-description-zh": "金额(分),须为正整数。"
     },
     "archived": {
      "description": "Moved into the archive table by the archiving task (read-only).",
      "type": "boolean",
      "x-description-zh": "已被归档任务搬进档案表(只读)。"
     },
     "balance_cents": {
      "description": "Account balance in cents, same as balance_cents of GET /users/{user_id}/account (0 when there is no account). Only present in the GET /users list, not in single-user responses",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "账户余额(分),同 GET /users/{user_id}/account 的 balance_cents(无账户记 0)。只有 GET /users 列表带,单个用户的读写接口不带。"
     },
     "certified": {
      "description": "Whether real-name verification has passed",
      "type": "boolean",
      "x-description-zh": "是否已通过实名认证。"
     },
     "client_ip": {
      "description": "Source IP of this request, derived the same way as the login IP allowlist check (what the allowlist compares is what is shown). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "本次请求的来源 IP,与登录 IP 白名单校验用的是同一个取法(白名单比什么就显示什么)。只有 GET /me、PUT /me 带。"
     },
     "created_at": {
      "description": "Created at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "创建时间"
     },
     "data": {
      "description": "Extra data (such as package purchase details).",
      "type": "object",
      "x-description-zh": "附加数据(如套餐购买明细)。"
     },
     "delegated_session": {
      "description": "Whether the current session was issued by superadmin sign-in or switch-to-user (if so, password, email, phone, login allowlist, login verification and real-name are read-only). Only present in GET /me and PUT /me",
      "readOnly": true,
      "type": "boolean",
      "x-description-zh": "当前会话是否由超管代登录或切换为用户签发(是则口令、邮箱、手机号、登录白名单、二次验证与实名只读)。只有 GET /me、PUT /me 带。"
     },
     "des": {
      "description": "Description",
      "type": "string",
      "x-description-zh": "备注说明"
     },
     "direction": {
      "default": "credit",
      "description": "credit = recharge (default), debit = deduct.",
      "enum": [
       "credit",
       "debit"
      ],
      "type": "string",
      "x-description-zh": "credit 充值(缺省)、debit 扣款。"
     },
     "email": {
      "description": "Email",
      "type": "string",
      "x-description-zh": "邮箱"
     },
     "enabled": {
      "description": "Whether enabled",
      "type": "boolean",
      "x-description-zh": "是否启用"
     },
     "expires_at": {
      "description": "Expires at",
      "type": "string",
      "x-description-zh": "过期时间"
     },
     "freeze_reason": {
      "description": "Freeze reason; empty if not frozen.",
      "type": "string",
      "x-description-zh": "冻结原因;未冻结为空。"
     },
     "frozen": {
      "description": "Whether the account is frozen; deductions are rejected while frozen.",
      "type": "boolean",
      "x-description-zh": "是否已冻结;冻结后扣款一律被拒。"
     },
     "id": {
      "description": "Record ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "记录 ID"
     },
     "ids": {
      "description": "User IDs to operate on, 1 to 100 per call.",
      "items": {
       "type": "integer"
      },
      "type": "array",
      "x-description-zh": "要操作的用户 id,一次 1~100 个。"
     },
     "last_used_at": {
      "description": "Time of last use; null if never used",
      "type": "string",
      "x-description-zh": "最近一次使用时间;从未使用为空。"
     },
     "ledger_id": {
      "description": "ID of the linked ledger entry; null if none.",
      "type": "integer",
      "x-description-zh": "关联的账户流水 ID;没有则为空。"
     },
     "login_ip_allow": {
      "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
     },
     "login_verify": {
      "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
      "enum": [
       "none",
       "email",
       "sms"
      ],
      "type": "object",
      "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
      "x-gocdn-type": "LoginVerify"
     },
     "mch_order_no": {
      "description": "Merchant order number (the gateway-side order number); null for non-online payments.",
      "type": "string",
      "x-description-zh": "商户订单号(网关侧订单号);非在线支付为空。"
     },
     "name": {
      "description": "Name",
      "type": "string",
      "x-description-zh": "名称"
     },
     "paid_at": {
      "description": "Payment time; null if unpaid.",
      "type": "string",
      "x-description-zh": "付款时间;未付款为空。"
     },
     "password": {
      "description": "Required on create; on update, providing it resets the password and revokes all sessions of the user",
      "type": "string",
      "x-description-zh": "创建时必填;修改时给了即重设口令并吊销该用户全部会话。"
     },
     "pay_type": {
      "description": "admin/balance/alipay/wxpay, etc.; empty = unpaid.",
      "type": "string",
      "x-description-zh": "admin/balance/alipay/wxpay 等;空 = 未付款。"
     },
     "phone": {
      "description": "Phone number",
      "type": "string",
      "x-description-zh": "手机号"
     },
     "prefix": {
      "description": "First few characters of the plaintext key, for recognition",
      "type": "string",
      "x-description-zh": "明文的前几位,便于辨认。"
     },
     "remark": {
      "description": "Remark",
      "type": "string",
      "x-description-zh": "备注"
     },
     "reset": {
      "description": "When true, issue a new key; the old one stops working at once",
      "type": "boolean",
      "x-description-zh": "为 true 时换新 key,旧 key 立即失效。"
     },
     "role": {
      "description": "Account role: admin or tenant",
      "enum": [
       "admin",
       "tenant"
      ],
      "type": "string",
      "x-description-zh": "账号角色:admin 管理员,tenant 租户。"
     },
     "scopes": {
      "description": "Granted scopes, same values as scopes at creation",
      "items": {
       "type": "string"
      },
      "type": "array",
      "x-description-zh": "授权范围,取值同创建时的 scopes。"
     },
     "secret": {
      "description": "Plaintext key (the X-API-Key value), returned only once at creation; only a hash is stored",
      "type": "string",
      "x-description-zh": "明文 key(X-API-Key 的值),只在创建时返回一次;库里只存哈希。"
     },
     "status": {
      "description": "Order status: unpaid or paid.",
      "enum": [
       "unpaid",
       "paid"
      ],
      "type": "string",
      "x-description-zh": "订单状态:unpaid 待付款、paid 已付款。"
     },
     "tenant_id": {
      "description": "Owner tenant (user) ID",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "所属租户(用户)ID"
     },
     "totp_enabled": {
      "description": "Whether TOTP is enabled",
      "type": "boolean",
      "x-description-zh": "是否已启用动态口令。"
     },
     "totp_recovery_left": {
      "description": "Number of unused TOTP recovery codes. Only present in GET /me and PUT /me when TOTP is enabled",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "未用完的 TOTP 恢复码个数。只有 GET /me、PUT /me 且已启用动态口令时带。"
     },
     "transaction_id": {
      "description": "Gateway-side transaction ID; empty if unpaid.",
      "type": "string",
      "x-description-zh": "网关侧交易号;未付款为空。"
     },
     "type": {
      "description": "recharge (admin recharge) / deduct (admin deduction) / payment (online payment) / package (package purchase), etc.",
      "type": "string",
      "x-description-zh": "recharge(管理员充值)/deduct(管理员扣款)/payment(在线支付)/package(套餐)等。"
     },
     "updated_at": {
      "description": "Updated at",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "更新时间"
     },
     "user_id": {
      "description": "User ID",
      "type": "integer",
      "x-description-zh": "用户 ID"
     },
     "username": {
      "description": "Username",
      "type": "string",
      "x-description-zh": "用户名"
     }
    },
    "type": "object"
   },
   "verify-codes": {
    "properties": {
     "account": {
      "description": "Login name (required for login)",
      "type": "string",
      "x-description-zh": "登录名(login 必填)。"
     },
     "captcha_code": {
      "description": "Characters shown in the captcha image (required when sending SMS)",
      "type": "string",
      "x-description-zh": "图形验证码上显示的字符(发短信必填)。"
     },
     "captcha_id": {
      "description": "Captcha id (required when sending SMS)",
      "type": "string",
      "x-description-zh": "图形验证码 id(发短信必填)。"
     },
     "channel": {
      "description": "Delivery channel: email or sms",
      "enum": [
       "email",
       "sms"
      ],
      "type": "string",
      "x-description-zh": "发送通道:email 邮件,sms 短信。"
     },
     "expires_in": {
      "description": "Validity in seconds",
      "type": "integer",
      "x-description-zh": "有效期,秒。"
     },
     "purpose": {
      "description": "Purpose: bind (registration or rebinding), reset_password, or login (second factor)",
      "enum": [
       "bind",
       "reset_password",
       "login"
      ],
      "type": "string",
      "x-description-zh": "用途:bind 注册或改绑,reset_password 找回密码,login 登录二次验证。"
     },
     "resend_in": {
      "description": "Seconds before the code can be resent",
      "type": "integer",
      "x-description-zh": "多少秒后可以重发。"
     },
     "target": {
      "description": "Email or phone number (required for bind and reset_password)",
      "type": "string",
      "x-description-zh": "邮箱或手机号(bind、reset_password 必填)。"
     },
     "to": {
      "description": "Masked recipient address",
      "type": "string",
      "x-description-zh": "打码后的收件地址。"
     }
    },
    "type": "object"
   },
   "waf-settings": {
    "properties": {
     "body_max_kb": {
      "description": "Only the first this many KiB of the request body are inspected; 0 = body not inspected.",
      "type": "integer",
      "x-description-zh": "请求体只查前多少 KiB;0 = 不查请求体。"
     },
     "enabled": {
      "description": "Platform-wide master switch; false = no site is inspected.",
      "type": "boolean",
      "x-description-zh": "全网总开关;false = 所有站点都不查。"
     },
     "engine_unavailable_nodes": {
      "description": "Number of online primary nodes reporting the WAF engine (libinjection) unavailable (the sqli/xss rules do not take effect there); ignored on update.",
      "readOnly": true,
      "type": "integer",
      "x-description-zh": "在线主节点里报 WAF 引擎(libinjection)不可用的台数(缺库时 sqli/xss 规则不生效);修改时忽略。"
     },
     "enhanced": {
      "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; standard/strict level and semantic detection still work but are read-only) or basic (not purchased or past the buffer; not in effect, settings kept); ignored on update.",
      "enum": [
       "full",
       "readonly",
       "basic"
      ],
      "readOnly": true,
      "type": "string",
      "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;标准/严格等级与语义检测照常生效但只读)、basic 未开通或缓冲已过(不生效,设置保留);修改时忽略。"
     },
     "expected_updated_at": {
      "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared by CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
      "type": "string",
      "x-description-zh": "乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
     },
     "intel_share": {
      "description": "Threat intelligence sharing - anonymously report auto-banned risky IPs, upload-scan hits/false positives and new file fingerprints to the provider (records via GET /intel-reports). Omit to keep the stored value; on when never set (on by default; can be turned off anytime, reporting stops immediately).",
      "type": "boolean",
      "x-description-zh": "威胁情报共享:把自动封禁的高危 IP、上传扫描命中/误报与新出现的文件指纹匿名上报服务商(记录见 GET /intel-reports)。不带 = 保持原值,没设过为开(默认开启,可随时关闭,关闭后立即停止上报)。"
     },
     "level": {
      "description": "Platform default protection level (used by sites that did not pick one); standard/strict are WAF enhanced and go through the enhanced gate (while read-only or not purchased the level can only be lowered, not raised). Omit to keep the stored value; basic when never set.",
      "enum": [
       "basic",
       "standard",
       "strict"
      ],
      "type": "string",
      "x-description-zh": "全网缺省防护等级(站点没单独选时用它);standard/strict 属 WAF 增强,改动过增强门(到期只读期与未开通只许调低,调高拒)。不带 = 保持原值,没设过为 basic。"
     },
     "observe_days": {
      "description": "Observation days for new rules/levels (log only, no blocking); 0 = no observation. Omit to keep the stored value; 3 when never set.",
      "type": "integer",
      "x-description-zh": "新规则/新等级的观察天数(只记录不拦);0 = 不观察。不带 = 保持原值,没设过为 3。"
     },
     "rule_lib": {
      "description": "Rule library overview (read-only, ignored on update) - whether the paid feature rules_update is on, package version, counts per class and node alignment; without it nodes use the 23 built-in rules. Details via GET /waf-protections.",
      "readOnly": true,
      "type": "object",
      "x-description-zh": "规则库对照表(只读,修改时忽略):付费项 rules_update 是否开通、规则包版本与各类条数、节点对齐;没开通时用节点内置 23 条。明细见 GET /waf-protections。",
      "x-gocdn-type": "WafRuleLib"
     },
     "scanner": {
      "description": "Scanner protection (scan section of the built-in guard) - master switch, action and ban duration, plus the five judging rules (any one triggers) each with its own switch and thresholds/custom lists. A rule that is switched off is not judged; custom paths live on the master and survive rule-pack updates.",
      "type": "object",
      "x-description-zh": "扫描器防护(内置防护 protect.builtin_guard 的 scan 段):总开关、处置与封禁时长,以及「判定(满足任一)」五项各自的勾选与阈值/自定义名单。任一项关掉即不判该项;自定义路径保存在主控,换规则版本不受影响。",
      "x-gocdn-type": "WafScanner"
     },
     "semantic": {
      "description": "Semantic detection (WAF enhanced) - judges attacks by meaning on top of rule scoring; the node enforces it.",
      "type": "object",
      "x-description-zh": "语义检测(WAF 增强):在规则打分之外再按语义判攻击;节点按观察期只记不拦、过期后拦截。",
      "x-gocdn-type": "WafSemantic"
     },
     "threshold": {
      "description": "Default blocking threshold (sum of anomaly scores of matched rules); a non-zero site waf.threshold takes precedence.",
      "type": "integer",
      "x-description-zh": "缺省拦截阈值(命中规则的异常分累计);站点 waf.threshold 非 0 时以站点为准。"
     },
     "trunc_action": {
      "description": "Action when part of a request was not inspected (rule 920901) - more than 1024 parameters, more than 256 headers, JSON/XML items over the limit, form fields over the budget, or a non-binary body larger than body_max_kb. Whatever can be re-checked is re-checked first; only what is still uncovered is handled by this setting. log only records (event tagged body_trunc) and never blocks; strict_block blocks at the strict level and only records at basic/standard; block blocks at every level. Default strict_block: at the strict level a non-binary body above body_max_kb (64 KB by default, e.g. a large JSON) is blocked by 920901 - raise body_max_kb, set log, or exempt 920901 in the site WAF exceptions. Note 920901 counts toward the repeated-hit ban (site waf.ban_on_repeat); on sites where it is enabled, client IPs that routinely send large JSON get banned. Sites in observe mode only record. Omit to keep the stored value; strict_block when never set.",
      "enum": [
       "log",
       "strict_block",
       "block"
      ],
      "type": "string",
      "x-description-zh": "请求内容有一部分没查到时的处置(规则号 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。"
     },
     "updated_at": {
      "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
      "readOnly": true,
      "type": "string",
      "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
     }
    },
    "type": "object"
   }
  },
  "securitySchemes": {
   "ApiKey": {
    "in": "header",
    "name": "X-API-Key",
    "type": "apiKey"
   },
   "Bearer": {
    "scheme": "bearer",
    "type": "http"
   }
  }
 },
 "info": {
  "description": "Send the X-API-Key header (create a key on the API Keys page; the key is shown only once at creation). An Authorization: Bearer token obtained by logging in also works.",
  "title": "gocdn API",
  "version": "2.1.1792967583",
  "x-docs": "https://www-demo.kuxitong.com/en/docs/api"
 },
 "openapi": "3.0.3",
 "paths": {
  "/api/v2/account": {
   "get": {
    "operationId": "get-account",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get my account",
    "tags": [
     "account"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "我的账户"
   }
  },
  "/api/v2/acls": {
   "get": {
    "operationId": "get-acls",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by enabled state.",
      "in": "query",
      "name": "enabled",
      "schema": {
       "description": "Filter by enabled state.",
       "type": "boolean",
       "x-description-zh": "按启用状态过滤。"
      }
     },
     {
      "description": "Filter by name substring.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Filter by name substring.",
       "type": "string",
       "x-description-zh": "按名称包含过滤。"
      }
     },
     {
      "description": "platform = platform objects only; tenant = tenant objects only.",
      "in": "query",
      "name": "owner",
      "schema": {
       "description": "platform = platform objects only; tenant = tenant objects only.",
       "enum": [
        "platform",
        "tenant"
       ],
       "type": "string",
       "x-description-zh": "platform = 只看平台对象;tenant = 只看租户对象。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List ACLs",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出ACL"
   },
   "post": {
    "operationId": "post-acls",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "default_action": "deny",
        "name": "office",
        "rules": [
         {
          "action": "allow",
          "when": {
           "f": "ip",
           "op": "cidr",
           "v": [
            "192.0.2.0/24"
           ]
          }
         }
        ]
       },
       "schema": {
        "properties": {
         "default_action": {
          "description": "Action when no rule matches.",
          "enum": [
           "allow",
           "deny"
          ],
          "type": "string",
          "x-description-zh": "都不命中时的动作。"
         },
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "rules": {
          "description": "Matched in order; the count is limited by the setting protect.acl_rules_max.",
          "items": {
           "type": "object",
           "x-gocdn-type": "AclRule"
          },
          "type": "array",
          "x-description-zh": "按序匹配;条数受配置 protect.acl_rules_max 约束。"
         },
         "tenant_id": {
          "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
         }
        },
        "required": [
         "default_action",
         "name",
         "rules"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create ACL",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建ACL"
   }
  },
  "/api/v2/acls/batch-enable": {
   "post": {
    "operationId": "post-acls-batch-enable",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "enabled": false,
        "ids": [
         1,
         2
        ]
       },
       "schema": {
        "properties": {
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ids": {
          "description": "IDs of the objects to change, at most 100.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改的对象 id,至多 100 个。"
         }
        },
        "required": [
         "enabled",
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch enable or disable ACLs",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量启用或禁用ACL"
   }
  },
  "/api/v2/acls/{id}": {
   "delete": {
    "operationId": "delete-acls-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete ACL",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除ACL"
   },
   "get": {
    "operationId": "get-acls-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get ACL",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取ACL"
   },
   "put": {
    "operationId": "put-acls-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "default_action": "deny",
        "name": "office",
        "rules": [
         {
          "action": "allow",
          "when": {
           "f": "ip",
           "op": "cidr",
           "v": [
            "192.0.2.0/24"
           ]
          }
         }
        ]
       },
       "schema": {
        "properties": {
         "default_action": {
          "description": "Action when no rule matches.",
          "enum": [
           "allow",
           "deny"
          ],
          "type": "string",
          "x-description-zh": "都不命中时的动作。"
         },
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "rules": {
          "description": "Matched in order; the count is limited by the setting protect.acl_rules_max.",
          "items": {
           "type": "object",
           "x-gocdn-type": "AclRule"
          },
          "type": "array",
          "x-description-zh": "按序匹配;条数受配置 protect.acl_rules_max 约束。"
         },
         "tenant_id": {
          "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
         }
        },
        "required": [
         "default_action",
         "name",
         "rules"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update ACL",
    "tags": [
     "acls"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改ACL"
   }
  },
  "/api/v2/acme-accounts": {
   "get": {
    "operationId": "get-acme-accounts",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list accounts of this CA.",
      "in": "query",
      "name": "ca",
      "schema": {
       "description": "Only list accounts of this CA.",
       "enum": [
        "lets",
        "zerossl"
       ],
       "type": "string",
       "x-description-zh": "只列这家 CA 的账号。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List ACME accounts",
    "tags": [
     "acme-accounts"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出ACME 账号"
   },
   "post": {
    "operationId": "post-acme-accounts",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ca": "zerossl",
        "eab_hmac": "${EAB_HMAC}",
        "eab_kid": "kid-example",
        "name": "zerossl-main"
       },
       "schema": {
        "properties": {
         "api_key": {
          "description": "Mask of the ZeroSSL REST API key (`****abcd`); empty = not set. The key is stored encrypted and never returned in plaintext.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。"
         },
         "ca": {
          "description": "CA that issues certificates: lets = Let's Encrypt; zerossl = ZeroSSL.",
          "enum": [
           "lets",
           "zerossl"
          ],
          "type": "string",
          "x-description-zh": "签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。"
         },
         "directory": {
          "description": "ACME directory URL; empty = the CA's URL in the controller's acme.directories (the production URL by default).",
          "type": "string",
          "x-description-zh": "ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。"
         },
         "eab_hmac": {
          "description": "Masked (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
          "type": "string",
          "x-description-zh": "掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
         },
         "eab_kid": {
          "description": "EAB key ID (used by ZeroSSL).",
          "type": "string",
          "x-description-zh": "EAB 密钥 id(ZeroSSL 用)。"
         },
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "recheck": {
          "description": "When true, re-check the stored API key; on success the account becomes usable again and certificates waiting on it are retried immediately.",
          "type": "boolean",
          "x-description-zh": "为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。"
         }
        },
        "required": [
         "ca",
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create ACME account",
    "tags": [
     "acme-accounts"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建ACME 账号"
   }
  },
  "/api/v2/acme-accounts/{id}": {
   "delete": {
    "operationId": "delete-acme-accounts-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete ACME account",
    "tags": [
     "acme-accounts"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除ACME 账号"
   },
   "get": {
    "operationId": "get-acme-accounts-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get ACME account",
    "tags": [
     "acme-accounts"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取ACME 账号"
   },
   "put": {
    "operationId": "put-acme-accounts-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ca": "zerossl",
        "eab_hmac": "${EAB_HMAC}",
        "eab_kid": "kid-example",
        "name": "zerossl-main"
       },
       "schema": {
        "properties": {
         "api_key": {
          "description": "Mask of the ZeroSSL REST API key (`****abcd`); empty = not set. The key is stored encrypted and never returned in plaintext.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "ZeroSSL REST API Key 的掩码(`****abcd`);空 = 没配。Key 加密存库,不回明文。"
         },
         "ca": {
          "description": "CA that issues certificates: lets = Let's Encrypt; zerossl = ZeroSSL.",
          "enum": [
           "lets",
           "zerossl"
          ],
          "type": "string",
          "x-description-zh": "签发证书的 CA:lets = Let's Encrypt;zerossl = ZeroSSL。"
         },
         "directory": {
          "description": "ACME directory URL; empty = the CA's URL in the controller's acme.directories (the production URL by default).",
          "type": "string",
          "x-description-zh": "ACME 目录地址;空 = 主控配置 acme.directories 里该 CA 的地址(缺省为正式地址)。"
         },
         "eab_hmac": {
          "description": "Masked (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
          "type": "string",
          "x-description-zh": "掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
         },
         "eab_kid": {
          "description": "EAB key ID (used by ZeroSSL).",
          "type": "string",
          "x-description-zh": "EAB 密钥 id(ZeroSSL 用)。"
         },
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "recheck": {
          "description": "When true, re-check the stored API key; on success the account becomes usable again and certificates waiting on it are retried immediately.",
          "type": "boolean",
          "x-description-zh": "为 true 时重新检测已存的 API Key;通过则账号回到可用,并立即重签因账号不可用而等待的证书。"
         }
        },
        "required": [
         "ca",
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update ACME account",
    "tags": [
     "acme-accounts"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改ACME 账号"
   }
  },
  "/api/v2/alert-rules": {
   "get": {
    "operationId": "get-alert-rules",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List alert rules and their status",
    "tags": [
     "alert-rules"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出告警规则与当前状态"
   }
  },
  "/api/v2/alerts": {
   "get": {
    "operationId": "get-alerts",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Filter by rule name.",
      "in": "query",
      "name": "rule",
      "schema": {
       "description": "Filter by rule name.",
       "type": "string",
       "x-description-zh": "按规则名过滤。"
      }
     },
     {
      "description": "Filter by kind: fire for alerts, resolve for recoveries.",
      "in": "query",
      "name": "kind",
      "schema": {
       "description": "Filter by kind: fire for alerts, resolve for recoveries.",
       "enum": [
        "fire",
        "resolve"
       ],
       "type": "object",
       "x-description-zh": "按种类过滤:fire 告警;resolve 恢复。",
       "x-gocdn-type": "AlertKind"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List recent alerts and recoveries",
    "tags": [
     "alerts"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出最近告警与恢复记录"
   }
  },
  "/api/v2/api-keys": {
   "get": {
    "operationId": "get-api-keys",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List API keys",
    "tags": [
     "api-keys"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "列出 API Key"
   },
   "post": {
    "operationId": "post-api-keys",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "allow_ips": {
          "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
          "type": "object",
          "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
          "x-gocdn-type": "ApiKeyAllowIps"
         },
         "expires_at": {
          "description": "Expires at",
          "type": "string",
          "x-description-zh": "过期时间"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "scopes": {
          "description": "Granted scopes, same values as scopes at creation",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "授权范围,取值同创建时的 scopes。"
         }
        },
        "required": [
         "name",
         "scopes"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create API key",
    "tags": [
     "api-keys"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "创建 API Key"
   }
  },
  "/api/v2/api-keys/{id}": {
   "delete": {
    "operationId": "delete-api-keys-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete API key",
    "tags": [
     "api-keys"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "删除 API Key"
   },
   "put": {
    "operationId": "put-api-keys-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "reset": true
       },
       "schema": {
        "properties": {
         "allow_ips": {
          "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
          "type": "object",
          "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
          "x-gocdn-type": "ApiKeyAllowIps"
         },
         "reset": {
          "description": "When true, issue a new key; the old one stops working at once",
          "type": "boolean",
          "x-description-zh": "为 true 时换新 key,旧 key 立即失效。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update API key IP allowlist or reset it",
    "tags": [
     "api-keys"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改 API Key 的 IP 白名单或重置"
   }
  },
  "/api/v2/auth/captcha": {
   "get": {
    "operationId": "get-auth-captcha",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Get captcha",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "获取图形验证码"
   }
  },
  "/api/v2/auth/login": {
   "post": {
    "operationId": "post-auth-login",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "captcha_code": {
          "description": "Characters shown in the captcha image",
          "type": "string",
          "x-description-zh": "图形验证码上显示的字符。"
         },
         "captcha_id": {
          "description": "Captcha id from GET /auth/captcha; required after repeated failed logins",
          "type": "string",
          "x-description-zh": "图形验证码 id,来自 GET /auth/captcha;连续登录失败后必填。"
         },
         "password": {
          "description": "Login password",
          "type": "string",
          "x-description-zh": "登录口令。"
         },
         "totp_code": {
          "description": "Current 6-digit TOTP code, or an unused recovery code (XXXXX-XXXXX, consumed on use); required when the account has TOTP enabled",
          "type": "string",
          "x-description-zh": "动态口令(TOTP)的 6 位当前码,或一个未用过的恢复码(XXXXX-XXXXX,用后作废);账号启用动态口令时必填。"
         },
         "username": {
          "description": "Username",
          "type": "string",
          "x-description-zh": "用户名"
         },
         "verify_code": {
          "description": "Second-factor login code. Required when the account has email/SMS code login (login_verify) enabled; obtain it first via POST /verify-codes (purpose=login)",
          "type": "string",
          "x-description-zh": "登录二次验证码。账号开了邮件/短信验证码登录(login_verify)时必填,先经 POST /verify-codes(purpose=login)获取。"
         }
        },
        "required": [
         "password",
         "username"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Log in",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "登录"
   }
  },
  "/api/v2/auth/logout": {
   "post": {
    "operationId": "post-auth-logout",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Log out",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "退出登录"
   }
  },
  "/api/v2/auth/password": {
   "put": {
    "operationId": "put-auth-password",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "new_password": {
          "description": "New password, 8 to 128 characters",
          "example": "correct-horse-battery",
          "type": "string",
          "x-description-zh": "新口令,8 到 128 个字符。"
         },
         "old_password": {
          "description": "Current password",
          "type": "string",
          "x-description-zh": "原口令。"
         }
        },
        "required": [
         "new_password",
         "old_password"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Change password",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改口令"
   }
  },
  "/api/v2/auth/password-reset": {
   "post": {
    "operationId": "post-auth-password-reset",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "channel": "email",
        "code": "123456",
        "new_password": "${NEW_PASSWORD}",
        "target": "user@example.com"
       },
       "schema": {
        "properties": {
         "channel": {
          "description": "Recover by email or by phone number",
          "enum": [
           "email",
           "sms"
          ],
          "type": "string",
          "x-description-zh": "按邮箱还是手机号找回。"
         },
         "code": {
          "description": "Verification code sent to target (POST /verify-codes, purpose=reset_password)",
          "type": "string",
          "x-description-zh": "发到 target 的验证码(POST /verify-codes,purpose=reset_password)。"
         },
         "new_password": {
          "description": "New password, 8 to 128 characters",
          "example": "correct-horse-battery",
          "type": "string",
          "x-description-zh": "新口令,8 到 128 个字符。"
         },
         "target": {
          "description": "Email or phone number bound to the account",
          "type": "string",
          "x-description-zh": "账号绑定的邮箱或手机号。"
         }
        },
        "required": [
         "channel",
         "code",
         "new_password",
         "target"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Reset password",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "找回密码"
   }
  },
  "/api/v2/auth/refresh": {
   "post": {
    "operationId": "post-auth-refresh",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "refresh_token": {
          "description": "Refresh token, exchanged for a new token pair",
          "type": "string",
          "x-description-zh": "刷新令牌,用来换新的一对令牌。"
         }
        },
        "required": [
         "refresh_token"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Refresh token",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "刷新令牌"
   }
  },
  "/api/v2/auth/sso": {
   "post": {
    "operationId": "post-auth-sso",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "sso_ticket": "eyJib2R5Ijp7fX0"
       },
       "schema": {
        "properties": {
         "sso_ticket": {
          "description": "Login ticket issued by the super admin: base64url (no padding) bytes of a licwire envelope (kind sso_ticket)",
          "type": "string",
          "x-description-zh": "超管签发的登录票:licwire 信封(kind sso_ticket)字节的 base64url(无填充)。"
         }
        },
        "required": [
         "sso_ticket"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Admin SSO login",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "超管代登录"
   }
  },
  "/api/v2/auth/switch": {
   "post": {
    "operationId": "post-auth-switch",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "user_id": 2
       },
       "schema": {
        "properties": {
         "user_id": {
          "description": "User ID",
          "type": "integer",
          "x-description-zh": "用户 ID"
         }
        },
        "required": [
         "user_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Switch admin to user",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "管理员切换到用户"
   }
  },
  "/api/v2/auth/switch-login": {
   "post": {
    "operationId": "post-auth-switch-login",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "switch_ticket": {
          "description": "One-time switch ticket obtained by an administrator.",
          "type": "string",
          "x-description-zh": "管理员换到的一次性切换票。"
         }
        },
        "required": [
         "switch_ticket"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Log in with a switch ticket",
    "tags": [
     "auth"
    ],
    "x-summary-zh": "凭切换票登录"
   }
  },
  "/api/v2/auth/switch-ticket": {
   "post": {
    "operationId": "post-auth-switch-ticket",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "user_id": 2
       },
       "schema": {
        "properties": {
         "user_id": {
          "description": "User ID",
          "type": "integer",
          "x-description-zh": "用户 ID"
         }
        },
        "required": [
         "user_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create a one-time switch ticket",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "管理员换一张切换到用户的一次性票"
   }
  },
  "/api/v2/auth/totp": {
   "delete": {
    "operationId": "delete-auth-totp",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "code": {
          "description": "Verification code sent to target (POST /verify-codes, purpose=reset_password)",
          "type": "string",
          "x-description-zh": "发到 target 的验证码(POST /verify-codes,purpose=reset_password)。"
         }
        },
        "required": [
         "code"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Disable TOTP",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "关闭动态口令"
   },
   "post": {
    "operationId": "post-auth-totp",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Generate TOTP secret",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "生成动态口令密钥"
   },
   "put": {
    "operationId": "put-auth-totp",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "code": {
          "description": "Verification code sent to target (POST /verify-codes, purpose=reset_password)",
          "type": "string",
          "x-description-zh": "发到 target 的验证码(POST /verify-codes,purpose=reset_password)。"
         }
        },
        "required": [
         "code"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Enable TOTP",
    "tags": [
     "auth"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "启用动态口令"
   }
  },
  "/api/v2/bans": {
   "get": {
    "operationId": "get-bans",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "A single address matches exactly; a CIDR returns every ban inside that network (single addresses and networks no shorter than it).",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "A single address matches exactly; a CIDR returns every ban inside that network (single addresses and networks no shorter than it).",
       "type": "string",
       "x-description-zh": "给单个地址精确匹配;给 CIDR 网段则返回落入该网段的全部封禁(单地址条目,及前缀不短于该网段的网段条目)。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "true = only bans that have not expired.",
      "in": "query",
      "name": "active",
      "schema": {
       "description": "true = only bans that have not expired.",
       "type": "boolean",
       "x-description-zh": "true = 只看未到期的。"
      }
     },
     {
      "description": "Filter by scope (global = global blacklist).",
      "in": "query",
      "name": "level",
      "schema": {
       "description": "Filter by scope (global = global blacklist).",
       "enum": [
        "site",
        "tenant",
        "global"
       ],
       "type": "string",
       "x-description-zh": "按作用范围过滤(global = 全局黑名单)。"
      }
     },
     {
      "description": "Filter by source: manual = created in the panel; node = banned automatically by a node (challenge limit exceeded, rule ban, handshake flood, etc.).",
      "in": "query",
      "name": "source",
      "schema": {
       "description": "Filter by source: manual = created in the panel; node = banned automatically by a node (challenge limit exceeded, rule ban, handshake flood, etc.).",
       "enum": [
        "manual",
        "node"
       ],
       "type": "string",
       "x-description-zh": "按来源过滤:manual = 面板下的(人工);node = 节点自动封的(挑战超限、规则 ban、握手洪水等)。"
      }
     },
     {
      "description": "Filter by source type (manual / cc / waf / scan / status / tls / intel). Accepts a comma-separated list (e.g. status,tls; duplicates are dropped); every item must be one of the seven values, otherwise 422. Omit for all.",
      "in": "query",
      "name": "source_type",
      "schema": {
       "description": "Filter by source type (manual / cc / waf / scan / status / tls / intel). Accepts a comma-separated list (e.g. status,tls; duplicates are dropped); every item must be one of the seven values, otherwise 422. Omit for all.",
       "example": "status,tls",
       "type": "string",
       "x-description-zh": "按来源细类过滤(manual / cc / waf / scan / status / tls / intel);可逗号分隔多个(如 status,tls,重复的去重),每项都须是这七个值之一,否则 422;不带为全部。"
      }
     },
     {
      "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
      "in": "query",
      "name": "created_from",
      "schema": {
       "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
       "type": "string",
       "x-description-zh": "只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List bans",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出封禁"
   },
   "post": {
    "operationId": "post-bans",
    "parameters": [
     {
      "description": "Admin only: tenant the ban belongs to. Required for level=tenant; optional for level=site (defaults to the site owner, and must match it when given). Ignored for tenant credentials",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: tenant the ban belongs to. Required for level=tenant; optional for level=site (defaults to the site owner, and must match it when given). Ignored for tenant credentials",
       "type": "integer",
       "x-description-zh": "仅管理员可用:封禁所属租户。租户级必填;站点级可省(按站主),带了须与站主一致。租户凭据调用时忽略。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ip": "198.51.100.7",
        "level": "tenant"
       },
       "schema": {
        "properties": {
         "expires_at": {
          "description": "Expiry time; null = permanent.",
          "type": "string",
          "x-description-zh": "到期时刻;null = 永久。"
         },
         "ip": {
          "description": "IP or CIDR.",
          "type": "string",
          "x-description-zh": "IP 或 CIDR。"
         },
         "level": {
          "description": "Scope: site = one site; tenant = all sites of the tenant; global = the whole network (admin only).",
          "enum": [
           "site",
           "tenant",
           "global"
          ],
          "type": "string",
          "x-description-zh": "作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。"
         },
         "reason": {
          "description": "Reason: manual by default for bans created in the panel; for automatic bans by a node, the triggering rule (ruleset/rule id such as cc.level.r5/r1) or module name (ssl_handshake = handshake flood), or auto when there is no rule.",
          "type": "string",
          "x-description-zh": "原因:人工封禁默认 manual;节点自动封的是触发规则(规则集/规则 id,如 cc.level.r5/r1)或模块名(ssl_handshake = 握手洪水),无规则的记 auto。"
         },
         "site_id": {
          "description": "Site id, required when level=site; 0 otherwise.",
          "type": "integer",
          "x-description-zh": "level=site 时必填的站点 id;其余为 0。"
         }
        },
        "required": [
         "ip",
         "level"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create ban",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建封禁"
   }
  },
  "/api/v2/bans/site-counts": {
   "get": {
    "operationId": "get-bans-site-counts",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by source type (manual / cc / waf / scan / status / tls / intel). Accepts a comma-separated list (e.g. status,tls; duplicates are dropped); every item must be one of the seven values, otherwise 422. Omit for all.",
      "in": "query",
      "name": "source_type",
      "schema": {
       "description": "Filter by source type (manual / cc / waf / scan / status / tls / intel). Accepts a comma-separated list (e.g. status,tls; duplicates are dropped); every item must be one of the seven values, otherwise 422. Omit for all.",
       "example": "status,tls",
       "type": "string",
       "x-description-zh": "按来源细类过滤(manual / cc / waf / scan / status / tls / intel);可逗号分隔多个(如 status,tls,重复的去重),每项都须是这七个值之一,否则 422;不带为全部。"
      }
     },
     {
      "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
      "in": "query",
      "name": "created_from",
      "schema": {
       "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
       "type": "string",
       "x-description-zh": "只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Count bans per site",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "按站点统计封禁"
   }
  },
  "/api/v2/bans/source-counts": {
   "get": {
    "operationId": "get-bans-source-counts",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
      "in": "query",
      "name": "created_from",
      "schema": {
       "description": "Only bans created at or after this instant (e.g. \"added today\"). A repeat ban by a node extends the existing row and does not change its creation time, so only the first record counts.",
       "type": "string",
       "x-description-zh": "只看该时刻(含)及之后创建的封禁,用于「今天新增」。同一对象节点再封是续期,不改创建时刻,所以只算首次落库。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Count bans per source type",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "按来源细类统计封禁"
   }
  },
  "/api/v2/bans/unban": {
   "post": {
    "operationId": "post-bans-unban",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ips": [
         "198.51.100.7"
        ],
        "level": "tenant"
       },
       "schema": {
        "properties": {
         "all": {
          "description": "true = unban the whole site, clearing every ban of site_id; level=site only and counts as one unban toward the daily limit.",
          "type": "boolean",
          "x-description-zh": "true = 全站解封:清空 site_id 这个站的全部封禁,只用于 level=site,计 1 次每天解封次数。"
         },
         "ips": {
          "description": "IPs/CIDRs to unban (omit when all=true, required otherwise); the number per request is limited by protect.unban_batch_max and the daily count per tenant by protect.unban_daily_max.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "要解封的 IP/CIDR(all=true 时不带,否则必填);一次条数受 protect.unban_batch_max 约束,租户每天次数受 protect.unban_daily_max 约束。"
         },
         "level": {
          "description": "Scope: site = one site; tenant = all sites of the tenant; global = the whole network (admin only).",
          "enum": [
           "site",
           "tenant",
           "global"
          ],
          "type": "string",
          "x-description-zh": "作用范围:site = 某站点;tenant = 该租户全部站点;global = 全网(仅管理员)。"
         },
         "site_id": {
          "description": "Site id, required when level=site; 0 otherwise.",
          "type": "integer",
          "x-description-zh": "level=site 时必填的站点 id;其余为 0。"
         }
        },
        "required": [
         "level"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Unban by IP",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "按 IP 解封"
   }
  },
  "/api/v2/bans/unban-quota": {
   "get": {
    "operationId": "get-bans-unban-quota",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Unban quota and today's usage",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "解封配额与今日已用"
   }
  },
  "/api/v2/bans/unbans": {
   "get": {
    "operationId": "get-bans-unbans",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by site (site-level unbans only).",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site (site-level unbans only).",
       "type": "integer",
       "x-description-zh": "按站点过滤(只含站点级解封)。"
      }
     },
     {
      "description": "Only records at or after this time (for example to count today's unbans).",
      "in": "query",
      "name": "since",
      "schema": {
       "description": "Only records at or after this time (for example to count today's unbans).",
       "type": "string",
       "x-description-zh": "只列这个时刻及之后的(如数今天用了几次)。"
      }
     },
     {
      "description": "Filter by whether an administrator unbanned on the site owner's behalf; pass false to count the owner's own unbans today (those done by an administrator do not use the owner's quota).",
      "in": "query",
      "name": "by_admin",
      "schema": {
       "description": "Filter by whether an administrator unbanned on the site owner's behalf; pass false to count the owner's own unbans today (those done by an administrator do not use the owner's quota).",
       "type": "boolean",
       "x-description-zh": "按是否管理员代站主解封过滤;数站主今天用掉的次数传 false(代解不占站主次数)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List unban records",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出解封记录"
   }
  },
  "/api/v2/bans/{id}": {
   "delete": {
    "operationId": "delete-bans-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete ban",
    "tags": [
     "bans"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除封禁"
   }
  },
  "/api/v2/bot-settings": {
   "get": {
    "operationId": "get-bot-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get bot settings",
    "tags": [
     "bot-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取 Bot 设置"
   },
   "put": {
    "operationId": "put-bot-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "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
        }
       },
       "schema": {
        "properties": {
         "actions": {
          "description": "Action per class; defaults are allow for search engines and monitors/tools, log for automation tools, challenge for headless browsers and block for malicious bots and fake crawlers. headless, malicious and fake belong to WAF enhanced.",
          "type": "object",
          "x-description-zh": "按类处置;缺省搜索引擎、监控·工具放行,自动化工具只记录,无头浏览器验证,恶意 Bot 与伪造爬虫拦截。headless、malicious、fake 属 WAF 增强。"
         },
         "challenge": {
          "description": "Challenge kind used when the action is challenge - js (invisible), slide, rotate, click or captcha (default js).",
          "enum": [
           "js",
           "slide",
           "rotate",
           "click",
           "captcha"
          ],
          "type": "string",
          "x-description-zh": "处置为 challenge 时的验证方式:js 无感、slide 滑块、rotate 旋转图片、click 点选、captcha 字符(缺省 js)。"
         },
         "enabled": {
          "description": "Master switch; false = no site does bot detection.",
          "type": "boolean",
          "x-description-zh": "总开关;false = 所有站点都不做 Bot 判定。"
         },
         "enhanced": {
          "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; headless browsers, malicious bots and fake crawlers are treated as ordinary visitors and not scored, settings kept); ignored on update.",
          "enum": [
           "full",
           "readonly",
           "basic"
          ],
          "readOnly": true,
          "type": "string",
          "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(无头浏览器、恶意 Bot、伪造爬虫按普通访客,不打分,设置保留);修改时忽略。"
         },
         "exceptions": {
          "description": "Exceptions - matching requests skip bot detection (at least one of path, cidr and ja4; several in one entry must all match).",
          "items": {
           "type": "object"
          },
          "type": "array",
          "x-description-zh": "例外:命中的请求不做 Bot 判定(path、cidr、ja4 至少一项,同一条里多项须同时满足)。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "protect": {
          "description": "Protected endpoints (path prefixes such as /login, WAF enhanced) - requesting them without loading a page first adds to the score.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "保护接口(路径前缀,如 /login,WAF 增强):没看过页面直接请求它们加分。"
         },
         "score": {
          "description": "Behaviour score bands (WAF enhanced, 0-100) - below js pass; js to slide invisible challenge; slide to block challenge by kind; from block act as a malicious bot. Requires js \u003c slide \u003c block. A visitor who passes a challenge scores 0 for 30 minutes.",
          "type": "object",
          "x-description-zh": "行为评分分段(WAF 增强,0–100):低于 js 放行;js 到 slide 无感验证;slide 到 block 按 kind 验证;达到 block 按恶意 Bot 处置。须 js \u003c slide \u003c block。通过验证的访客 30 分钟内分数清零。"
         },
         "updated_at": {
          "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update bot settings",
    "tags": [
     "bot-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 Bot 设置"
   }
  },
  "/api/v2/bot-stats": {
   "get": {
    "operationId": "get-bot-stats",
    "parameters": [
     {
      "description": "Count this site only; omit for all sites.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Count this site only; omit for all sites.",
       "type": "integer",
       "x-description-zh": "只统计该网站;不带为全部网站。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get bot stats",
    "tags": [
     "bot-stats"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取 Bot 统计"
   }
  },
  "/api/v2/cache-groups": {
   "get": {
    "operationId": "get-cache-groups",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List cache groups",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出缓存分组"
   },
   "post": {
    "operationId": "post-cache-groups",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "cache": {
          "description": "Cache rules, same as the cache field ({rules, ignore_params}) of the node contract schema/site.json; validated by the server against the contract.",
          "type": "object",
          "x-description-zh": "缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。",
          "x-gocdn-type": "CacheConfig"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "from_site_id": {
          "description": "Save from a site (rules are taken from the site's current effective value; cache is ignored).",
          "type": "integer",
          "x-description-zh": "从站点另存(规则取该站当前生效值,忽略 cache)。"
         },
         "is_default": {
          "description": "Platform default group (exactly one).",
          "readOnly": true,
          "type": "boolean",
          "x-description-zh": "平台默认分组(恰一个)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         },
         "switch_site": {
          "description": "After saving, make the site reference the new group.",
          "type": "boolean",
          "x-description-zh": "另存后让该站引用新分组。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create cache group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建缓存分组"
   }
  },
  "/api/v2/cache-groups/{id}": {
   "delete": {
    "operationId": "delete-cache-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete cache group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除缓存分组"
   },
   "get": {
    "operationId": "get-cache-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get cache group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取缓存分组"
   },
   "put": {
    "operationId": "put-cache-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "cache": {
          "description": "Cache rules, same as the cache field ({rules, ignore_params}) of the node contract schema/site.json; validated by the server against the contract.",
          "type": "object",
          "x-description-zh": "缓存规则,同节点契约 schema/site.json 的 cache({rules, ignore_params}),服务端按契约校验。",
          "x-gocdn-type": "CacheConfig"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update cache group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改缓存分组"
   }
  },
  "/api/v2/cache-groups/{id}/copy": {
   "post": {
    "operationId": "post-cache-groups-id-copy",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Copy cache group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "复制缓存分组"
   }
  },
  "/api/v2/cache-groups/{id}/set-default": {
   "post": {
    "operationId": "post-cache-groups-id-set-default",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set as platform default group",
    "tags": [
     "cache-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "设为平台默认分组"
   }
  },
  "/api/v2/cache-jobs": {
   "get": {
    "operationId": "get-cache-jobs",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list jobs of this type.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Only list jobs of this type.",
       "enum": [
        "purge_url",
        "purge_dir",
        "prefetch"
       ],
       "type": "string",
       "x-description-zh": "只列该类型的任务。"
      }
     },
     {
      "description": "If it starts with http:// or https://, exact match on the full URL, normalized as on submission (the job's URL list contains it); otherwise exact match on the host name.",
      "in": "query",
      "name": "url",
      "schema": {
       "description": "If it starts with http:// or https://, exact match on the full URL, normalized as on submission (the job's URL list contains it); otherwise exact match on the host name.",
       "type": "string",
       "x-description-zh": "以 http:// 或 https:// 开头时按完整 URL(同提交时规范化)精确匹配(任务的 URL 列表里含它);否则按主机名精确匹配。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List purge/prefetch jobs",
    "tags": [
     "cache-jobs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出刷新/预热任务"
   },
   "post": {
    "operationId": "post-cache-jobs",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "type": "purge_url",
        "urls": [
         "https://www.example.com/index.html"
        ]
       },
       "schema": {
        "properties": {
         "type": {
          "description": "purge_url = purge URLs; purge_dir = purge directories (URL ends with /); prefetch = prefetch.",
          "enum": [
           "purge_url",
           "purge_dir",
           "prefetch"
          ],
          "type": "string",
          "x-description-zh": "purge_url 刷新 URL;purge_dir 刷新目录(URL 以 / 结尾);prefetch 预热。"
         },
         "urls": {
          "description": "http(s)://host/path (normalized, see create); at most 100 entries per prefetch.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "http(s)://主机/路径(规范化后,见创建接口);预热一次最多 100 条。"
         }
        },
        "required": [
         "type",
         "urls"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create purge/prefetch job",
    "tags": [
     "cache-jobs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建刷新/预热任务"
   }
  },
  "/api/v2/cache-jobs/{id}": {
   "get": {
    "operationId": "get-cache-jobs-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get purge/prefetch job",
    "tags": [
     "cache-jobs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取刷新/预热任务"
   }
  },
  "/api/v2/cache-policy": {
   "get": {
    "operationId": "get-cache-policy",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Cache policy",
    "tags": [
     "cache-policy"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "缓存策略"
   },
   "put": {
    "operationId": "put-cache-policy",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "default_group_id": {
          "description": "Platform default group; null = no group yet.",
          "type": "integer",
          "x-description-zh": "平台默认分组;null = 还没有分组。"
         }
        },
        "required": [
         "default_group_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set the tenant's default group",
    "tags": [
     "cache-policy"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设本租户的默认分组"
   }
  },
  "/api/v2/cache-policy/reset-sites": {
   "post": {
    "operationId": "post-cache-policy-reset-sites",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Reset all sites to the default group",
    "tags": [
     "cache-policy"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "全部站点改回按默认分组"
   }
  },
  "/api/v2/cache-presets": {
   "get": {
    "operationId": "get-cache-presets",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Factory default cache rules",
    "tags": [
     "cache-presets"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "出厂标配缓存规则"
   }
  },
  "/api/v2/cache-quota": {
   "get": {
    "operationId": "get-cache-quota",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Daily purge/prefetch quota and today's usage",
    "tags": [
     "cache-quota"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "刷新/预热每日限额与今日已用"
   }
  },
  "/api/v2/cache-sites/{id}": {
   "get": {
    "operationId": "get-cache-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site cache mode",
    "tags": [
     "cache-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点的缓存方式"
   },
   "put": {
    "operationId": "put-cache-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的站点 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "group_id": {
          "description": "Group referenced explicitly; null = follows the default group.",
          "type": "integer",
          "x-description-zh": "显式引用的分组;null = 按默认分组。"
         }
        },
        "required": [
         "group_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set the cache group used by a site",
    "tags": [
     "cache-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点引用缓存分组"
   }
  },
  "/api/v2/cc-filters": {
   "get": {
    "operationId": "get-cc-filters",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by name substring.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Filter by name substring.",
       "type": "string",
       "x-description-zh": "按名称包含过滤。"
      }
     },
     {
      "description": "platform = platform objects only; tenant = tenant objects only.",
      "in": "query",
      "name": "owner",
      "schema": {
       "description": "platform = platform objects only; tenant = tenant objects only.",
       "enum": [
        "platform",
        "tenant"
       ],
       "type": "string",
       "x-description-zh": "platform = 只看平台对象;tenant = 只看租户对象。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List CC filters",
    "tags": [
     "cc-filters"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出CC 过滤器"
   },
   "post": {
    "operationId": "post-cc-filters",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "max": 20,
        "name": "rate-5-20",
        "per_uri_max": 10,
        "type": "rate",
        "window_s": 5
       },
       "schema": {
        "properties": {
         "count_key": {
          "description": "Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip).",
          "enum": [
           "ip",
           "ja4",
           "ip_ja4"
          ],
          "type": "string",
          "x-description-zh": "按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。"
         },
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "kind": {
          "description": "Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate.",
          "type": "string",
          "x-description-zh": "挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。"
         },
         "max": {
          "description": "Requests allowed within the window.",
          "type": "integer",
          "x-description-zh": "窗口内允许的请求数。"
         },
         "mode": {
          "description": "Required for url_auth: signing scheme. a = ?\u003csign_arg\u003e=md5(key+path+timestamp)\u0026\u003ctime_arg\u003e=timestamp; b = ?\u003csign_arg\u003e=timestamp-random-uid-md5(path-timestamp-random-uid-key).",
          "enum": [
           "a",
           "b"
          ],
          "type": "string",
          "x-description-zh": "url_auth 必填:鉴权方式。a = ?\u003csign_arg\u003e=md5(密钥+路径+时间戳)\u0026\u003ctime_arg\u003e=时间戳;b = ?\u003csign_arg\u003e=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "per_uri_max": {
          "description": "rate: per-URI limit; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "rate:单 URI 上限;0 = 不限。"
         },
         "sign_arg": {
          "description": "Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen).",
          "type": "string",
          "x-description-zh": "url_auth 必填:签名参数名(字母、数字、下划线、连字符)。"
         },
         "sign_use_max": {
          "description": "url_auth: how many times the same signature may be used; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "url_auth:同一签名最多用几次;0 = 不限。"
         },
         "time_arg": {
          "description": "Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b.",
          "type": "string",
          "x-description-zh": "url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。"
         },
         "ttl_s": {
          "description": "Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time.",
          "type": "integer",
          "x-description-zh": "url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。"
         },
         "type": {
          "description": "rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt).",
          "enum": [
           "rate",
           "challenge",
           "url_auth"
          ],
          "type": "string",
          "x-description-zh": "rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。"
         },
         "window_s": {
          "description": "Counting window in seconds.",
          "type": "integer",
          "x-description-zh": "统计窗口秒数。"
         }
        },
        "required": [
         "max",
         "name",
         "type",
         "window_s"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create CC filter",
    "tags": [
     "cc-filters"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建CC 过滤器"
   }
  },
  "/api/v2/cc-filters/{id}": {
   "delete": {
    "operationId": "delete-cc-filters-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete CC filter",
    "tags": [
     "cc-filters"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除CC 过滤器"
   },
   "get": {
    "operationId": "get-cc-filters-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CC filter",
    "tags": [
     "cc-filters"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取CC 过滤器"
   },
   "put": {
    "operationId": "put-cc-filters-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "max": 20,
        "name": "rate-5-20",
        "per_uri_max": 10,
        "type": "rate",
        "window_s": 5
       },
       "schema": {
        "properties": {
         "count_key": {
          "description": "Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip).",
          "enum": [
           "ip",
           "ja4",
           "ip_ja4"
          ],
          "type": "string",
          "x-description-zh": "按谁计数(rate/challenge):ip = 按客户端 IP(缺省,现有行为);ja4 = 只按 TLS 指纹计数(不分 IP),同指纹的真实访客会一起计入,所以只许配 log 动作,规则条目配 ban/deny 保存时 422;要处置用 ip_ja4 = 同一 IP 且同一指纹合计。非 HTTPS 请求没有指纹,ja4/ip_ja4 退回按 IP。url_auth 不用,只能是 ip。"
         },
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "kind": {
          "description": "Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate.",
          "type": "string",
          "x-description-zh": "挑战类型(challenge 必填):js/redirect/slide/captcha/click/delay_jump/rotate/cookie;rate 不带。"
         },
         "max": {
          "description": "Requests allowed within the window.",
          "type": "integer",
          "x-description-zh": "窗口内允许的请求数。"
         },
         "mode": {
          "description": "Required for url_auth: signing scheme. a = ?\u003csign_arg\u003e=md5(key+path+timestamp)\u0026\u003ctime_arg\u003e=timestamp; b = ?\u003csign_arg\u003e=timestamp-random-uid-md5(path-timestamp-random-uid-key).",
          "enum": [
           "a",
           "b"
          ],
          "type": "string",
          "x-description-zh": "url_auth 必填:鉴权方式。a = ?\u003csign_arg\u003e=md5(密钥+路径+时间戳)\u0026\u003ctime_arg\u003e=时间戳;b = ?\u003csign_arg\u003e=时间戳-随机串-uid-md5(路径-时间戳-随机串-uid-密钥)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "per_uri_max": {
          "description": "rate: per-URI limit; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "rate:单 URI 上限;0 = 不限。"
         },
         "sign_arg": {
          "description": "Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen).",
          "type": "string",
          "x-description-zh": "url_auth 必填:签名参数名(字母、数字、下划线、连字符)。"
         },
         "sign_use_max": {
          "description": "url_auth: how many times the same signature may be used; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "url_auth:同一签名最多用几次;0 = 不限。"
         },
         "time_arg": {
          "description": "Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b.",
          "type": "string",
          "x-description-zh": "url_auth 且 mode=a 必填:时间戳参数名;mode=b 不带。"
         },
         "ttl_s": {
          "description": "Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time.",
          "type": "integer",
          "x-description-zh": "url_auth 必填(1~2592000):签名时间戳与当前时间最多相差几秒。"
         },
         "type": {
          "description": "rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt).",
          "enum": [
           "rate",
           "challenge",
           "url_auth"
          ],
          "type": "string",
          "x-description-zh": "rate = 请求频率;challenge = 挑战(kind 指定类型);url_auth = URL 鉴权(签名密钥取站点 config.url_auth_salt)。"
         },
         "window_s": {
          "description": "Counting window in seconds.",
          "type": "integer",
          "x-description-zh": "统计窗口秒数。"
         }
        },
        "required": [
         "max",
         "name",
         "type",
         "window_s"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update CC filter",
    "tags": [
     "cc-filters"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改CC 过滤器"
   }
  },
  "/api/v2/cc-matches": {
   "get": {
    "operationId": "get-cc-matches",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by name substring.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Filter by name substring.",
       "type": "string",
       "x-description-zh": "按名称包含过滤。"
      }
     },
     {
      "description": "platform = platform objects only; tenant = tenant objects only.",
      "in": "query",
      "name": "owner",
      "schema": {
       "description": "platform = platform objects only; tenant = tenant objects only.",
       "enum": [
        "platform",
        "tenant"
       ],
       "type": "string",
       "x-description-zh": "platform = 只看平台对象;tenant = 只看租户对象。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List CC matchers",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出CC 匹配器"
   },
   "post": {
    "operationId": "post-cc-matches",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "name": "static",
        "when": {
         "f": "req_uri",
         "op": "contains",
         "v": [
          ".js",
          ".css"
         ]
        }
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "when": {
          "description": "Rule DSL condition: a combination of all/any/not, or a leaf {f, op, v, set, neg}; validated by the server and errors are returned as 422 (field is a JSON Pointer, code is the lowercase DSL error code). null = match everything.",
          "type": "object",
          "x-description-zh": "规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create CC matcher",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建CC 匹配器"
   }
  },
  "/api/v2/cc-matches/replay": {
   "post": {
    "operationId": "post-cc-matches-replay",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "when": {
         "f": "ja4",
         "op": "eq",
         "v": [
          "t13d1516h2_8daaf6152771_e5627efa2ab1"
         ]
        }
       },
       "schema": {
        "properties": {
         "site_id": {
          "description": "Count this site's traffic only; omitted = every site visible to the caller.",
          "type": "integer",
          "x-description-zh": "只算这个网站的流量;不给 = 当前身份可见的全部网站。"
         },
         "when": {
          "description": "Rule DSL condition: a combination of all/any/not, or a leaf {f, op, v, set, neg}; validated by the server and errors are returned as 422 (field is a JSON Pointer, code is the lowercase DSL error code). null = match everything.",
          "type": "object",
          "x-description-zh": "规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Replay a CC matcher draft",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "回放CC 匹配器草稿"
   }
  },
  "/api/v2/cc-matches/{id}": {
   "delete": {
    "operationId": "delete-cc-matches-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete CC matcher",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除CC 匹配器"
   },
   "get": {
    "operationId": "get-cc-matches-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CC matcher",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取CC 匹配器"
   },
   "put": {
    "operationId": "put-cc-matches-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "name": "static",
        "when": {
         "f": "req_uri",
         "op": "contains",
         "v": [
          ".js",
          ".css"
         ]
        }
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "when": {
          "description": "Rule DSL condition: a combination of all/any/not, or a leaf {f, op, v, set, neg}; validated by the server and errors are returned as 422 (field is a JSON Pointer, code is the lowercase DSL error code). null = match everything.",
          "type": "object",
          "x-description-zh": "规则 DSL 条件:all/any/not 组合,或 {f, op, v, set, neg} 叶子;由 internal/ruledsl 校验,错误以 422 透传(field 为 JSON Pointer,code 为小写的 ruledsl 错误码)。 null = 匹配全部。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update CC matcher",
    "tags": [
     "cc-matches"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改CC 匹配器"
   }
  },
  "/api/v2/cc-rules": {
   "get": {
    "operationId": "get-cc-rules",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by enabled state.",
      "in": "query",
      "name": "enabled",
      "schema": {
       "description": "Filter by enabled state.",
       "type": "boolean",
       "x-description-zh": "按启用状态过滤。"
      }
     },
     {
      "description": "Filter by name substring.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Filter by name substring.",
       "type": "string",
       "x-description-zh": "按名称包含过滤。"
      }
     },
     {
      "description": "platform = platform objects only; tenant = tenant objects only.",
      "in": "query",
      "name": "owner",
      "schema": {
       "description": "platform = platform objects only; tenant = tenant objects only.",
       "enum": [
        "platform",
        "tenant"
       ],
       "type": "string",
       "x-description-zh": "platform = 只看平台对象;tenant = 只看租户对象。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List CC rule groups",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出CC 规则组"
   },
   "post": {
    "operationId": "post-cc-rules",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "items": [
         {
          "action": "ban",
          "filter_ids": [
           8
          ],
          "match_id": 3
         }
        ],
        "name": "js"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "items": {
          "description": "Rule items, executed in order; the count is limited by the setting protect.cc_rule_items_max.",
          "items": {
           "type": "object",
           "x-gocdn-type": "CcRuleItem"
          },
          "type": "array",
          "x-description-zh": "规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "show_to": {
          "description": "Tenants that can see a platform rule group; empty = visible to all tenants, otherwise only the listed tenants can see it and select it as a site's cc_level. Returned to admins only.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。"
         },
         "sort": {
          "description": "Panel sort order (smaller first).",
          "type": "integer",
          "x-description-zh": "面板排序(小的在前)。"
         },
         "tenant_id": {
          "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
         },
         "visible": {
          "default": true,
          "description": "Shown in the site's rule group drop-down.",
          "type": "boolean",
          "x-description-zh": "在站点的规则组下拉里展示。"
         }
        },
        "required": [
         "items",
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create CC rule group",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建CC 规则组"
   }
  },
  "/api/v2/cc-rules/batch-enable": {
   "post": {
    "operationId": "post-cc-rules-batch-enable",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "enabled": false,
        "ids": [
         1,
         2
        ]
       },
       "schema": {
        "properties": {
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ids": {
          "description": "IDs of the objects to change, at most 100.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改的对象 id,至多 100 个。"
         }
        },
        "required": [
         "enabled",
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch enable or disable CC rule groups",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量启用或禁用CC规则组"
   }
  },
  "/api/v2/cc-rules/{id}": {
   "delete": {
    "operationId": "delete-cc-rules-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete CC rule group",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除CC 规则组"
   },
   "get": {
    "operationId": "get-cc-rules-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CC rule group",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取CC 规则组"
   },
   "put": {
    "operationId": "put-cc-rules-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "items": [
         {
          "action": "ban",
          "filter_ids": [
           8
          ],
          "match_id": 3
         }
        ],
        "name": "js"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object).",
          "type": "string",
          "x-description-zh": "备注;不给则为空(修改时不给也清空,整体替换)。"
         },
         "enabled": {
          "default": true,
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "items": {
          "description": "Rule items, executed in order; the count is limited by the setting protect.cc_rule_items_max.",
          "items": {
           "type": "object",
           "x-gocdn-type": "CcRuleItem"
          },
          "type": "array",
          "x-description-zh": "规则条目,按序执行;条数受配置 protect.cc_rule_items_max 约束。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "show_to": {
          "description": "Tenants that can see a platform rule group; empty = visible to all tenants, otherwise only the listed tenants can see it and select it as a site's cc_level. Returned to admins only.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "平台规则组的可见租户;空 = 所有租户可见,非空只有列出的租户能看到、能在站点 cc_level 选它。只返回给管理员。"
         },
         "sort": {
          "description": "Panel sort order (smaller first).",
          "type": "integer",
          "x-description-zh": "面板排序(小的在前)。"
         },
         "tenant_id": {
          "description": "Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants).",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "所属租户;null = 平台对象(内置或管理员建,租户只读)。"
         },
         "visible": {
          "default": true,
          "description": "Shown in the site's rule group drop-down.",
          "type": "boolean",
          "x-description-zh": "在站点的规则组下拉里展示。"
         }
        },
        "required": [
         "items",
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update CC rule group",
    "tags": [
     "cc-rules"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改CC 规则组"
   }
  },
  "/api/v2/cc-settings": {
   "get": {
    "operationId": "get-cc-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CC settings",
    "tags": [
     "cc-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取 CC 设置"
   },
   "put": {
    "operationId": "put-cc-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auto_switch": {
         "enabled": false,
         "hold_s": 300,
         "qps_50x": 10,
         "qps_total": 500,
         "rule_id": 2
        },
        "default_rule_id": 10002
       },
       "schema": {
        "properties": {
         "auto_switch": {
          "description": "Settings for automatically switching to a stricter CC rule group.",
          "type": "object",
          "x-description-zh": "CC 防护自动升级设置:攻击时自动切换到更严的规则组。",
          "x-gocdn-type": "CcAutoSwitch"
         },
         "default_page_rule_id": {
          "description": "Platform CC rule group id used by the default page (requests to unbound domains); null or omitted = no protection.",
          "type": "integer",
          "x-description-zh": "默认页(未绑定域名)用的平台 CC 规则组 id;null 或不带 = 不防护。"
         },
         "default_rule_id": {
          "description": "Platform CC rule group id used when a site has not chosen one; null = node default.",
          "type": "integer",
          "x-description-zh": "站点未选规则组时用的平台 CC 规则组 id;null = 节点缺省。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared by CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "updated_at": {
          "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
         }
        },
        "required": [
         "auto_switch",
         "default_rule_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update CC settings",
    "tags": [
     "cc-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 CC 设置"
   }
  },
  "/api/v2/cert-settings": {
   "get": {
    "operationId": "get-cert-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get certificate settings",
    "tags": [
     "cert-settings"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "获取证书设置"
   },
   "put": {
    "operationId": "put-cert-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "default_type": "custom"
       },
       "schema": {
        "properties": {
         "default_type": {
          "description": "The user's own default type (custom/lets/zerossl); null = follow the platform.",
          "type": "string",
          "x-description-zh": "本人设的默认类型(custom/lets/zerossl);null = 跟随平台。"
         }
        },
        "required": [
         "default_type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update certificate settings",
    "tags": [
     "cert-settings"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改证书设置"
   }
  },
  "/api/v2/certify-channels": {
   "get": {
    "operationId": "get-certify-channels",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get identity verification channels",
    "tags": [
     "certify-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "实名通道设置"
   },
   "put": {
    "operationId": "put-certify-channels",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "alipay": {
          "description": "Merchant parameters of Alipay identity verification (alipay.user.certify.open.*).",
          "type": "object",
          "x-description-zh": "支付宝身份验证(alipay.user.certify.open.*)的商户参数。",
          "x-gocdn-type": "CertifyAlipay"
         },
         "wechat": {
          "description": "Parameters of Tencent Cloud FaceID (WeChat face verification, faceid DetectAuth).",
          "type": "object",
          "x-description-zh": "腾讯云慧眼(微信人脸核身,faceid DetectAuth)的参数。",
          "x-gocdn-type": "CertifyWechat"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update identity verification channels",
    "tags": [
     "certify-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改实名通道"
   }
  },
  "/api/v2/certs": {
   "get": {
    "operationId": "get-certs",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Name contains.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Name contains.",
       "type": "string",
       "x-description-zh": "名称包含。"
      }
     },
     {
      "description": "SAN contains (part of a domain or IP).",
      "in": "query",
      "name": "domain",
      "schema": {
       "description": "SAN contains (part of a domain or IP).",
       "type": "string",
       "x-description-zh": "SAN 包含(域名或 IP 的一部分)。"
      }
     },
     {
      "description": "site = site certificate; ip = platform IP certificate; panel = panel certificate (used by the controller's HTTPS listener).",
      "in": "query",
      "name": "scope",
      "schema": {
       "description": "site = site certificate; ip = platform IP certificate; panel = panel certificate (used by the controller's HTTPS listener).",
       "enum": [
        "site",
        "ip",
        "panel"
       ],
       "type": "string",
       "x-description-zh": "site = 站点证书;ip = 平台 IP 证书;panel = 面板证书(主控 HTTPS 监听用)。"
      }
     },
     {
      "description": "Whether enabled",
      "in": "query",
      "name": "enabled",
      "schema": {
       "description": "Whether enabled",
       "type": "boolean",
       "x-description-zh": "是否启用"
      }
     },
     {
      "description": "Only list certificates expiring within N days (including expired ones).",
      "in": "query",
      "name": "expire_days",
      "schema": {
       "description": "Only list certificates expiring within N days (including expired ones).",
       "type": "integer",
       "x-description-zh": "只列 N 天内到期(含已过期)的证书。"
      }
     },
     {
      "description": "Exact certificate ID match.",
      "in": "query",
      "name": "id",
      "schema": {
       "description": "Exact certificate ID match.",
       "type": "integer",
       "x-description-zh": "证书 id 精确匹配。"
      }
     },
     {
      "description": "Comma-separated certificate IDs (at most 200); matches any of them. Combined with id as an intersection.",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Comma-separated certificate IDs (at most 200); matches any of them. Combined with id as an intersection.",
       "type": "string",
       "x-description-zh": "多个证书 id 逗号分隔(至多 200 个),命中其中任一个。"
      }
     },
     {
      "description": "Remark contains.",
      "in": "query",
      "name": "des",
      "schema": {
       "description": "Remark contains.",
       "type": "string",
       "x-description-zh": "备注包含。"
      }
     },
     {
      "description": "Certificate type.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Certificate type.",
       "enum": [
        "custom",
        "lets",
        "zerossl",
        "zerossl_api"
       ],
       "type": "string",
       "x-description-zh": "证书类型。"
      }
     },
     {
      "description": "Certificates using this DNS API credential.",
      "in": "query",
      "name": "dns_api_id",
      "schema": {
       "description": "Certificates using this DNS API credential.",
       "type": "integer",
       "x-description-zh": "用此 DNS API 凭据的证书。"
      }
     },
     {
      "description": "Comma-separated domains or IPs; matches certificates whose SAN contains any of them (exact match).",
      "in": "query",
      "name": "domains",
      "schema": {
       "description": "Comma-separated domains or IPs; matches certificates whose SAN contains any of them (exact match).",
       "type": "string",
       "x-description-zh": "多个域名或 IP,逗号分隔,证书 SAN 里含其中任一个(精确匹配)。"
      }
     },
     {
      "description": "ACME issuance state (uploaded certificates have none).",
      "in": "query",
      "name": "issue_state",
      "schema": {
       "description": "ACME issuance state (uploaded certificates have none).",
       "enum": [
        "pending",
        "running",
        "issued",
        "failed"
       ],
       "type": "string",
       "x-description-zh": "ACME 签发状态(上传的证书没有)。"
      }
     },
     {
      "description": "domain = SAN contains a domain; ip = SAN is all IPs.",
      "in": "query",
      "name": "kind",
      "schema": {
       "description": "domain = SAN contains a domain; ip = SAN is all IPs.",
       "enum": [
        "domain",
        "ip"
       ],
       "type": "string",
       "x-description-zh": "domain = SAN 含域名;ip = SAN 全是 IP。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List certificates",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出证书"
   },
   "post": {
    "operationId": "post-certs",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "acme": {
          "description": "Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.).",
          "readOnly": true,
          "type": "object",
          "x-description-zh": "签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。",
          "x-gocdn-type": "CertAcmeSummary"
         },
         "cert": {
          "description": "Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key).",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "key": {
          "description": "Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key.",
          "type": "string",
          "x-description-zh": "私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "scope": {
          "description": "Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate.",
          "enum": [
           "site",
           "ip",
           "panel"
          ],
          "type": "string",
          "x-description-zh": "证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。"
         },
         "type": {
          "description": "custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API.",
          "type": "string",
          "x-description-zh": "custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create certificate",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建证书"
   }
  },
  "/api/v2/certs/acme-states": {
   "get": {
    "operationId": "get-certs-acme-states",
    "parameters": [
     {
      "description": "Certificate IDs, comma-separated, at most 200.",
      "in": "query",
      "name": "ids",
      "required": true,
      "schema": {
       "description": "Certificate IDs, comma-separated, at most 200.",
       "type": "string",
       "x-description-zh": "证书 id,逗号分隔,至多 200 个。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get ACME issuance states in batch",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量查 ACME 签发状态"
   }
  },
  "/api/v2/certs/batch": {
   "post": {
    "operationId": "post-certs-batch",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "items": [
         {
          "domains": [
           "a.example.com"
          ]
         },
         {
          "domains": [
           "b.example.com",
           "www.b.example.com"
          ]
         }
        ],
        "type": "lets"
       },
       "schema": {
        "properties": {
         "acme_account_id": {
          "description": "Account to issue with (same as acme.acme_account_id in POST /certs); if omitted, the tenant's enabled account for the type is used first, then the platform's.",
          "type": "integer",
          "x-description-zh": "指定签发账号(同 POST /certs 的 acme.acme_account_id);不给按类型先取本租户启用的、再取平台启用的。"
         },
         "auto_renew": {
          "description": "Defaults to true if omitted.",
          "type": "boolean",
          "x-description-zh": "不给为 true。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "dns_api_id": {
          "description": "DNS API credential used for DNS-01 validation (for ACME certificates).",
          "type": "integer",
          "x-description-zh": "DNS-01 验证用的 DNS API 凭据(ACME 证书用)。"
         },
         "items": {
          "description": "Issuance states.",
          "items": {
           "type": "object",
           "x-gocdn-type": "CertAcme"
          },
          "type": "array",
          "x-description-zh": "签发状态。"
         },
         "type": {
          "description": "custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API.",
          "type": "string",
          "x-description-zh": "custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。"
         }
        },
        "required": [
         "items"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch-create ACME certificates",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量申请 ACME 证书"
   }
  },
  "/api/v2/certs/batch-issue": {
   "post": {
    "operationId": "post-certs-batch-issue",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ids": [
         1
        ]
       },
       "schema": {
        "properties": {
         "ids": {
          "description": "Certificate IDs.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "证书 id。"
         }
        },
        "required": [
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch reissue or renew ACME certificates",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量重签或续签 ACME 证书"
   }
  },
  "/api/v2/certs/zerossl-ips": {
   "get": {
    "operationId": "get-certs-zerossl-ips",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List IPs eligible for ZeroSSL certificates",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出可签 ZeroSSL 证书的 IP"
   }
  },
  "/api/v2/certs/{id}": {
   "delete": {
    "operationId": "delete-certs-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete certificate",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除证书"
   },
   "get": {
    "operationId": "get-certs-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get certificate",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取证书"
   },
   "put": {
    "operationId": "put-certs-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "acme": {
          "description": "Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.).",
          "readOnly": true,
          "type": "object",
          "x-description-zh": "签发状态摘要(证书 GET 与列表里带):签发得来的证书(type=lets/zerossl/zerossl_api)才有,上传的证书(custom)没有这个字段。完整状态(验证方式、ARI 窗口等)见 GET /certs/{id}/acme。",
          "x-gocdn-type": "CertAcmeSummary"
         },
         "cert": {
          "description": "Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key).",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "证书链 PEM(叶证书在前,补全过中间证书,不含根);不含私钥(私钥只能经 POST /certs/{id}/private-key 导出)。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "key": {
          "description": "Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key.",
          "type": "string",
          "x-description-zh": "私钥 PEM(PKCS#1/PKCS#8/SEC1,不许加密);换证时不给则用原私钥核对。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "scope": {
          "description": "Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate.",
          "enum": [
           "site",
           "ip",
           "panel"
          ],
          "type": "string",
          "x-description-zh": "证书范围:site = 站点证书;ip = 平台 IP 证书;panel = 面板证书。"
         },
         "type": {
          "description": "custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API.",
          "type": "string",
          "x-description-zh": "custom = 上传;lets/zerossl = ACME 签发;zerossl_api = ZeroSSL 付费 REST API 签发。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update certificate",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改证书"
   }
  },
  "/api/v2/certs/{id}/acme": {
   "get": {
    "operationId": "get-certs-id-acme",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get certificate ACME issuance status",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取证书的 ACME 签发状态"
   },
   "put": {
    "operationId": "put-certs-id-acme",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auto_renew": false
       },
       "schema": {
        "properties": {
         "auto_renew": {
          "description": "Defaults to true if omitted.",
          "type": "boolean",
          "x-description-zh": "不给为 true。"
         }
        },
        "required": [
         "auto_renew"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update certificate auto-renewal switch",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改证书的自动续签开关"
   }
  },
  "/api/v2/certs/{id}/bind": {
   "post": {
    "operationId": "post-certs-id-bind",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "site_ids": [
         1
        ]
       },
       "schema": {
        "properties": {
         "site_ids": {
          "description": "Sites using this certificate.",
          "items": {
           "type": "integer"
          },
          "readOnly": true,
          "type": "array",
          "x-description-zh": "在用此证书的站点。"
         }
        },
        "required": [
         "site_ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Bind certificate to sites",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "证书绑定到站点"
   }
  },
  "/api/v2/certs/{id}/issue": {
   "post": {
    "operationId": "post-certs-id-issue",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Reissue ACME certificate",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "重新签发 ACME 证书"
   }
  },
  "/api/v2/certs/{id}/private-key": {
   "post": {
    "operationId": "post-certs-id-private-key",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "password": {
          "description": "Current login password.",
          "type": "string",
          "x-description-zh": "当前登录口令。"
         },
         "totp_code": {
          "description": "Current 6-digit TOTP code; the account must have TOTP enabled.",
          "type": "string",
          "x-description-zh": "动态口令(TOTP)的 6 位当前码;账号须已启用动态口令。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Export certificate private key",
    "tags": [
     "certs"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "导出证书私钥"
   }
  },
  "/api/v2/cname-domains": {
   "get": {
    "operationId": "get-cname-domains",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Only list root domains containing this text (partial match, case-insensitive; surrounding spaces and a trailing dot are ignored).",
      "in": "query",
      "name": "domain",
      "schema": {
       "description": "Only list root domains containing this text (partial match, case-insensitive; surrounding spaces and a trailing dot are ignored).",
       "type": "string",
       "x-description-zh": "只列根域包含该串的(部分匹配,不分大小写,首尾空格与结尾的点忽略)。"
      }
     },
     {
      "description": "Only list domains belonging to this provider type (such as aliyun).",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Only list domains belonging to this provider type (such as aliyun).",
       "type": "string",
       "x-description-zh": "只列归属该服务商类型(如 aliyun)的。"
      }
     },
     {
      "description": "Only list domains belonging to this account.",
      "in": "query",
      "name": "dns_provider_id",
      "schema": {
       "description": "Only list domains belonging to this account.",
       "type": "integer",
       "x-description-zh": "只列归属该账号的。"
      }
     },
     {
      "description": "Only list domains in this status.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Only list domains in this status.",
       "enum": [
        "active",
        "retiring"
       ],
       "type": "object",
       "x-description-zh": "只列该状态的。",
       "x-gocdn-type": "CnameDomainStatus"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List CNAME access domains",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出CNAME 接入域名"
   },
   "post": {
    "operationId": "post-cname-domains",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "dns_provider_id": 1,
        "domain": "cdn.example.com",
        "expire_at": "2027-01-31",
        "remark": "主接入域名"
       },
       "schema": {
        "properties": {
         "dns_provider_id": {
          "description": "ID of the provider account hosting this root domain.",
          "type": "integer",
          "x-description-zh": "托管该根域的服务商账号 id。"
         },
         "domain": {
          "description": "Lowercase root domain, such as cdn.example.com.",
          "type": "string",
          "x-description-zh": "小写根域,如 cdn.example.com。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "expire_at": {
          "description": "Expiry date entered by the admin, YYYY-MM-DD; the admin is reminded 30, 7 and 1 days before expiry and once after it.",
          "type": "string",
          "x-description-zh": "管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。"
         },
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         },
         "status": {
          "description": "active: in use; retiring: being retired (migrated away, no longer offered when choosing a package domain).",
          "enum": [
           "active",
           "retiring"
          ],
          "type": "object",
          "x-description-zh": "active 使用中;retiring 停用中(已更换走,不再给套餐选)。",
          "x-gocdn-type": "CnameDomainStatus"
         }
        },
        "required": [
         "dns_provider_id",
         "domain"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create CNAME access domain",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建CNAME 接入域名"
   }
  },
  "/api/v2/cname-domains/status": {
   "put": {
    "operationId": "put-cname-domains-status",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ids": [
         1
        ],
        "status": "retiring"
       },
       "schema": {
        "properties": {
         "ids": {
          "description": "IDs of the access domains to update.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要设置状态的接入域名 id 列表。"
         },
         "status": {
          "description": "active: in use; retiring: being retired (migrated away, no longer offered when choosing a package domain).",
          "enum": [
           "active",
           "retiring"
          ],
          "type": "object",
          "x-description-zh": "active 使用中;retiring 停用中(已更换走,不再给套餐选)。",
          "x-gocdn-type": "CnameDomainStatus"
         }
        },
        "required": [
         "ids",
         "status"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch set CNAME access domain status",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "批量设置CNAME 接入域名状态"
   }
  },
  "/api/v2/cname-domains/{id}": {
   "delete": {
    "operationId": "delete-cname-domains-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "When true, delete only the local record and do not clean up provider-side records under this root domain.",
      "in": "query",
      "name": "local_only",
      "schema": {
       "description": "When true, delete only the local record and do not clean up provider-side records under this root domain.",
       "type": "boolean",
       "x-description-zh": "为 true 时只删本平台记录,不去服务商侧清该根域下的旧解析(面板「仅删除本地记录」)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete CNAME access domain",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除CNAME 接入域名"
   },
   "get": {
    "operationId": "get-cname-domains-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CNAME access domain",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取CNAME 接入域名"
   },
   "put": {
    "operationId": "put-cname-domains-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "dns_provider_id": 1,
        "domain": "cdn.example.com",
        "expire_at": "2027-01-31",
        "remark": "主接入域名"
       },
       "schema": {
        "properties": {
         "dns_provider_id": {
          "description": "ID of the provider account hosting this root domain.",
          "type": "integer",
          "x-description-zh": "托管该根域的服务商账号 id。"
         },
         "domain": {
          "description": "Lowercase root domain, such as cdn.example.com.",
          "type": "string",
          "x-description-zh": "小写根域,如 cdn.example.com。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "expire_at": {
          "description": "Expiry date entered by the admin, YYYY-MM-DD; the admin is reminded 30, 7 and 1 days before expiry and once after it.",
          "type": "string",
          "x-description-zh": "管理员手填的到期日 YYYY-MM-DD;到期前 30/7/1 天与过期后各提醒管理员一次。"
         },
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         },
         "status": {
          "description": "active: in use; retiring: being retired (migrated away, no longer offered when choosing a package domain).",
          "enum": [
           "active",
           "retiring"
          ],
          "type": "object",
          "x-description-zh": "active 使用中;retiring 停用中(已更换走,不再给套餐选)。",
          "x-gocdn-type": "CnameDomainStatus"
         }
        },
        "required": [
         "dns_provider_id",
         "domain"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update CNAME access domain",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改CNAME 接入域名"
   }
  },
  "/api/v2/cname-domains/{id}/migrate": {
   "post": {
    "operationId": "post-cname-domains-id-migrate",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "notify": {
          "default": true,
          "description": "Whether to send in-app messages to the affected customers.",
          "type": "boolean",
          "x-description-zh": "是否给受影响客户发站内信。"
         },
         "retire": {
          "default": true,
          "description": "Whether to set the old domain to retiring.",
          "type": "boolean",
          "x-description-zh": "是否把旧域名置为停用中。"
         },
         "target_id": {
          "description": "ID of the target root domain.",
          "type": "integer",
          "x-description-zh": "目标根域 id。"
         }
        },
        "required": [
         "target_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Migrate CNAME access domain",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "整体更换CNAME 接入域名"
   }
  },
  "/api/v2/cname-domains/{id}/refs": {
   "get": {
    "operationId": "get-cname-domains-id-refs",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get CNAME access domain references",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查CNAME 接入域名的引用"
   }
  },
  "/api/v2/cname-domains/{id}/switch-check": {
   "get": {
    "operationId": "get-cname-domains-id-switch-check",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Only list rows in this check state.",
      "in": "query",
      "name": "state",
      "schema": {
       "description": "Only list rows in this check state.",
       "enum": [
        "changed",
        "unchanged",
        "not_cname",
        "failed",
        "pending"
       ],
       "type": "object",
       "x-description-zh": "只列该核对状态的。",
       "x-gocdn-type": "CnameSwitchState"
      }
     },
     {
      "description": "Fuzzy match on customer name, site domain or actual resolution.",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Fuzzy match on customer name, site domain or actual resolution.",
       "type": "string",
       "x-description-zh": "模糊匹配客户名、网站域名或实际解析。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Check switch status after migration",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查更换后的切换核对"
   }
  },
  "/api/v2/cname-domains/{id}/switch-check/export": {
   "get": {
    "operationId": "get-cname-domains-id-switch-check-export",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Only list rows in this check state.",
      "in": "query",
      "name": "state",
      "schema": {
       "description": "Only list rows in this check state.",
       "enum": [
        "changed",
        "unchanged",
        "not_cname",
        "failed",
        "pending"
       ],
       "type": "object",
       "x-description-zh": "只列该核对状态的。",
       "x-gocdn-type": "CnameSwitchState"
      }
     },
     {
      "description": "Fuzzy match on customer name, site domain or actual resolution.",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Fuzzy match on customer name, site domain or actual resolution.",
       "type": "string",
       "x-description-zh": "模糊匹配客户名、网站域名或实际解析。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Export switch check table",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "导出切换核对对照表"
   }
  },
  "/api/v2/cname-domains/{id}/switch-check/remind": {
   "post": {
    "operationId": "post-cname-domains-id-switch-check-remind",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Remind customers who have not switched",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "提醒未改的客户"
   }
  },
  "/api/v2/cname-domains/{id}/switch-check/run": {
   "post": {
    "operationId": "post-cname-domains-id-switch-check-run",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Run switch check now",
    "tags": [
     "cname-domains"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "立即核对"
   }
  },
  "/api/v2/dns-apis": {
   "get": {
    "operationId": "get-dns-apis",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List DNS API credentials",
    "tags": [
     "dns-apis"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出DNS API 凭据"
   },
   "post": {
    "operationId": "post-dns-apis",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auth": {
         "DP_Id": "12345",
         "DP_Key": "${DP_KEY}"
        },
        "name": "my-dns",
        "type": "dnspod_cn"
       },
       "schema": {
        "properties": {
         "auth": {
          "description": "Credential key name to mask (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
          "type": "object",
          "x-description-zh": "凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "type": {
          "description": "DNS provider.",
          "type": "string",
          "x-description-zh": "DNS 服务商。"
         }
        },
        "required": [
         "name",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create DNS API credential",
    "tags": [
     "dns-apis"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建DNS API 凭据"
   }
  },
  "/api/v2/dns-apis/{id}": {
   "delete": {
    "operationId": "delete-dns-apis-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete DNS API credential",
    "tags": [
     "dns-apis"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除DNS API 凭据"
   },
   "get": {
    "operationId": "get-dns-apis-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get DNS API credential",
    "tags": [
     "dns-apis"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取DNS API 凭据"
   },
   "put": {
    "operationId": "put-dns-apis-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auth": {
         "DP_Id": "12345",
         "DP_Key": "${DP_KEY}"
        },
        "name": "my-dns",
        "type": "dnspod_cn"
       },
       "schema": {
        "properties": {
         "auth": {
          "description": "Credential key name to mask (last 4 chars shown as `****abcd` when 16+ chars, otherwise `********`); plaintext is never returned.",
          "type": "object",
          "x-description-zh": "凭据键名 → 掩码(≥16 位露末 4 位 `****abcd`,否则 `********`),不回明文。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "type": {
          "description": "DNS provider.",
          "type": "string",
          "x-description-zh": "DNS 服务商。"
         }
        },
        "required": [
         "name",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update DNS API credential",
    "tags": [
     "dns-apis"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改DNS API 凭据"
   }
  },
  "/api/v2/dns-providers": {
   "get": {
    "operationId": "get-dns-providers",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Only list providers of this type (such as aliyun).",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Only list providers of this type (such as aliyun).",
       "type": "string",
       "x-description-zh": "只列该服务商类型(如 aliyun)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List DNS providers",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出DNS 服务商"
   },
   "post": {
    "operationId": "post-dns-providers",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auth_id": "LTAI-example",
        "auth_key": "${DNS_AUTH_KEY}",
        "name": "main-aliyun",
        "ttl": 120,
        "type": "aliyun"
       },
       "schema": {
        "properties": {
         "auth_id": {
          "description": "Credential ID (Alibaba Cloud AccessKey ID, DNSPod Token ID or Tencent Cloud SecretId, Cloudflare email; empty when a Cloudflare API Token is used).",
          "type": "string",
          "x-description-zh": "凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。"
         },
         "auth_key": {
          "description": "Credential (AccessKey Secret / Token / SecretKey / API Key); required on create, omitted or empty on update = keep the existing value. Stored encrypted.",
          "type": "string",
          "x-description-zh": "凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "gateway": {
          "description": "Self-hosted API gateway address (used by dnsdun only).",
          "type": "string",
          "x-description-zh": "自建 API 网关地址(只有 dnsdun 用)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         },
         "ttl": {
          "description": "Default TTL (seconds) of records under this account.",
          "type": "integer",
          "x-description-zh": "本账号下记录的默认 TTL(秒)。"
         },
         "type": {
          "description": "Provider type: aliyun, cloudflare, dnspod_cn, dnspod_com, dns_la, dnsdotcom, dnsdun.",
          "type": "string",
          "x-description-zh": "服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。"
         }
        },
        "required": [
         "name",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create DNS provider",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建DNS 服务商"
   }
  },
  "/api/v2/dns-providers/{id}": {
   "delete": {
    "operationId": "delete-dns-providers-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete DNS provider",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除DNS 服务商"
   },
   "get": {
    "operationId": "get-dns-providers-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get DNS provider",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取DNS 服务商"
   },
   "put": {
    "operationId": "put-dns-providers-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "auth_id": "LTAI-example",
        "auth_key": "${DNS_AUTH_KEY}",
        "name": "main-aliyun",
        "ttl": 120,
        "type": "aliyun"
       },
       "schema": {
        "properties": {
         "auth_id": {
          "description": "Credential ID (Alibaba Cloud AccessKey ID, DNSPod Token ID or Tencent Cloud SecretId, Cloudflare email; empty when a Cloudflare API Token is used).",
          "type": "string",
          "x-description-zh": "凭据 ID(阿里云 AccessKey ID、DNSPod Token ID 或腾讯云 SecretId、Cloudflare 邮箱;Cloudflare API Token 时为空)。"
         },
         "auth_key": {
          "description": "Credential (AccessKey Secret / Token / SecretKey / API Key); required on create, omitted or empty on update = keep the existing value. Stored encrypted.",
          "type": "string",
          "x-description-zh": "凭据(AccessKey Secret / Token / SecretKey / API Key);创建必填,修改时不给或为空 = 沿用原值。库内加密保存。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "gateway": {
          "description": "Self-hosted API gateway address (used by dnsdun only).",
          "type": "string",
          "x-description-zh": "自建 API 网关地址(只有 dnsdun 用)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         },
         "ttl": {
          "description": "Default TTL (seconds) of records under this account.",
          "type": "integer",
          "x-description-zh": "本账号下记录的默认 TTL(秒)。"
         },
         "type": {
          "description": "Provider type: aliyun, cloudflare, dnspod_cn, dnspod_com, dns_la, dnsdotcom, dnsdun.",
          "type": "string",
          "x-description-zh": "服务商类型:aliyun、cloudflare、dnspod_cn、dnspod_com;dns_la、dnsdotcom、dnsdun。"
         }
        },
        "required": [
         "name",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update DNS provider",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改DNS 服务商"
   }
  },
  "/api/v2/dns-providers/{id}/lines": {
   "get": {
    "operationId": "get-dns-providers-id-lines",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Root domain, such as example.com.",
      "in": "query",
      "name": "domain",
      "required": true,
      "schema": {
       "description": "Root domain, such as example.com.",
       "type": "string",
       "x-description-zh": "根域,如 example.com。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Fetch DNS provider lines",
    "tags": [
     "dns-providers"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "拉取DNS 服务商线路"
   }
  },
  "/api/v2/dns-sync": {
   "post": {
    "operationId": "post-dns-sync",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Sync DNS records now",
    "tags": [
     "dns-sync"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "立即同步解析"
   }
  },
  "/api/v2/global-ip-lists": {
   "get": {
    "operationId": "get-global-ip-lists",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get global IP blacklist and whitelist",
    "tags": [
     "global-ip-lists"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取全局黑白名单"
   },
   "put": {
    "operationId": "put-global-ip-lists",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "black_items": [
         {
          "expires_at": "2030-01-01T00:00:00Z",
          "ip": "198.51.100.0/24",
          "reason": "scanner"
         }
        ]
       },
       "schema": {
        "properties": {
         "black": {
          "description": "IP/CIDR of the unexpired blacklist entries.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "黑名单的 IP/CIDR(未过期的全部条目)。"
         },
         "black_items": {
          "description": "Blacklist entries with expiry, reason and source.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpListItem"
          },
          "type": "array",
          "x-description-zh": "黑名单条目(含到期时间、原因、来源)。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (use 1970-01-01T00:00:00Z when it was null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "white": {
          "description": "IP/CIDR of the unexpired whitelist entries.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "白名单的 IP/CIDR(未过期的全部条目)。"
         },
         "white_items": {
          "description": "Whitelist entries with expiry, reason and source.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpListItem"
          },
          "type": "array",
          "x-description-zh": "白名单条目(含到期时间、原因、来源)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set global IP blacklist and whitelist",
    "tags": [
     "global-ip-lists"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "设置全局黑白名单"
   }
  },
  "/api/v2/global-ip-lists/export": {
   "get": {
    "operationId": "get-global-ip-lists-export",
    "parameters": [
     {
      "description": "Which list to export.",
      "in": "query",
      "name": "list",
      "required": true,
      "schema": {
       "description": "Which list to export.",
       "enum": [
        "black",
        "white"
       ],
       "type": "string",
       "x-description-zh": "导出哪张名单。"
      }
     },
     {
      "description": "Only export entries from this source; omit for all.",
      "in": "query",
      "name": "source",
      "schema": {
       "description": "Only export entries from this source; omit for all.",
       "enum": [
        "manual",
        "import",
        "ip_detail",
        "api"
       ],
       "type": "object",
       "x-description-zh": "只导出该来源的条目;不带为全部。",
       "x-gocdn-type": "IpListSource"
      }
     },
     {
      "description": "txt (default, one entry per line) or csv (with header, a source column and a UTF-8 BOM).",
      "in": "query",
      "name": "format",
      "schema": {
       "default": "txt",
       "description": "txt (default, one entry per line) or csv (with header, a source column and a UTF-8 BOM).",
       "enum": [
        "txt",
        "csv"
       ],
       "type": "string",
       "x-description-zh": "txt(缺省,纯文本每行一条)或 csv(带表头与来源列、UTF-8 BOM)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Export global IP list entries",
    "tags": [
     "global-ip-lists"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "导出全局黑白名单"
   }
  },
  "/api/v2/global-ip-lists/import": {
   "post": {
    "operationId": "post-global-ip-lists-import",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "dry_run": true,
        "list": "black",
        "mode": "merge",
        "text": "198.51.100.0/24,2030-01-01T00:00:00Z,scanner\n"
       },
       "schema": {
        "properties": {
         "dry_run": {
          "default": false,
          "description": "true only checks the file and saves nothing.",
          "type": "boolean",
          "x-description-zh": "true 只预检,不保存。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (use 1970-01-01T00:00:00Z when it was null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "list": {
          "description": "Which list to import into.",
          "enum": [
           "black",
           "white"
          ],
          "type": "string",
          "x-description-zh": "导入到哪张名单。"
         },
         "mode": {
          "default": "merge",
          "description": "merge adds to the current list (the imported row wins for the same IP); replace swaps the whole list for the imported rows.",
          "enum": [
           "merge",
           "replace"
          ],
          "type": "string",
          "x-description-zh": "merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。"
         },
         "text": {
          "description": "File content (txt/csv), one entry per line: IP/CIDR[,expiry][,reason].",
          "type": "string",
          "x-description-zh": "文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。"
         }
        },
        "required": [
         "list",
         "text"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Bulk import global IP list entries",
    "tags": [
     "global-ip-lists"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "批量导入全局黑白名单"
   }
  },
  "/api/v2/intel": {
   "get": {
    "operationId": "get-intel",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get high-risk IP library status",
    "tags": [
     "intel"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取高危 IP 库状态"
   }
  },
  "/api/v2/intel-reports": {
   "get": {
    "operationId": "get-intel-reports",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Filter by type (ip / upload_hit / false_positive / sha256_report / samples); omit for all.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by type (ip / upload_hit / false_positive / sha256_report / samples); omit for all.",
       "enum": [
        "ip",
        "upload_hit",
        "false_positive",
        "sha256_report",
        "samples"
       ],
       "type": "object",
       "x-description-zh": "按类型过滤(ip / upload_hit / false_positive / sha256_report / samples);不带为全部。",
       "x-gocdn-type": "IntelReportType"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List intelligence reports",
    "tags": [
     "intel-reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查询情报上报记录"
   }
  },
  "/api/v2/intel/allow": {
   "post": {
    "operationId": "post-intel-allow",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ip": "192.0.2.10"
       },
       "schema": {
        "properties": {
         "ip": {
          "description": "Address or network.",
          "type": "string",
          "x-description-zh": "地址或网段。"
         },
         "reason": {
          "description": "Why it is whitelisted (kept on the whitelist entry); defaults to a fixed note when omitted.",
          "type": "string",
          "x-description-zh": "加白原因(记在白名单条目上);不带记「高危 IP 库加白」。"
         }
        },
        "required": [
         "ip"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Whitelist a high-risk IP",
    "tags": [
     "intel"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "高危 IP 单条加白"
   }
  },
  "/api/v2/intel/ips": {
   "get": {
    "operationId": "get-intel-ips",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "A single address returns the entry covering it; anything else filters by substring of the CIDR text (admins only; tenants must give a single address).",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "A single address returns the entry covering it; anything else filters by substring of the CIDR text (admins only; tenants must give a single address).",
       "type": "string",
       "x-description-zh": "单个地址 = 查覆盖它的条目;其余按 CIDR 文本包含过滤(仅管理员,租户必须给单个地址)。"
      }
     },
     {
      "description": "Filter by level.",
      "in": "query",
      "name": "level",
      "schema": {
       "description": "Filter by level.",
       "enum": [
        "high",
        "medium"
       ],
       "type": "object",
       "x-description-zh": "按等级过滤。",
       "x-gocdn-type": "IntelLevel"
      }
     },
     {
      "description": "Filter by type.",
      "in": "query",
      "name": "reason",
      "schema": {
       "description": "Filter by type.",
       "enum": [
        "scanner",
        "exploit",
        "cc"
       ],
       "type": "object",
       "x-description-zh": "按类型过滤。",
       "x-gocdn-type": "IntelReason"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List high-risk IP library entries",
    "tags": [
     "intel"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "查询高危 IP 库条目"
   }
  },
  "/api/v2/intel/policy": {
   "put": {
    "operationId": "put-intel-policy",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "action": "challenge",
        "level": "high"
       },
       "schema": {
        "properties": {
         "action": {
          "description": "Handling: challenge (pass only after a JS check), block (ban on the site and answer 403), log (record only).",
          "enum": [
           "challenge",
           "block",
           "log"
          ],
          "type": "object",
          "x-description-zh": "处置方式:challenge 验证(JS 验证通过才放行);block 拦截(封本站并回 403);log 观察(只记录)。",
          "x-gocdn-type": "IntelAction"
         },
         "level": {
          "description": "Level: high (exploit type or score \u003e= 80); medium.",
          "enum": [
           "high",
           "medium"
          ],
          "type": "object",
          "x-description-zh": "等级:high 高危(漏洞利用类或分数 ≥ 80);medium 中危。",
          "x-gocdn-type": "IntelLevel"
         }
        },
        "required": [
         "action",
         "level"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update high-risk IP library policy",
    "tags": [
     "intel"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改高危 IP 库处置策略"
   }
  },
  "/api/v2/intel/visitors": {
   "get": {
    "operationId": "get-intel-visitors",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "High-risk IPs that visited today",
    "tags": [
     "intel"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "今日访问过我的高危 IP"
   }
  },
  "/api/v2/ip-pools": {
   "get": {
    "operationId": "get-ip-pools",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Filter by region.",
      "in": "query",
      "name": "region_id",
      "schema": {
       "description": "Filter by region.",
       "type": "integer",
       "x-description-zh": "按区域过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List IP pools",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出 IP 池"
   },
   "post": {
    "operationId": "post-ip-pools",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         }
        },
        "required": [
         "name",
         "region_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create IP pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建 IP 池"
   }
  },
  "/api/v2/ip-pools/candidates": {
   "get": {
    "operationId": "get-ip-pools-candidates",
    "parameters": [
     {
      "description": "Region ID.",
      "in": "query",
      "name": "region_id",
      "required": true,
      "schema": {
       "description": "Region ID.",
       "type": "integer",
       "x-description-zh": "区域 ID。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "IP pool candidate node IPs",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "IP 池候选节点 IP"
   }
  },
  "/api/v2/ip-pools/{id}": {
   "delete": {
    "operationId": "delete-ip-pools-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete IP pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除 IP 池"
   },
   "get": {
    "operationId": "get-ip-pools-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get IP pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取 IP 池"
   },
   "put": {
    "operationId": "put-ip-pools-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         }
        },
        "required": [
         "name",
         "region_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update IP pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 IP 池"
   }
  },
  "/api/v2/ip-pools/{id}/refs": {
   "get": {
    "operationId": "get-ip-pools-id-refs",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Show only this pool IP.",
      "in": "query",
      "name": "ip_id",
      "schema": {
       "description": "Show only this pool IP.",
       "type": "integer",
       "x-description-zh": "只看这个池内 IP。"
      }
     },
     {
      "description": "Maximum number of sites listed per IP.",
      "in": "query",
      "name": "limit",
      "schema": {
       "default": 20,
       "description": "Maximum number of sites listed per IP.",
       "type": "integer",
       "x-description-zh": "每个 IP 最多列几个站点。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "IP pool referencing sites",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "IP 池引用站点"
   }
  },
  "/api/v2/ip-pools/{pool_id}/ips": {
   "get": {
    "operationId": "get-ip-pools-pool-id-ips",
    "parameters": [
     {
      "in": "path",
      "name": "pool_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List IPs in pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出池内 IP"
   },
   "post": {
    "operationId": "post-ip-pools-pool-id-ips",
    "parameters": [
     {
      "in": "path",
      "name": "pool_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "bind_addr": {
          "description": "The local address the node actually listens on (NAT setups); null means use ip.",
          "type": "string",
          "x-description-zh": "节点上实际监听的本机地址(NAT 场景);null = 用 ip。"
         },
         "node_id": {
          "description": "Node ID",
          "type": "integer",
          "x-description-zh": "节点 ID"
         }
        },
        "required": [
         "node_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Add IP to pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "IP 入池"
   }
  },
  "/api/v2/ip-pools/{pool_id}/ips/{id}": {
   "delete": {
    "operationId": "delete-ip-pools-pool-id-ips-id",
    "parameters": [
     {
      "in": "path",
      "name": "pool_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Remove IP from pool",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "IP 出池"
   },
   "put": {
    "operationId": "put-ip-pools-pool-id-ips-id",
    "parameters": [
     {
      "in": "path",
      "name": "pool_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "bind_addr": {
          "description": "The local address the node actually listens on (NAT setups); null means use ip.",
          "type": "string",
          "x-description-zh": "节点上实际监听的本机地址(NAT 场景);null = 用 ip。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update pool IP",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改池内 IP"
   }
  },
  "/api/v2/ip-pools/{pool_id}/ips/{id}/issue-cert": {
   "post": {
    "operationId": "post-ip-pools-pool-id-ips-id-issue-cert",
    "parameters": [
     {
      "in": "path",
      "name": "pool_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "confirm": {
          "description": "Confirm re-issuing when a valid certificate already exists.",
          "type": "boolean",
          "x-description-zh": "已有有效证书时确认重签。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Issue platform certificate for pool IP",
    "tags": [
     "ip-pools"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "签发池内 IP 的平台证书"
   }
  },
  "/api/v2/ip-sites": {
   "get": {
    "operationId": "get-ip-sites",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Filter by user package.",
       "type": "integer",
       "x-description-zh": "按用户套餐过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List IP sites",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出 IP 站点"
   },
   "post": {
    "operationId": "post-ip-sites",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "config": {
          "description": "Node configuration fields (same as the site config; kind is always ip, and listen_addrs is derived from the bindings at publish time).",
          "type": "object",
          "x-description-zh": "节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ip_ids": {
          "description": "IDs of the bound pool IPs, in order.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "绑定的池内 IP id(按次序)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origins": {
          "description": "Origin servers.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpSiteOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = every request returns this status code (set by admins or billing).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
         },
         "upid": {
          "description": "User package ID.",
          "type": "integer",
          "x-description-zh": "用户套餐 id。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create IP site",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建 IP 站点"
   }
  },
  "/api/v2/ip-sites/available-ips": {
   "get": {
    "operationId": "get-ip-sites-available-ips",
    "parameters": [
     {
      "description": "User package ID.",
      "in": "query",
      "name": "upid",
      "required": true,
      "schema": {
       "description": "User package ID.",
       "type": "integer",
       "x-description-zh": "用户套餐 ID。"
      }
     },
     {
      "description": "pool = the whole pool; mine = only the IPs already selected.",
      "in": "query",
      "name": "scope",
      "schema": {
       "default": "pool",
       "description": "pool = the whole pool; mine = only the IPs already selected.",
       "enum": [
        "pool",
        "mine"
       ],
       "type": "string",
       "x-description-zh": "pool 整池;mine 只列已选。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "IP site available IPs",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "IP 站点可选 IP"
   }
  },
  "/api/v2/ip-sites/port-check": {
   "post": {
    "operationId": "post-ip-sites-port-check",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "http_ports": {
          "description": "HTTP ports to check; ports outside 1-65535 are not rejected but reported as range.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要检查的 HTTP 端口列表;超出 1~65535 的不拒,结果里标 range。"
         },
         "https_ports": {
          "description": "HTTPS ports to check; ports outside 1-65535 are not rejected but reported as range.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要检查的 HTTPS 端口列表;超出 1~65535 的不拒,结果里标 range。"
         },
         "ip_ids": {
          "description": "IDs of the bound pool IPs, in order.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "绑定的池内 IP id(按次序)。"
         },
         "site_id": {
          "description": "Pass when editing a site: ports held by this site itself are not counted as occupied.",
          "type": "integer",
          "x-description-zh": "改站时给:本站自己占的不算占用。"
         },
         "upid": {
          "description": "User package ID.",
          "type": "integer",
          "x-description-zh": "用户套餐 id。"
         }
        },
        "required": [
         "ip_ids",
         "upid"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "IP site port pre-check",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "IP 站点端口预检"
   }
  },
  "/api/v2/ip-sites/{id}": {
   "delete": {
    "operationId": "delete-ip-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete IP site",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除 IP 站点"
   },
   "get": {
    "operationId": "get-ip-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get IP site",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取 IP 站点"
   },
   "put": {
    "operationId": "put-ip-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "config": {
          "description": "Node configuration fields (same as the site config; kind is always ip, and listen_addrs is derived from the bindings at publish time).",
          "type": "object",
          "x-description-zh": "节点配置字段(同站点 config;kind 恒为 ip,listen_addrs 发布时由绑定现取)。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ip_ids": {
          "description": "IDs of the bound pool IPs, in order.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "绑定的池内 IP id(按次序)。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origins": {
          "description": "Origin servers.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpSiteOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = every request returns this status code (set by admins or billing).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
         },
         "upid": {
          "description": "User package ID.",
          "type": "integer",
          "x-description-zh": "用户套餐 id。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update IP site",
    "tags": [
     "ip-sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改 IP 站点"
   }
  },
  "/api/v2/l2/enable-batch": {
   "post": {
    "operationId": "post-l2-enable-batch",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "apply_sites": {
          "description": "Also enable on existing sites (only those never set; sites turned off manually, or whose tenant package does not include tiered origin, stay unchanged).",
          "type": "boolean",
          "x-description-zh": "给现有网站也开(只动从没设过的网站,手动关过的、所属租户套餐不含分层回源的不动)。"
         },
         "node_ids": {
          "description": "Edge node IDs to turn into L2.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改做 L2 的边缘节点 id。"
         }
        },
        "required": [
         "node_ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Add L2 nodes in batch",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "批量加 L2"
   }
  },
  "/api/v2/l2/groups": {
   "get": {
    "operationId": "get-l2-groups",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List L2 groups",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出 L2 组"
   },
   "post": {
    "operationId": "post-l2-groups",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "all_regions": {
          "description": "Serve all regions (requires cross_region).",
          "type": "boolean",
          "x-description-zh": "服务全部区域(须勾跨区域)。"
         },
         "balance": {
          "description": "Distribution: url_hash pins by URL, rr round-robin.",
          "enum": [
           "url_hash",
           "rr"
          ],
          "type": "string",
          "x-description-zh": "分配方式:url_hash 按网址固定,rr 轮流。"
         },
         "cross_region": {
          "description": "Allow cross-region use (required for nodes outside the regions or all regions; adds about 50-200 ms).",
          "type": "boolean",
          "x-description-zh": "允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。"
         },
         "name": {
          "description": "Group name, unique platform-wide.",
          "type": "string",
          "x-description-zh": "组名,全平台唯一。"
         },
         "node_ids": {
          "description": "Edge node IDs to turn into L2.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改做 L2 的边缘节点 id。"
         },
         "regions": {
          "description": "Served region IDs; ignored when all_regions is true.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "服务区域 id;all_regions 为真时忽略。"
         },
         "rules": {
          "description": "Group rules (saved with the group).",
          "items": {
           "type": "object",
           "x-gocdn-type": "L2Rule"
          },
          "type": "array",
          "x-description-zh": "组内规则(随组保存)。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create L2 group",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "新建 L2 组"
   }
  },
  "/api/v2/l2/groups/{id}": {
   "delete": {
    "operationId": "delete-l2-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete L2 group",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除 L2 组"
   },
   "get": {
    "operationId": "get-l2-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get L2 group",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查看 L2 组"
   },
   "patch": {
    "operationId": "patch-l2-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "all_regions": {
          "description": "Serve all regions (requires cross_region).",
          "type": "boolean",
          "x-description-zh": "服务全部区域(须勾跨区域)。"
         },
         "balance": {
          "description": "Distribution: url_hash pins by URL, rr round-robin.",
          "enum": [
           "url_hash",
           "rr"
          ],
          "type": "string",
          "x-description-zh": "分配方式:url_hash 按网址固定,rr 轮流。"
         },
         "cross_region": {
          "description": "Allow cross-region use (required for nodes outside the regions or all regions; adds about 50-200 ms).",
          "type": "boolean",
          "x-description-zh": "允许跨区域使用(选了区域外的节点或全部区域必须勾,多约 50–200 毫秒)。"
         },
         "name": {
          "description": "Group name, unique platform-wide.",
          "type": "string",
          "x-description-zh": "组名,全平台唯一。"
         },
         "node_ids": {
          "description": "Edge node IDs to turn into L2.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改做 L2 的边缘节点 id。"
         },
         "regions": {
          "description": "Served region IDs; ignored when all_regions is true.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "服务区域 id;all_regions 为真时忽略。"
         },
         "rules": {
          "description": "Group rules (saved with the group).",
          "items": {
           "type": "object",
           "x-gocdn-type": "L2Rule"
          },
          "type": "array",
          "x-description-zh": "组内规则(随组保存)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update L2 group",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 L2 组"
   }
  },
  "/api/v2/l2/groups/{id}/copy": {
   "post": {
    "operationId": "post-l2-groups-id-copy",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "name": {
          "description": "Group name, unique platform-wide.",
          "type": "string",
          "x-description-zh": "组名,全平台唯一。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Copy L2 group",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "复制 L2 组"
   }
  },
  "/api/v2/l2/groups/{id}/reset-sites": {
   "post": {
    "operationId": "post-l2-groups-id-reset-sites",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Reset sites of a group to region default",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "把用这个组的网站改回区域默认"
   }
  },
  "/api/v2/l2/nodes": {
   "get": {
    "operationId": "get-l2-nodes",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List L2 nodes",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出 L2 节点"
   }
  },
  "/api/v2/l2/nodes/{id}": {
   "patch": {
    "operationId": "patch-l2-nodes-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "access_addr": {
          "description": "Private address edges use to reach it (IP only, no port; IPv4-mapped IPv6 is stored as IPv4); empty means the public IP.",
          "type": "string",
          "x-description-zh": "边缘访问它的内网地址(只收 IP,不带端口;IPv4 映射的 IPv6 存成 IPv4);空 = 公网 IP。"
         },
         "role": {
          "description": "Primary or backup: backups stand by while a primary in the same group is up.",
          "enum": [
           "primary",
           "backup"
          ],
          "type": "string",
          "x-description-zh": "主备:同组有主可用时备只待命,主全挂才用备(在组内成员间比较)。"
         },
         "weight": {
          "description": "Weight 1-100; multiple primaries share URLs by weight.",
          "type": "integer",
          "x-description-zh": "权重 1–100,多台主按权重分网址。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update L2 node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 L2 节点"
   }
  },
  "/api/v2/l2/nodes/{id}/disable": {
   "post": {
    "operationId": "post-l2-nodes-id-disable",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "reason": {
          "description": "Reason for disabling.",
          "type": "string",
          "x-description-zh": "停用原因。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Disable L2 node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "停用 L2 节点"
   }
  },
  "/api/v2/l2/nodes/{id}/enable": {
   "post": {
    "operationId": "post-l2-nodes-id-enable",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Enable L2 node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "启用 L2 节点"
   }
  },
  "/api/v2/l2/nodes/{id}/impact": {
   "get": {
    "operationId": "get-l2-nodes-id-impact",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Impact before revert or disable",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "改回 / 停用前的影响"
   }
  },
  "/api/v2/l2/nodes/{id}/mark-allowed": {
   "post": {
    "operationId": "post-l2-nodes-id-mark-allowed",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Mark origins as allowing the node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "标记源站已放行"
   }
  },
  "/api/v2/l2/nodes/{id}/probe-access": {
   "post": {
    "operationId": "post-l2-nodes-id-probe-access",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Check whether origins allow the node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "检测源站是否已放行"
   }
  },
  "/api/v2/l2/nodes/{id}/revert": {
   "post": {
    "operationId": "post-l2-nodes-id-revert",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Revert to edge node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "改回边缘节点"
   }
  },
  "/api/v2/l2/pause": {
   "post": {
    "operationId": "post-l2-pause",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "auto_resume_at": {
          "description": "Automatic resume time (must be in the future); omit for manual resume.",
          "type": "string",
          "x-description-zh": "自动恢复时刻(须在现在之后);不给 = 手动恢复。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Pause tiered origin network-wide",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "全网暂停分层回源"
   }
  },
  "/api/v2/l2/recommend": {
   "get": {
    "operationId": "get-l2-recommend",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "One-click enable recommendation",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "一键启用推荐"
   }
  },
  "/api/v2/l2/resume": {
   "post": {
    "operationId": "post-l2-resume",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Resume tiered origin network-wide",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "全网恢复分层回源"
   }
  },
  "/api/v2/l2/revoke-impact": {
   "get": {
    "operationId": "get-l2-revoke-impact",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "License loss impact and fallback window",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "授权失效的影响与回落窗口"
   }
  },
  "/api/v2/l2/stats": {
   "get": {
    "operationId": "get-l2-stats",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Tiered origin statistics",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "分层回源统计"
   }
  },
  "/api/v2/l2/stats/nodes": {
   "get": {
    "operationId": "get-l2-stats-nodes",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Statistics by L2 node",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "按 L2 节点的统计"
   }
  },
  "/api/v2/l2/stats/sites": {
   "get": {
    "operationId": "get-l2-stats-sites",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Substring of the primary domain, case-insensitive.",
      "in": "query",
      "name": "domain",
      "schema": {
       "description": "Substring of the primary domain, case-insensitive.",
       "type": "string",
       "x-description-zh": "主域名子串,不分大小写。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Tiered origin statistics by site",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "按网站的分层回源统计"
   }
  },
  "/api/v2/l2/status": {
   "get": {
    "operationId": "get-l2-status",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Tiered origin overview",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "分层回源总览"
   }
  },
  "/api/v2/l2/tasks/{id}": {
   "get": {
    "operationId": "get-l2-tasks-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get L2 task progress",
    "tags": [
     "l2"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查看 L2 任务进度"
   }
  },
  "/api/v2/ledger-entries": {
   "get": {
    "operationId": "get-ledger-entries",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by ledger entry kind.",
      "in": "query",
      "name": "kind",
      "schema": {
       "description": "Filter by ledger entry kind.",
       "type": "string",
       "x-description-zh": "按流水类别过滤。"
      }
     },
     {
      "description": "Entry time from (inclusive), RFC 3339.",
      "in": "query",
      "name": "start",
      "schema": {
       "description": "Entry time from (inclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "记账时间起(含),RFC 3339。"
      }
     },
     {
      "description": "Entry time until (exclusive), RFC 3339.",
      "in": "query",
      "name": "end",
      "schema": {
       "description": "Entry time until (exclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "记账时间止(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List ledger entries",
    "tags": [
     "ledger-entries"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出账户流水"
   }
  },
  "/api/v2/lines": {
   "get": {
    "operationId": "get-lines",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List lines",
    "tags": [
     "lines"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出线路"
   },
   "post": {
    "operationId": "post-lines",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "dns_line": "default",
        "node_group_id": 1,
        "node_id": 1,
        "weight": 1
       },
       "schema": {
        "properties": {
         "dns_line": {
          "description": "DNS resolution line code (default = default line; carrier/region line codes are mapped by the DNS domain).",
          "type": "string",
          "x-description-zh": "DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "force": {
          "description": "Force the write and skip two safeguards (requires a second confirmation): when the line becomes an enabled primary line, its node must have applied its configuration and be at most one release behind (otherwise 422 node_config_behind); disabling the last enabled primary line of the node group or making it a backup (otherwise 422 last_primary_line).",
          "type": "boolean",
          "x-description-zh": "强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。"
         },
         "is_backup": {
          "description": "Backup IP; kept out of DNS normally and brought in or taken out automatically according to the node group's backup IP switch mode.",
          "type": "boolean",
          "x-description-zh": "备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。"
         },
         "is_backup_default": {
          "description": "Backup default line; when the node group has no default line in use, this line is automatically resolved on the default line instead, and switched back once one is in use again.",
          "type": "boolean",
          "x-description-zh": "备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。"
         },
         "node_group_id": {
          "description": "ID of the node group this line belongs to.",
          "type": "integer",
          "x-description-zh": "所属节点组的 id。"
         },
         "node_id": {
          "description": "Node ID",
          "type": "integer",
          "x-description-zh": "节点 ID"
         },
         "weight": {
          "description": "Weight, 1 to 100; a larger weight receives a larger share of resolutions.",
          "type": "integer",
          "x-description-zh": "权重,1 到 100,越大分到的解析越多。"
         }
        },
        "required": [
         "node_group_id",
         "node_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create line",
    "tags": [
     "lines"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建线路"
   }
  },
  "/api/v2/lines/{id}": {
   "delete": {
    "operationId": "delete-lines-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete line",
    "tags": [
     "lines"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除线路"
   },
   "get": {
    "operationId": "get-lines-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get line",
    "tags": [
     "lines"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取线路"
   },
   "put": {
    "operationId": "put-lines-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "enabled": false
       },
       "schema": {
        "properties": {
         "dns_line": {
          "description": "DNS resolution line code (default = default line; carrier/region line codes are mapped by the DNS domain).",
          "type": "string",
          "x-description-zh": "DNS 解析线路代码(default = 默认线路;运营商/地区线路代码由 DNS 域映射)。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "force": {
          "description": "Force the write and skip two safeguards (requires a second confirmation): when the line becomes an enabled primary line, its node must have applied its configuration and be at most one release behind (otherwise 422 node_config_behind); disabling the last enabled primary line of the node group or making it a backup (otherwise 422 last_primary_line).",
          "type": "boolean",
          "x-description-zh": "强制写入,跳过两道保护(须二次确认):线路成为启用的主线路时节点须已装上配置、比该装的版本落后不超过 1 版(否则 422 node_config_behind);停用或转备用组里最后一条启用的主线路(否则 422 last_primary_line)。"
         },
         "is_backup": {
          "description": "Backup IP; kept out of DNS normally and brought in or taken out automatically according to the node group's backup IP switch mode.",
          "type": "boolean",
          "x-description-zh": "备用 IP:平时不进解析,按节点组的备用 IP 切换方式自动启用/撤下。"
         },
         "is_backup_default": {
          "description": "Backup default line; when the node group has no default line in use, this line is automatically resolved on the default line instead, and switched back once one is in use again.",
          "type": "boolean",
          "x-description-zh": "备用默认解析:节点组里没有在用的默认线路时,这条线路自动改按默认线路解析,有了再改回原线路。"
         },
         "node_group_id": {
          "description": "ID of the node group this line belongs to.",
          "type": "integer",
          "x-description-zh": "所属节点组的 id。"
         },
         "node_id": {
          "description": "Node ID",
          "type": "integer",
          "x-description-zh": "节点 ID"
         },
         "weight": {
          "description": "Weight, 1 to 100; a larger weight receives a larger share of resolutions.",
          "type": "integer",
          "x-description-zh": "权重,1 到 100,越大分到的解析越多。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update line",
    "tags": [
     "lines"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改线路"
   }
  },
  "/api/v2/login-policy": {
   "get": {
    "operationId": "get-login-policy",
    "parameters": [
     {
      "description": "Login name (username, email or phone number)",
      "in": "query",
      "name": "account",
      "required": true,
      "schema": {
       "description": "Login name (username, email or phone number)",
       "type": "string",
       "x-description-zh": "登录名(用户名、邮箱或手机号)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Get login policy",
    "tags": [
     "login-policy"
    ],
    "x-summary-zh": "登录策略"
   }
  },
  "/api/v2/me": {
   "get": {
    "operationId": "get-me",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get current user",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "当前用户"
   },
   "put": {
    "operationId": "put-me",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "email_code": {
          "description": "Code sent to the new email (POST /verify-codes, purpose=bind); required when changing the email",
          "type": "string",
          "x-description-zh": "发到新邮箱的验证码(POST /verify-codes,purpose=bind);改邮箱时必填。"
         },
         "login_ip_allow": {
          "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
         },
         "login_verify": {
          "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
          "enum": [
           "none",
           "email",
           "sms"
          ],
          "type": "object",
          "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
          "x-gocdn-type": "LoginVerify"
         },
         "phone": {
          "description": "Phone number",
          "type": "string",
          "x-description-zh": "手机号"
         },
         "phone_code": {
          "description": "Code sent to the new phone number (POST /verify-codes, purpose=bind); required when changing the phone number",
          "type": "string",
          "x-description-zh": "发到新手机号的验证码(POST /verify-codes,purpose=bind);改手机号时必填。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update profile",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改个人资料"
   }
  },
  "/api/v2/me/certification": {
   "get": {
    "operationId": "get-me-certification",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get real-name verification status",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "实名认证状态"
   },
   "post": {
    "operationId": "post-me-certification",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "id_number": "11010519491231002X",
        "real_name": "张三"
       },
       "schema": {
        "properties": {
         "id_number": {
          "description": "Masked ID number",
          "type": "string",
          "x-description-zh": "打码后的证件号。"
         },
         "real_name": {
          "description": "Masked real name",
          "type": "string",
          "x-description-zh": "打码后的姓名。"
         }
        },
        "required": [
         "id_number",
         "real_name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Submit real-name verification",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "提交实名认证"
   }
  },
  "/api/v2/me/preferences": {
   "get": {
    "operationId": "get-me-preferences",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get preferences",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "用户偏好"
   },
   "put": {
    "operationId": "put-me-preferences",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update preferences",
    "tags": [
     "me"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改用户偏好"
   }
  },
  "/api/v2/message-channels": {
   "get": {
    "operationId": "get-message-channels",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delivery channels",
    "tags": [
     "message-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "发信通道"
   },
   "put": {
    "operationId": "put-message-channels",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "sms": {
          "description": "SMS channel settings.",
          "type": "object",
          "x-description-zh": "短信通道配置。",
          "x-gocdn-type": "SmsChannel"
         },
         "smtp": {
          "description": "SMTP email channel settings.",
          "type": "object",
          "x-description-zh": "SMTP 邮件通道配置。",
          "x-gocdn-type": "SmtpChannel"
         }
        },
        "required": [
         "sms",
         "smtp"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update delivery channels",
    "tags": [
     "message-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改发信通道"
   }
  },
  "/api/v2/message-channels/test": {
   "post": {
    "operationId": "post-message-channels-test",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "channel": "email",
        "to": "admin@example.com"
       },
       "schema": {
        "properties": {
         "channel": {
          "description": "Channel to test (email or sms).",
          "enum": [
           "email",
           "sms"
          ],
          "type": "string",
          "x-description-zh": "要测试的通道(email 邮件、sms 短信)。"
         },
         "draft": {
          "description": "Unsaved channel settings; same shape as the save endpoint, omitted fields and blank secrets fall back to the stored values.",
          "type": "object",
          "x-description-zh": "未保存的通道设置草稿;字段形状同保存接口,没给的字段、留空的密钥沿用已存值。",
          "x-gocdn-type": "ChannelTestDraft"
         },
         "template_id": {
          "description": "An approved template id is required for the Tencent Cloud SMS channel (not needed for SMSBao).",
          "type": "string",
          "x-description-zh": "腾讯云短信须给已审核的模板 id(短信宝不需要)。"
         },
         "to": {
          "description": "Recipient address or phone number.",
          "type": "string",
          "x-description-zh": "收件邮箱或手机号。"
         }
        },
        "required": [
         "channel",
         "to"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Test delivery channel",
    "tags": [
     "message-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "测试发信通道"
   }
  },
  "/api/v2/message-subscriptions": {
   "get": {
    "operationId": "get-message-subscriptions",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Message subscriptions",
    "tags": [
     "message-subscriptions"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "消息订阅"
   },
   "put": {
    "operationId": "put-message-subscriptions",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "items": {
          "description": "Items on this page",
          "items": {
           "type": "object",
           "x-gocdn-type": "SubscriptionItem"
          },
          "type": "array",
          "x-description-zh": "本页条目"
         }
        },
        "required": [
         "items"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update message subscriptions",
    "tags": [
     "message-subscriptions"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "修改消息订阅"
   }
  },
  "/api/v2/message-webhooks": {
   "get": {
    "operationId": "get-message-webhooks",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List alert webhooks",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "告警 Webhook 列表"
   },
   "post": {
    "operationId": "post-message-webhooks",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "chat_id": {
          "description": "Telegram chat (numeric id or @channel name).",
          "type": "string",
          "x-description-zh": "Telegram 会话(数字 id 或 @频道名)。"
         },
         "created_at": {
          "description": "Created at",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "创建时间"
         },
         "enabled": {
          "description": "Whether it is enabled; disabled ones are skipped. Enabled by default.",
          "type": "boolean",
          "x-description-zh": "是否启用;停用的不发。缺省启用。"
         },
         "id": {
          "description": "Record ID",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "记录 ID"
         },
         "kind": {
          "description": "Kind: dingtalk, feishu, wecom, telegram or generic JSON.",
          "enum": [
           "dingtalk",
           "feishu",
           "wecom",
           "telegram",
           "generic"
          ],
          "type": "string",
          "x-description-zh": "类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。"
         },
         "last4": {
          "description": "Last 4 characters of the address (the token for Telegram), for recognition only.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "地址(Telegram 为 Token)的末 4 位,仅用于辨认。"
         },
         "name": {
          "description": "Name, unique across all webhooks.",
          "type": "string",
          "x-description-zh": "名称,全局唯一。"
         },
         "secret": {
          "description": "Bot token for Telegram (required); signing secret for the others (optional). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。"
         },
         "updated_at": {
          "description": "Updated at",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "更新时间"
         },
         "url": {
          "description": "Bot URL (https, public; required for DingTalk, Feishu, WeCom and generic; unused for Telegram). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。"
         }
        },
        "required": [
         "created_at",
         "id",
         "kind",
         "name",
         "updated_at"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create alert webhook",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "新建告警 Webhook"
   }
  },
  "/api/v2/message-webhooks/test": {
   "post": {
    "operationId": "post-message-webhooks-test",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "chat_id": {
          "description": "Telegram chat (numeric id or @channel name).",
          "type": "string",
          "x-description-zh": "Telegram 会话(数字 id 或 @频道名)。"
         },
         "id": {
          "description": "Record ID",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "记录 ID"
         },
         "kind": {
          "description": "Kind: dingtalk, feishu, wecom, telegram or generic JSON.",
          "enum": [
           "dingtalk",
           "feishu",
           "wecom",
           "telegram",
           "generic"
          ],
          "type": "string",
          "x-description-zh": "类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。"
         },
         "secret": {
          "description": "Bot token for Telegram (required); signing secret for the others (optional). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。"
         },
         "url": {
          "description": "Bot URL (https, public; required for DingTalk, Feishu, WeCom and generic; unused for Telegram). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。"
         }
        },
        "required": [
         "kind"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Test unsaved alert webhook",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "测试未保存的告警 Webhook"
   }
  },
  "/api/v2/message-webhooks/{id}": {
   "delete": {
    "operationId": "delete-message-webhooks-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete alert webhook",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除告警 Webhook"
   },
   "put": {
    "operationId": "put-message-webhooks-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "chat_id": {
          "description": "Telegram chat (numeric id or @channel name).",
          "type": "string",
          "x-description-zh": "Telegram 会话(数字 id 或 @频道名)。"
         },
         "created_at": {
          "description": "Created at",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "创建时间"
         },
         "enabled": {
          "description": "Whether it is enabled; disabled ones are skipped. Enabled by default.",
          "type": "boolean",
          "x-description-zh": "是否启用;停用的不发。缺省启用。"
         },
         "id": {
          "description": "Record ID",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "记录 ID"
         },
         "kind": {
          "description": "Kind: dingtalk, feishu, wecom, telegram or generic JSON.",
          "enum": [
           "dingtalk",
           "feishu",
           "wecom",
           "telegram",
           "generic"
          ],
          "type": "string",
          "x-description-zh": "类型:dingtalk 钉钉、feishu 飞书、wecom 企业微信、telegram Telegram、generic 通用 JSON。"
         },
         "last4": {
          "description": "Last 4 characters of the address (the token for Telegram), for recognition only.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "地址(Telegram 为 Token)的末 4 位,仅用于辨认。"
         },
         "name": {
          "description": "Name, unique across all webhooks.",
          "type": "string",
          "x-description-zh": "名称,全局唯一。"
         },
         "secret": {
          "description": "Bot token for Telegram (required); signing secret for the others (optional). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "Telegram 为 Bot Token(必填);其余为加签密钥(可空)。只写,不回显。"
         },
         "updated_at": {
          "description": "Updated at",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "更新时间"
         },
         "url": {
          "description": "Bot URL (https, public; required for DingTalk, Feishu, WeCom and generic; unused for Telegram). Write-only, never echoed.",
          "type": "string",
          "x-description-zh": "机器人地址(https,公网;钉钉、飞书、企业微信、通用必填;Telegram 不用)。只写,不回显。"
         }
        },
        "required": [
         "created_at",
         "id",
         "kind",
         "name",
         "updated_at"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update alert webhook",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改告警 Webhook"
   }
  },
  "/api/v2/message-webhooks/{id}/test": {
   "post": {
    "operationId": "post-message-webhooks-id-test",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Test saved alert webhook",
    "tags": [
     "message-webhooks"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "测试已保存的告警 Webhook"
   }
  },
  "/api/v2/messages": {
   "get": {
    "operationId": "get-messages",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Message type, such as announcement or cert-expire.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Message type, such as announcement or cert-expire.",
       "type": "string",
       "x-description-zh": "消息类型,如 announcement、cert-expire。"
      }
     },
     {
      "description": "Site ID",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Site ID",
       "type": "integer",
       "x-description-zh": "网站 ID"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List messages",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出消息"
   },
   "post": {
    "operationId": "post-messages",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "content": "今晚 23 点维护。",
        "title": "维护通知"
       },
       "schema": {
        "properties": {
         "content": {
          "description": "Message body.",
          "type": "string",
          "x-description-zh": "消息正文。"
         },
         "is_bold": {
          "description": "Whether to show the title in bold.",
          "type": "boolean",
          "x-description-zh": "标题是否加粗。"
         },
         "is_external": {
          "description": "When true, clicking jumps to url and url is required; otherwise content is required.",
          "type": "boolean",
          "x-description-zh": "为真时点击跳 url,url 必填;否则 content 必填。"
         },
         "is_popup": {
          "description": "Whether to show it as a pop-up.",
          "type": "boolean",
          "x-description-zh": "是否弹窗显示。"
         },
         "is_red": {
          "description": "Whether to show the title in red.",
          "type": "boolean",
          "x-description-zh": "标题是否标红。"
         },
         "is_show": {
          "description": "Whether the message is visible.",
          "type": "boolean",
          "x-description-zh": "是否显示。"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         },
         "title": {
          "description": "Message title.",
          "type": "string",
          "x-description-zh": "消息标题。"
         },
         "url": {
          "description": "Link opened on click when is_external is true.",
          "type": "string",
          "x-description-zh": "is_external 为真时点击跳转的链接。"
         }
        },
        "required": [
         "title"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Publish announcement",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "发布公告"
   }
  },
  "/api/v2/messages/read": {
   "post": {
    "operationId": "post-messages-read",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "ids": {
          "description": "Empty means all messages sent to you.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "为空表示发给自己的全部已读。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Mark messages as read",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "标记已读"
   }
  },
  "/api/v2/messages/recent": {
   "get": {
    "operationId": "get-messages-recent",
    "parameters": [
     {
      "description": "Only messages from the last this many days.",
      "in": "query",
      "name": "days",
      "schema": {
       "default": 30,
       "description": "Only messages from the last this many days.",
       "type": "integer",
       "x-description-zh": "只取最近这么多天的消息。"
      }
     },
     {
      "description": "Maximum number of messages to return.",
      "in": "query",
      "name": "limit",
      "schema": {
       "default": 8,
       "description": "Maximum number of messages to return.",
       "type": "integer",
       "x-description-zh": "最多返回的条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Recent unread messages",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "近期未读消息"
   }
  },
  "/api/v2/messages/unread-count": {
   "get": {
    "operationId": "get-messages-unread-count",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Unread message count",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "未读消息数"
   }
  },
  "/api/v2/messages/{id}": {
   "delete": {
    "operationId": "delete-messages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete message",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除消息"
   },
   "get": {
    "operationId": "get-messages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get message",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取消息"
   },
   "put": {
    "operationId": "put-messages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "content": {
          "description": "Message body.",
          "type": "string",
          "x-description-zh": "消息正文。"
         },
         "is_bold": {
          "description": "Whether to show the title in bold.",
          "type": "boolean",
          "x-description-zh": "标题是否加粗。"
         },
         "is_external": {
          "description": "When true, clicking jumps to url and url is required; otherwise content is required.",
          "type": "boolean",
          "x-description-zh": "为真时点击跳 url,url 必填;否则 content 必填。"
         },
         "is_popup": {
          "description": "Whether to show it as a pop-up.",
          "type": "boolean",
          "x-description-zh": "是否弹窗显示。"
         },
         "is_red": {
          "description": "Whether to show the title in red.",
          "type": "boolean",
          "x-description-zh": "标题是否标红。"
         },
         "is_show": {
          "description": "Whether the message is visible.",
          "type": "boolean",
          "x-description-zh": "是否显示。"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         },
         "title": {
          "description": "Message title.",
          "type": "string",
          "x-description-zh": "消息标题。"
         },
         "url": {
          "description": "Link opened on click when is_external is true.",
          "type": "string",
          "x-description-zh": "is_external 为真时点击跳转的链接。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update message",
    "tags": [
     "messages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改消息"
   }
  },
  "/api/v2/monitor-logs": {
   "get": {
    "operationId": "get-monitor-logs",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Filter by node.",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by node.",
       "type": "integer",
       "x-description-zh": "按节点过滤。"
      }
     },
     {
      "description": "Filter by IP (exact match).",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Filter by IP (exact match).",
       "type": "string",
       "x-description-zh": "按 IP 过滤(精确匹配)。"
      }
     },
     {
      "description": "Filter by result: 1 reachable, 0 unreachable, -1 undetermined.",
      "in": "query",
      "name": "result",
      "schema": {
       "description": "Filter by result: 1 reachable, 0 unreachable, -1 undetermined.",
       "enum": [
        -1,
        0,
        1
       ],
       "type": "integer",
       "x-description-zh": "按结果过滤:1 通;0 不通;-1 判不了。"
      }
     },
     {
      "description": "Filter by type: aval availability probe, bw bandwidth sample. Omitted = all.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by type: aval availability probe, bw bandwidth sample. Omitted = all.",
       "enum": [
        "aval",
        "bw"
       ],
       "type": "string",
       "x-description-zh": "按类型过滤:aval 可用性探测;bw 带宽采样。不给 = 全部。"
      }
     },
     {
      "description": "Filter by monitor group (as returned by the external probe service, exact match); empty string = rows from the master's built-in probe. Omitted = all.",
      "in": "query",
      "name": "probe_group",
      "schema": {
       "description": "Filter by monitor group (as returned by the external probe service, exact match); empty string = rows from the master's built-in probe. Omitted = all.",
       "type": "string",
       "x-description-zh": "按监控组过滤(外部探测服务回的监控组,精确匹配);空串 = 主控内建探测的行。不给 = 全部。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339.",
      "in": "query",
      "name": "since",
      "schema": {
       "description": "Start time (inclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339.",
      "in": "query",
      "name": "until",
      "schema": {
       "description": "End time (exclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "截止时间(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List node monitor probe logs",
    "tags": [
     "monitor-logs"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出节点监控探测日志"
   }
  },
  "/api/v2/node-enroll-tokens": {
   "post": {
    "operationId": "post-node-enroll-tokens",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create node enrollment token",
    "tags": [
     "node-enroll-tokens"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "生成节点接入令牌"
   }
  },
  "/api/v2/node-groups": {
   "get": {
    "operationId": "get-node-groups",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
       "type": "string",
       "x-description-zh": "只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List node groups",
    "tags": [
     "node-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出节点分组"
   },
   "post": {
    "operationId": "post-node-groups",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "backup_interval_s": {
          "description": "Rotation interval in seconds in interval mode.",
          "type": "integer",
          "x-description-zh": "interval 方式的轮换间隔(秒)。"
         },
         "backup_ip_num": {
          "description": "Number of backup IPs in use per rotation in interval mode.",
          "type": "integer",
          "x-description-zh": "interval 方式每轮在用的备用 IP 数。"
         },
         "backup_min_online": {
          "description": "When usable lines in the group drop below this, access names referencing the group are switched to their own backup groups; 0 = never switch automatically, default 1 (switch when none is usable).",
          "type": "integer",
          "x-description-zh": "组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。"
         },
         "backup_switch_order": {
          "description": "Rotation order in interval mode: seq picks the least recently used first; rand picks at random.",
          "enum": [
           "seq",
           "rand"
          ],
          "type": "object",
          "x-description-zh": "interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。",
          "x-gocdn-type": "BackupSwitchOrder"
         },
         "backup_switch_type": {
          "description": "Backup IP switch mode. master_down: bring in as many backup IPs as there are unavailable primary IPs on the same DNS line; gt_online_ip: when online primary IPs are fewer than backup IPs, bring in backups to make up the difference (at most the number of unavailable primary IPs); interval: every IP in the group is a backup and they rotate on a timer (the group must have no primary IPs before switching to interval).",
          "enum": [
           "master_down",
           "gt_online_ip",
           "interval"
          ],
          "type": "object",
          "x-description-zh": "备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。",
          "x-gocdn-type": "BackupSwitchType"
         },
         "cname_hostname": {
          "description": "Host record part of the access name (for example www); lowercase letters, digits, hyphens, dot-separated labels; unique across groups (409 cname_hostname_taken); empty on create generates 8 random characters, empty on update keeps the current value.",
          "type": "string",
          "x-description-zh": "接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create node group",
    "tags": [
     "node-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建节点分组"
   }
  },
  "/api/v2/node-groups/{id}": {
   "delete": {
    "operationId": "delete-node-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete node group",
    "tags": [
     "node-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除节点分组"
   },
   "get": {
    "operationId": "get-node-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get node group",
    "tags": [
     "node-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取节点分组"
   },
   "put": {
    "operationId": "put-node-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "backup_min_online": 2
       },
       "schema": {
        "properties": {
         "backup_interval_s": {
          "description": "Rotation interval in seconds in interval mode.",
          "type": "integer",
          "x-description-zh": "interval 方式的轮换间隔(秒)。"
         },
         "backup_ip_num": {
          "description": "Number of backup IPs in use per rotation in interval mode.",
          "type": "integer",
          "x-description-zh": "interval 方式每轮在用的备用 IP 数。"
         },
         "backup_min_online": {
          "description": "When usable lines in the group drop below this, access names referencing the group are switched to their own backup groups; 0 = never switch automatically, default 1 (switch when none is usable).",
          "type": "integer",
          "x-description-zh": "组内可用线路少于它就把引用本组的接入名自动切到各自的备用组;0 = 不自动切,缺省 1(可用为 0 即切)。"
         },
         "backup_switch_order": {
          "description": "Rotation order in interval mode: seq picks the least recently used first; rand picks at random.",
          "enum": [
           "seq",
           "rand"
          ],
          "type": "object",
          "x-description-zh": "interval 方式的轮换顺序:seq 按最久未用的顺序;rand 随机。",
          "x-gocdn-type": "BackupSwitchOrder"
         },
         "backup_switch_type": {
          "description": "Backup IP switch mode. master_down: bring in as many backup IPs as there are unavailable primary IPs on the same DNS line; gt_online_ip: when online primary IPs are fewer than backup IPs, bring in backups to make up the difference (at most the number of unavailable primary IPs); interval: every IP in the group is a backup and they rotate on a timer (the group must have no primary IPs before switching to interval).",
          "enum": [
           "master_down",
           "gt_online_ip",
           "interval"
          ],
          "type": "object",
          "x-description-zh": "备用 IP 切换方式。master_down = 同一解析线路主 IP 不可用几个就启用几个备用;gt_online_ip = 在线主 IP 数少于备用 IP 数时补齐备用(不超过不可用主 IP 数);interval = 组内全是备用 IP,按间隔轮换(切到 interval 前组内不能有主 IP)。",
          "x-gocdn-type": "BackupSwitchType"
         },
         "cname_hostname": {
          "description": "Host record part of the access name (for example www); lowercase letters, digits, hyphens, dot-separated labels; unique across groups (409 cname_hostname_taken); empty on create generates 8 random characters, empty on update keeps the current value.",
          "type": "string",
          "x-description-zh": "接入名的主机记录部分(如 www),小写字母/数字/连字符、点分多段;各分组不能重复(409 cname_hostname_taken);新增留空随机生成 8 位,编辑留空保持原值。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update node group",
    "tags": [
     "node-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改节点分组"
   }
  },
  "/api/v2/nodes": {
   "get": {
    "operationId": "get-nodes",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List nodes",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出节点"
   },
   "post": {
    "operationId": "post-nodes",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "ip": "192.0.2.20",
        "name": "edge-1-ip2",
        "parent_id": 1
       },
       "schema": {
        "properties": {
         "area": {
          "description": "Area (display only, never sent to nodes); empty = not set. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。"
         },
         "bandwidth_mbps": {
          "description": "Node bandwidth in Mbps (display only, unrelated to monitor.bw_limit_mbps); 0 = not set. Sub-IPs take the primary node's value.",
          "type": "integer",
          "x-description-zh": "节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ip": {
          "description": "Node IP address (IPv4 or IPv6).",
          "type": "string",
          "x-description-zh": "节点 IP 地址(IPv4 或 IPv6)。"
         },
         "monitor": {
          "description": "Node monitor probe settings (the control plane probes this IP at the interval configured in monitor.node).",
          "type": "object",
          "x-description-zh": "节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。",
          "x-gocdn-type": "NodeMonitor"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "parent_id": {
          "description": "Primary node that owns this sub-IP; null = primary node.",
          "type": "integer",
          "x-description-zh": "子 IP 所属主节点;null = 主节点。"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         },
         "service_expire": {
          "description": "Server service expiry date YYYY-MM-DD (used for the home-page expiry reminder; never auto-disables); null = not set, no reminder. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。"
         },
         "service_start": {
          "description": "Server service start date YYYY-MM-DD (display only); null = not set. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create node",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建节点"
   }
  },
  "/api/v2/nodes/{id}": {
   "delete": {
    "operationId": "delete-nodes-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete node",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除节点"
   },
   "get": {
    "operationId": "get-nodes-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "When true, include capacity (primary nodes only; null when no system info is available).",
      "in": "query",
      "name": "capacity",
      "schema": {
       "description": "When true, include capacity (primary nodes only; null when no system info is available).",
       "type": "boolean",
       "x-description-zh": "为 true 时附带 capacity(主节点才有;没有系统信息时为 null)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get node",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取节点"
   },
   "put": {
    "operationId": "put-nodes-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "bandwidth_mbps": 30
       },
       "schema": {
        "properties": {
         "area": {
          "description": "Area (display only, never sent to nodes); empty = not set. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "地区(只做展示,不下发节点);空 = 未填。子 IP 取主节点的。"
         },
         "bandwidth_mbps": {
          "description": "Node bandwidth in Mbps (display only, unrelated to monitor.bw_limit_mbps); 0 = not set. Sub-IPs take the primary node's value.",
          "type": "integer",
          "x-description-zh": "节点带宽 Mbps(只做展示,与 monitor.bw_limit_mbps 无关);0 = 未填。子 IP 取主节点的。"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ip": {
          "description": "Node IP address (IPv4 or IPv6).",
          "type": "string",
          "x-description-zh": "节点 IP 地址(IPv4 或 IPv6)。"
         },
         "monitor": {
          "description": "Node monitor probe settings (the control plane probes this IP at the interval configured in monitor.node).",
          "type": "object",
          "x-description-zh": "节点监控探测设置(主控按 monitor.node 配置的间隔探这个 IP)。",
          "x-gocdn-type": "NodeMonitor"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "parent_id": {
          "description": "Primary node that owns this sub-IP; null = primary node.",
          "type": "integer",
          "x-description-zh": "子 IP 所属主节点;null = 主节点。"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         },
         "service_expire": {
          "description": "Server service expiry date YYYY-MM-DD (used for the home-page expiry reminder; never auto-disables); null = not set, no reminder. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "服务器到期日 YYYY-MM-DD(首页到期提醒用,不自动停用);null = 未填、不提醒。子 IP 取主节点的。"
         },
         "service_start": {
          "description": "Server service start date YYYY-MM-DD (display only); null = not set. Sub-IPs take the primary node's value.",
          "type": "string",
          "x-description-zh": "服务器开始日 YYYY-MM-DD(只做展示);null = 未填。子 IP 取主节点的。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update node",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改节点"
   }
  },
  "/api/v2/nodes/{id}/config-readmit": {
   "post": {
    "operationId": "post-nodes-id-config-readmit",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Re-push the config a node rolled back",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "重新下发被节点回滚的配置"
   }
  },
  "/api/v2/nodes/{id}/local-addrs": {
   "get": {
    "operationId": "get-nodes-id-local-addrs",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node NIC addresses",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点网卡地址"
   }
  },
  "/api/v2/nodes/{id}/to-pending": {
   "post": {
    "operationId": "post-nodes-id-to-pending",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Move node back to pending",
    "tags": [
     "nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点移回待初始化"
   }
  },
  "/api/v2/orders": {
   "get": {
    "operationId": "get-orders",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by order type (recharge/deduct/payment/package, etc.).",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by order type (recharge/deduct/payment/package, etc.).",
       "type": "string",
       "x-description-zh": "按订单类型过滤(recharge/deduct/payment/package 等)。"
      }
     },
     {
      "description": "Filter by status.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Filter by status.",
       "enum": [
        "unpaid",
        "paid"
       ],
       "type": "string",
       "x-description-zh": "按状态过滤。"
      }
     },
     {
      "description": "Order time from (inclusive), RFC 3339.",
      "in": "query",
      "name": "start",
      "schema": {
       "description": "Order time from (inclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "下单时间起(含),RFC 3339。"
      }
     },
     {
      "description": "Order time until (exclusive), RFC 3339.",
      "in": "query",
      "name": "end",
      "schema": {
       "description": "Order time until (exclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "下单时间止(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List orders",
    "tags": [
     "orders"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出订单"
   }
  },
  "/api/v2/orders/stats": {
   "get": {
    "operationId": "get-orders-stats",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by order type (recharge/deduct/payment/package, etc.).",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by order type (recharge/deduct/payment/package, etc.).",
       "type": "string",
       "x-description-zh": "按订单类型过滤(recharge/deduct/payment/package 等)。"
      }
     },
     {
      "description": "Filter by status.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Filter by status.",
       "enum": [
        "unpaid",
        "paid"
       ],
       "type": "string",
       "x-description-zh": "按状态过滤。"
      }
     },
     {
      "description": "Order time from (inclusive), RFC 3339.",
      "in": "query",
      "name": "start",
      "schema": {
       "description": "Order time from (inclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "下单时间起(含),RFC 3339。"
      }
     },
     {
      "description": "Order time until (exclusive), RFC 3339.",
      "in": "query",
      "name": "end",
      "schema": {
       "description": "Order time until (exclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "下单时间止(不含),RFC 3339。"
      }
     },
     {
      "description": "Aggregation granularity, default day.",
      "in": "query",
      "name": "group_by",
      "schema": {
       "description": "Aggregation granularity, default day.",
       "enum": [
        "day",
        "month",
        "year"
       ],
       "type": "string",
       "x-description-zh": "汇总粒度,缺省 day。"
      }
     },
     {
      "description": "Deprecated and kept only for compatibility with old callers (the range is still validated). Days, months and years are always split in the platform time zone (Asia/Shanghai), the same day boundary as today's traffic; this parameter no longer shifts them.",
      "in": "query",
      "name": "utc_offset_minutes",
      "schema": {
       "description": "Deprecated and kept only for compatibility with old callers (the range is still validated). Days, months and years are always split in the platform time zone (Asia/Shanghai), the same day boundary as today's traffic; this parameter no longer shifts them.",
       "type": "integer",
       "x-description-zh": "已废弃,仅为兼容旧调用方保留(仍校验取值范围)。日/月/年恒按平台时区(Asia/Shanghai)切分,与今日流量同一日界,不再随此参数平移。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Order amount statistics",
    "tags": [
     "orders"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "订单金额统计"
   }
  },
  "/api/v2/orders/{id}": {
   "get": {
    "operationId": "get-orders-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get order",
    "tags": [
     "orders"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取订单"
   },
   "put": {
    "operationId": "put-orders-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "des": "线下转账已核对"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         }
        },
        "required": [
         "des"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update order remark",
    "tags": [
     "orders"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "改订单备注"
   }
  },
  "/api/v2/package-catalog": {
   "get": {
    "operationId": "get-package-catalog",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Purchasable package catalog",
    "tags": [
     "package-catalog"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "可购买的套餐目录"
   }
  },
  "/api/v2/package-groups": {
   "get": {
    "operationId": "get-package-groups",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List package groups",
    "tags": [
     "package-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出套餐分组"
   },
   "post": {
    "operationId": "post-package-groups",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "name": "入门套餐"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create package group",
    "tags": [
     "package-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建套餐分组"
   }
  },
  "/api/v2/package-groups/{id}": {
   "delete": {
    "operationId": "delete-package-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete package group",
    "tags": [
     "package-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除套餐分组"
   },
   "get": {
    "operationId": "get-package-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get package group",
    "tags": [
     "package-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取套餐分组"
   },
   "put": {
    "operationId": "put-package-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "name": "入门套餐"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update package group",
    "tags": [
     "package-groups"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改套餐分组"
   }
  },
  "/api/v2/package-monitor": {
   "get": {
    "operationId": "get-package-monitor",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by user package id.",
      "in": "query",
      "name": "user_package_id",
      "schema": {
       "description": "Filter by user package id.",
       "type": "integer",
       "x-description-zh": "按用户套餐 id 过滤。"
      }
     },
     {
      "description": "Node ID",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Node ID",
       "type": "integer",
       "x-description-zh": "节点 ID"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Package monitor",
    "tags": [
     "package-monitor"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "套餐监控"
   }
  },
  "/api/v2/package-monitor/{id}/nodes": {
   "get": {
    "operationId": "get-package-monitor-id-nodes",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Package monitor by node",
    "tags": [
     "package-monitor"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "套餐监控(按节点)"
   }
  },
  "/api/v2/package-upgrades": {
   "get": {
    "operationId": "get-package-upgrades",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List upgrade packs",
    "tags": [
     "package-upgrades"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出升级包"
   },
   "post": {
    "operationId": "post-package-upgrades",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "amount": 10,
        "name": "域名 +10",
        "price_cents": 1000,
        "type": "domain"
       },
       "schema": {
        "properties": {
         "amount": {
          "description": "Amount added per unit; always 1 for feature items (custom_cc_rule/websocket).",
          "type": "integer",
          "x-description-zh": "每份加多少;功能类(custom_cc_rule/websocket)恒为 1"
         },
         "bind_packages": {
          "description": "Only these base packages may buy it; empty = no restriction.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "只许这些基础套餐加购;空 = 不限"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "price_cents": {
          "description": "Price per unit per month, in cents.",
          "type": "integer",
          "x-description-zh": "每份每月价格,分"
         },
         "type": {
          "description": "Add-on item: traffic GB, domains, non-standard ports, TCP/UDP forwarding ports, custom CC, bandwidth Mbps, connections, WebSocket, dedicated IPs.",
          "enum": [
           "traffic",
           "domain",
           "http_port",
           "stream_port",
           "custom_cc_rule",
           "bandwidth",
           "connection",
           "websocket",
           "ip_num"
          ],
          "type": "string",
          "x-description-zh": "加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数"
         }
        },
        "required": [
         "name",
         "price_cents",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create upgrade pack",
    "tags": [
     "package-upgrades"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建升级包"
   }
  },
  "/api/v2/package-upgrades/{id}": {
   "delete": {
    "operationId": "delete-package-upgrades-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete upgrade pack",
    "tags": [
     "package-upgrades"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除升级包"
   },
   "get": {
    "operationId": "get-package-upgrades-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get upgrade pack",
    "tags": [
     "package-upgrades"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取升级包"
   },
   "put": {
    "operationId": "put-package-upgrades-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "amount": 10,
        "name": "域名 +10",
        "price_cents": 1000,
        "type": "domain"
       },
       "schema": {
        "properties": {
         "amount": {
          "description": "Amount added per unit; always 1 for feature items (custom_cc_rule/websocket).",
          "type": "integer",
          "x-description-zh": "每份加多少;功能类(custom_cc_rule/websocket)恒为 1"
         },
         "bind_packages": {
          "description": "Only these base packages may buy it; empty = no restriction.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "只许这些基础套餐加购;空 = 不限"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "price_cents": {
          "description": "Price per unit per month, in cents.",
          "type": "integer",
          "x-description-zh": "每份每月价格,分"
         },
         "type": {
          "description": "Add-on item: traffic GB, domains, non-standard ports, TCP/UDP forwarding ports, custom CC, bandwidth Mbps, connections, WebSocket, dedicated IPs.",
          "enum": [
           "traffic",
           "domain",
           "http_port",
           "stream_port",
           "custom_cc_rule",
           "bandwidth",
           "connection",
           "websocket",
           "ip_num"
          ],
          "type": "string",
          "x-description-zh": "加购项:流量 GB、域名数、非标端口数、四层端口数、自定义 CC、带宽 Mbps、连接数、WebSocket、独立 IP 数"
         }
        },
        "required": [
         "name",
         "price_cents",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update upgrade pack",
    "tags": [
     "package-upgrades"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改升级包"
   }
  },
  "/api/v2/packages": {
   "get": {
    "operationId": "get-packages",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List packages",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出套餐"
   },
   "post": {
    "operationId": "post-packages",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "domains": 10,
        "group_ids": [],
        "http_ports": 2,
        "name": "基础版",
        "price_month_cents": 3000,
        "price_quarter_cents": 8000,
        "price_year_cents": 30000
       },
       "schema": {
        "properties": {
         "backup_group_id": {
          "description": "Backup node group; null = none.",
          "type": "integer",
          "x-description-zh": "备用线路分组;null = 没有"
         },
         "bandwidth_mbps": {
          "description": "Bandwidth in Mbps, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "带宽 Mbps,-1 不限"
         },
         "buy_limit": {
          "description": "Maximum copies a tenant may hold, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "每租户最多持有几份,-1 不限"
         },
         "cname_domain_id": {
          "description": "CNAME root domain; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "接入根域(CNAME 域名);null = 套餐不绑线路"
         },
         "cname_host_suffix": {
          "description": "Suffix for newly generated host records; empty = only the 8-character random name.",
          "type": "string",
          "x-description-zh": "新生成主机记录的后缀;空 = 只有 8 位随机名"
         },
         "cname_mode": {
          "description": "CNAME mode. site = one access name per site or stream; package = sites and streams of a purchased package share one access name.",
          "enum": [
           "site",
           "package"
          ],
          "type": "object",
          "x-description-zh": "CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。",
          "x-gocdn-type": "PackageCnameMode"
         },
         "connections": {
          "description": "Concurrent connections, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "并发连接数,-1 不限"
         },
         "custom_cc_rule": {
          "description": "Allows custom CC rules.",
          "type": "boolean",
          "x-description-zh": "可自定义 CC 规则"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "domains": {
          "description": "Number of domains (each IP site counts as 1), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "域名数(IP 站每站占 1),-1 不限"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_ids": {
          "description": "Package groups it belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "所属套餐分组"
         },
         "http_ports": {
          "description": "Number of non-standard HTTP/HTTPS ports (other than 80/443), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "HTTP/HTTPS 非标端口数(80/443 之外),-1 不限"
         },
         "ip_num": {
          "description": "Number of selectable IPs (\"My IPs\"), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "可选 IP 数(「我的 IP」),-1 不限"
         },
         "ip_pool_id": {
          "description": "IP pool used to provision IP sites (IP product line); null = not provisioned.",
          "type": "integer",
          "x-description-zh": "开通 IP 站点用的 IP 池(IP 产品线);null = 不开通"
         },
         "ip_site_port": {
          "description": "IP-site ports: distinct ports across all IP sites of the package (80/443 included), -1 = unlimited; IP-site ports do not count toward non-standard ports.",
          "type": "integer",
          "x-description-zh": "IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数"
         },
         "l2": {
          "description": "Includes tiered origin (tenant switch of the paid feature l2): tenants can turn on tiered origin for sites, and nodes use it, only while the master license l2 is active; existing packages are false (on upgrade, purchased packages of tenants already using tiered origin are set to true).",
          "type": "boolean",
          "x-description-zh": "含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true)"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "node_group_id": {
          "description": "Primary node group; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "主线路分组;null = 套餐不绑线路"
         },
         "origin_ip_limit": {
          "description": "Allowed origin IPs or CIDR ranges; empty = any. When set, origins of sites under the package must fall inside them and domain origins are rejected.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许"
         },
         "owners": {
          "description": "Tenant ids allowed to buy; empty = no restriction.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "限定可购买的租户 id;空 = 不限"
         },
         "price_month_cents": {
          "description": "Monthly price in cents.",
          "type": "integer",
          "x-description-zh": "月价,分"
         },
         "price_quarter_cents": {
          "description": "Quarterly price in cents.",
          "type": "integer",
          "x-description-zh": "季价,分"
         },
         "price_year_cents": {
          "description": "Yearly price in cents.",
          "type": "integer",
          "x-description-zh": "年价,分"
         },
         "region_id": {
          "description": "Region; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "区域;null = 套餐不绑线路"
         },
         "renew_before_days": {
          "description": "Renewal is only allowed within this many days before expiry, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "到期前几天内才许续费,-1 不限"
         },
         "require_verified": {
          "description": "Real-name verification is required to purchase.",
          "type": "boolean",
          "x-description-zh": "须实名认证才能购买"
         },
         "sale_until": {
          "description": "Not sold after this time; omitted/null = no limit.",
          "type": "string",
          "x-description-zh": "过了此刻不再出售;不给/null = 不限"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         },
         "stream_ports": {
          "description": "Number of TCP/UDP forwarding ports, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "四层转发端口数,-1 不限"
         },
         "traffic_gb": {
          "description": "Traffic in GB per billing cycle, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "每计费周期流量 GB,-1 不限"
         },
         "waf_enhanced": {
          "description": "Includes WAF Enhanced (tenant switch of the paid feature waf_enhanced): tenants can use standard/strict levels, big screen, deep Bot, anti-tamper and so on only while the master license WAF Enhanced is not degraded; existing packages are false.",
          "type": "boolean",
          "x-description-zh": "含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false"
         },
         "websocket": {
          "description": "Allows WebSocket.",
          "type": "boolean",
          "x-description-zh": "可开 WebSocket"
         }
        },
        "required": [
         "name",
         "price_month_cents",
         "price_quarter_cents",
         "price_year_cents"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create package",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建套餐"
   }
  },
  "/api/v2/packages/batch-enable": {
   "post": {
    "operationId": "post-packages-batch-enable",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "enabled": false,
        "ids": [
         1,
         2
        ]
       },
       "schema": {
        "properties": {
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "ids": {
          "description": "IDs of the objects to change, at most 100.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要改的对象 id,至多 100 个。"
         }
        },
        "required": [
         "enabled",
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch enable or disable packages",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "批量启用或禁用套餐"
   }
  },
  "/api/v2/packages/{id}": {
   "delete": {
    "operationId": "delete-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete package",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除套餐"
   },
   "get": {
    "operationId": "get-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get package",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取套餐"
   },
   "put": {
    "operationId": "put-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "domains": 10,
        "group_ids": [],
        "http_ports": 2,
        "name": "基础版",
        "price_month_cents": 3000,
        "price_quarter_cents": 8000,
        "price_year_cents": 30000
       },
       "schema": {
        "properties": {
         "backup_group_id": {
          "description": "Backup node group; null = none.",
          "type": "integer",
          "x-description-zh": "备用线路分组;null = 没有"
         },
         "bandwidth_mbps": {
          "description": "Bandwidth in Mbps, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "带宽 Mbps,-1 不限"
         },
         "buy_limit": {
          "description": "Maximum copies a tenant may hold, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "每租户最多持有几份,-1 不限"
         },
         "cname_domain_id": {
          "description": "CNAME root domain; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "接入根域(CNAME 域名);null = 套餐不绑线路"
         },
         "cname_host_suffix": {
          "description": "Suffix for newly generated host records; empty = only the 8-character random name.",
          "type": "string",
          "x-description-zh": "新生成主机记录的后缀;空 = 只有 8 位随机名"
         },
         "cname_mode": {
          "description": "CNAME mode. site = one access name per site or stream; package = sites and streams of a purchased package share one access name.",
          "enum": [
           "site",
           "package"
          ],
          "type": "object",
          "x-description-zh": "CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。",
          "x-gocdn-type": "PackageCnameMode"
         },
         "connections": {
          "description": "Concurrent connections, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "并发连接数,-1 不限"
         },
         "custom_cc_rule": {
          "description": "Allows custom CC rules.",
          "type": "boolean",
          "x-description-zh": "可自定义 CC 规则"
         },
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "domains": {
          "description": "Number of domains (each IP site counts as 1), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "域名数(IP 站每站占 1),-1 不限"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_ids": {
          "description": "Package groups it belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "所属套餐分组"
         },
         "http_ports": {
          "description": "Number of non-standard HTTP/HTTPS ports (other than 80/443), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "HTTP/HTTPS 非标端口数(80/443 之外),-1 不限"
         },
         "ip_num": {
          "description": "Number of selectable IPs (\"My IPs\"), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "可选 IP 数(「我的 IP」),-1 不限"
         },
         "ip_pool_id": {
          "description": "IP pool used to provision IP sites (IP product line); null = not provisioned.",
          "type": "integer",
          "x-description-zh": "开通 IP 站点用的 IP 池(IP 产品线);null = 不开通"
         },
         "ip_site_port": {
          "description": "IP-site ports: distinct ports across all IP sites of the package (80/443 included), -1 = unlimited; IP-site ports do not count toward non-standard ports.",
          "type": "integer",
          "x-description-zh": "IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数"
         },
         "l2": {
          "description": "Includes tiered origin (tenant switch of the paid feature l2): tenants can turn on tiered origin for sites, and nodes use it, only while the master license l2 is active; existing packages are false (on upgrade, purchased packages of tenants already using tiered origin are set to true).",
          "type": "boolean",
          "x-description-zh": "含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true)"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "node_group_id": {
          "description": "Primary node group; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "主线路分组;null = 套餐不绑线路"
         },
         "origin_ip_limit": {
          "description": "Allowed origin IPs or CIDR ranges; empty = any. When set, origins of sites under the package must fall inside them and domain origins are rejected.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "允许的源站 IP/网段;空 = 不限。非空时该套餐下站点的源站须落在其中,域名源站不许"
         },
         "owners": {
          "description": "Tenant ids allowed to buy; empty = no restriction.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "限定可购买的租户 id;空 = 不限"
         },
         "price_month_cents": {
          "description": "Monthly price in cents.",
          "type": "integer",
          "x-description-zh": "月价,分"
         },
         "price_quarter_cents": {
          "description": "Quarterly price in cents.",
          "type": "integer",
          "x-description-zh": "季价,分"
         },
         "price_year_cents": {
          "description": "Yearly price in cents.",
          "type": "integer",
          "x-description-zh": "年价,分"
         },
         "region_id": {
          "description": "Region; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "区域;null = 套餐不绑线路"
         },
         "renew_before_days": {
          "description": "Renewal is only allowed within this many days before expiry, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "到期前几天内才许续费,-1 不限"
         },
         "require_verified": {
          "description": "Real-name verification is required to purchase.",
          "type": "boolean",
          "x-description-zh": "须实名认证才能购买"
         },
         "sale_until": {
          "description": "Not sold after this time; omitted/null = no limit.",
          "type": "string",
          "x-description-zh": "过了此刻不再出售;不给/null = 不限"
         },
         "sort": {
          "description": "Display order (smaller first).",
          "type": "integer",
          "x-description-zh": "排序值(小的在前)。"
         },
         "stream_ports": {
          "description": "Number of TCP/UDP forwarding ports, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "四层转发端口数,-1 不限"
         },
         "traffic_gb": {
          "description": "Traffic in GB per billing cycle, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "每计费周期流量 GB,-1 不限"
         },
         "waf_enhanced": {
          "description": "Includes WAF Enhanced (tenant switch of the paid feature waf_enhanced): tenants can use standard/strict levels, big screen, deep Bot, anti-tamper and so on only while the master license WAF Enhanced is not degraded; existing packages are false.",
          "type": "boolean",
          "x-description-zh": "含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false"
         },
         "websocket": {
          "description": "Allows WebSocket.",
          "type": "boolean",
          "x-description-zh": "可开 WebSocket"
         }
        },
        "required": [
         "name",
         "price_month_cents",
         "price_quarter_cents",
         "price_year_cents"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update package",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改套餐"
   }
  },
  "/api/v2/packages/{id}/syncs": {
   "post": {
    "operationId": "post-packages-id-syncs",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "items": [
         "traffic_gb",
         "price_month_cents"
        ]
       },
       "schema": {
        "properties": {
         "items": {
          "description": "Fields to sync.",
          "items": {
           "type": "object",
           "x-gocdn-type": "PackageSyncField"
          },
          "type": "array",
          "x-description-zh": "要同步的字段"
         }
        },
        "required": [
         "items"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Sync base package to purchased packages",
    "tags": [
     "packages"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "同步基础套餐到已购套餐"
   }
  },
  "/api/v2/panel-cert": {
   "get": {
    "operationId": "get-panel-cert",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get panel certificate status",
    "tags": [
     "panel-cert"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查看面板证书状态"
   }
  },
  "/api/v2/panel-cert/issue": {
   "post": {
    "operationId": "post-panel-cert-issue",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Issue panel certificate",
    "tags": [
     "panel-cert"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "一键申请面板证书"
   }
  },
  "/api/v2/payment-channels": {
   "get": {
    "operationId": "get-payment-channels",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get payment channel settings",
    "tags": [
     "payment-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "支付通道设置"
   },
   "put": {
    "operationId": "put-payment-channels",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "alipay": {
          "description": "Merchant parameters of the Alipay gateway.",
          "type": "object",
          "x-description-zh": "支付宝网关的商户参数。",
          "x-gocdn-type": "AlipayGateway"
         },
         "codepay": {
          "description": "Merchant parameters of the Codepay gateway.",
          "type": "object",
          "x-description-zh": "码支付网关的商户参数。",
          "x-gocdn-type": "CodepayGateway"
         },
         "default_method": {
          "description": "The method selected by default on the recharge page; transfer = bank transfer (transfer must be enabled).",
          "enum": [
           "",
           "alipay",
           "wxpay",
           "transfer"
          ],
          "type": "string",
          "x-description-zh": "充值页默认选中的方式;transfer = 转账汇款(须已开启转账)。"
         },
         "epay": {
          "description": "Merchant parameters of the Epay gateway.",
          "type": "object",
          "x-description-zh": "易支付网关的商户参数。",
          "x-gocdn-type": "EpayGateway"
         },
         "methods": {
          "description": "Enable switch and gateway for each online payment method.",
          "type": "object",
          "x-description-zh": "各在线支付方式的开关与所走网关。",
          "x-gocdn-type": "PaymentMethodSet"
         },
         "notify_base": {
          "description": "Root URL of the panel reachable by the gateways (for example https://panel.example.com); callback URLs are built from it, and empty = orders cannot be placed.",
          "type": "string",
          "x-description-zh": "面板对网关可达的根地址(如 https://panel.example.com);回调地址由它拼出,空 = 不能下单。"
         },
         "return_url": {
          "description": "Page to return to after payment (used by Alipay desktop website payment and Epay); empty = no redirect.",
          "type": "string",
          "x-description-zh": "付款后跳回的页面(支付宝电脑网站支付、易支付用);空 = 不跳。"
         },
         "transfer": {
          "description": "Offline transfer settings.",
          "type": "object",
          "x-description-zh": "线下转账设置。",
          "x-gocdn-type": "PaymentTransfer"
         },
         "wxpay": {
          "description": "Merchant parameters of the WeChat Pay gateway.",
          "type": "object",
          "x-description-zh": "微信支付网关的商户参数。",
          "x-gocdn-type": "WxpayGateway"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update payment channels",
    "tags": [
     "payment-channels"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改支付通道"
   }
  },
  "/api/v2/payment-methods": {
   "get": {
    "operationId": "get-payment-methods",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get available recharge methods",
    "tags": [
     "payment-methods"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "可用的充值方式"
   }
  },
  "/api/v2/payment-notifications/{gateway}": {
   "get": {
    "operationId": "get-payment-notifications-gateway",
    "parameters": [
     {
      "in": "path",
      "name": "gateway",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Payment notification callback (GET)",
    "tags": [
     "payment-notifications"
    ],
    "x-summary-zh": "支付结果回调(GET)"
   },
   "post": {
    "operationId": "post-payment-notifications-gateway",
    "parameters": [
     {
      "in": "path",
      "name": "gateway",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Payment notification callback",
    "tags": [
     "payment-notifications"
    ],
    "x-summary-zh": "支付结果回调"
   }
  },
  "/api/v2/payments/{provider}/orders": {
   "post": {
    "operationId": "post-payments-provider-orders",
    "parameters": [
     {
      "in": "path",
      "name": "provider",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "amount_cents": {
          "description": "Recharge amount in cents.",
          "type": "integer",
          "x-description-zh": "充值金额(分)。"
         }
        },
        "required": [
         "amount_cents"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create online payment",
    "tags": [
     "payments"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "发起在线支付"
   }
  },
  "/api/v2/pending-nodes": {
   "get": {
    "operationId": "get-pending-nodes",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List pending nodes",
    "tags": [
     "pending-nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出待接入节点"
   }
  },
  "/api/v2/pending-nodes/{id}": {
   "delete": {
    "operationId": "delete-pending-nodes-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete pending node",
    "tags": [
     "pending-nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除待接入节点"
   }
  },
  "/api/v2/pending-nodes/{id}/approve": {
   "post": {
    "operationId": "post-pending-nodes-id-approve",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "ip": {
          "description": "Source address of the registration connection.",
          "type": "string",
          "x-description-zh": "注册连接的来源地址。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "region_id": {
          "description": "Region ID",
          "type": "integer",
          "x-description-zh": "区域 ID"
         },
         "replace_node_id": {
          "description": "Replace an existing primary node (new machine takes over the old one): the new node inherits the old node's lines, IP pool IP, region (when region_id is omitted), monitor settings, service period and area/bandwidth; the old node is disabled and removed from DNS, all in the approval transaction. The old node's sub IPs move to the new node by default (lines, pool IPs and monitor settings kept); see replace_sub_ips for new addresses or opting out. The old node must be an approved primary node with the same role; 409 ip_in_use when its pool IP is bound to IP sites and the IP changes.",
          "type": "integer",
          "x-description-zh": "替换已有主节点(新机顶替旧机):新节点继承旧节点的线路、IP 池里的 IP、区域(没给 region_id 时)、监控设置、服务期与地区/带宽,旧节点停用并从解析摘除,与审核同一事务。旧节点的子 IP 默认一并改挂新节点(线路、池内 IP、监控设置不变),地址与不迁见 replace_sub_ips。旧节点须是已审主节点、角色相同;池内 IP 被 IP 站点绑定且 IP 变了时 409 ip_in_use。"
         },
         "replace_sub_ips": {
          "description": "Per-sub-IP handling of the old node when replacing (only with replace_node_id); unlisted sub IPs move to the new node keeping their address. ip switches to a new address (422 conflict if another node uses it); skip=true leaves the sub IP and its lines on the old node, disabled.",
          "items": {
           "type": "object",
           "x-gocdn-type": "ReplaceSubIp"
          },
          "type": "array",
          "x-description-zh": "替换时逐条指定旧节点子 IP 的去向(只在给了 replace_node_id 时有效);没列出的子 IP 沿用原地址改挂新节点。ip 给了就改用新地址(已被别的节点用 422 conflict),skip 为 true 的不迁:该子 IP 及其线路随旧节点停用。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Approve pending node",
    "tags": [
     "pending-nodes"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "审核通过待接入节点"
   }
  },
  "/api/v2/pki-validations": {
   "get": {
    "operationId": "get-pki-validations",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List validation file contents",
    "tags": [
     "pki-validations"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出文件验证内容"
   },
   "post": {
    "operationId": "post-pki-validations",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "content": "example-validation-content",
        "name": "0123456789ABCDEF0123456789ABCDEF.txt",
        "ttl_s": 86400
       },
       "schema": {
        "properties": {
         "content": {
          "description": "Validation file content.",
          "type": "string",
          "x-description-zh": "验证文件内容。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "ttl_s": {
          "description": "Seconds after which the file is no longer served; 0 or omitted = never expires.",
          "type": "integer",
          "x-description-zh": "多少秒后不再代答;0 或不给 = 不过期。"
         }
        },
        "required": [
         "content",
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create validation file content",
    "tags": [
     "pki-validations"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "新建文件验证内容"
   }
  },
  "/api/v2/pki-validations/{id}": {
   "delete": {
    "operationId": "delete-pki-validations-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete validation file content",
    "tags": [
     "pki-validations"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除文件验证内容"
   }
  },
  "/api/v2/protect-schemes/leak": {
   "get": {
    "operationId": "get-protect-schemes-leak",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get the data leak protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取防泄露方案"
   },
   "put": {
    "operationId": "put-protect-schemes-leak",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "custom": {
          "description": "Custom regular expressions, at most 16.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteLeakGuardCustom"
          },
          "type": "array",
          "x-description-zh": "自定义正则,最多 16 条。"
         },
         "detect": {
          "description": "Action per built-in pattern; omit a pattern to not check it.",
          "type": "object",
          "x-description-zh": "内置识别各类的处置;不写 = 不查这一类。",
          "x-gocdn-type": "SiteLeakGuardDetect"
         },
         "exclude": {
          "description": "Path prefixes that are not checked (a trailing * is optional), at most 32.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "不检测的路径前缀(末尾 * 可省),最多 32 条。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never saved, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "observe_days": {
          "description": "Days a site observes when turned on by the scheme (record only, no action); 0 = act right away.",
          "type": "integer",
          "x-description-zh": "站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。"
         }
        },
        "required": [
         "custom",
         "detect",
         "exclude",
         "observe_days"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Save the data leak protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "保存防泄露方案"
   }
  },
  "/api/v2/protect-schemes/replay": {
   "get": {
    "operationId": "get-protect-schemes-replay",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get the replay protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取防重放方案"
   },
   "put": {
    "operationId": "put-protect-schemes-replay",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
          "enum": [
           "block",
           "challenge"
          ],
          "type": "object",
          "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
          "x-gocdn-type": "ReplayGuardAction"
         },
         "app_salt": {
          "description": "Signing salt (app key, 32-byte hex); with app_sign on but no salt, signed headers are never accepted.",
          "example": "0000000000000000000000000000000000000000000000000000000000000000",
          "type": "string",
          "x-description-zh": "签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。"
         },
         "app_sign": {
          "description": "App signed-header mode - requests carrying the signature headers are checked by signature, no token needed.",
          "type": "boolean",
          "x-description-zh": "App 签名头模式:请求带签名头即按签名校验,不需要令牌。"
         },
         "bind_ip": {
          "description": "Also bind the token to the client IP (a new IP invalidates it).",
          "type": "boolean",
          "x-description-zh": "令牌再绑客户端 IP(换 IP 即失效)。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never saved, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "methods": {
          "description": "Protected methods; omitted = POST/PUT/PATCH/DELETE.",
          "items": {
           "type": "object",
           "x-gocdn-type": "ReplayGuardMethod"
          },
          "type": "array",
          "x-description-zh": "受保护方法;不写 = POST/PUT/PATCH/DELETE。"
         },
         "paths": {
          "description": "Protected API paths, at most 64; empty = nothing protected.",
          "items": {
           "type": "object",
           "x-gocdn-type": "ReplayGuardPath"
          },
          "type": "array",
          "x-description-zh": "保护接口路径表,最多 64 条;空 = 不保护。"
         },
         "ttl_s": {
          "description": "Token lifetime in seconds, also used for signed-header timestamps; omitted = 120.",
          "type": "integer",
          "x-description-zh": "令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Save the replay protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "保存防重放方案"
   }
  },
  "/api/v2/protect-schemes/tamper": {
   "get": {
    "operationId": "get-protect-schemes-tamper",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get the web tamper protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取防篡改方案"
   },
   "put": {
    "operationId": "put-protect-schemes-tamper",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
          "enum": [
           "block",
           "challenge"
          ],
          "type": "object",
          "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
          "x-gocdn-type": "ReplayGuardAction"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never saved, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "mode": {
          "description": "What counts as tampering: structure = structural changes only; full = any change to the page.",
          "enum": [
           "structure",
           "full"
          ],
          "type": "string",
          "x-description-zh": "检查范围:structure 仅结构变化;full 整页任意变化。"
         },
         "observe_days": {
          "description": "Days a site observes when turned on by the scheme (record only, no action); 0 = act right away.",
          "type": "integer",
          "x-description-zh": "站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。"
         },
         "scopes": {
          "description": "Protected scopes, at most 50.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteTamperScope"
          },
          "type": "array",
          "x-description-zh": "保护范围,最多 50 条。"
         }
        },
        "required": [
         "action",
         "mode",
         "observe_days",
         "scopes"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Save the web tamper protection scheme",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "保存防篡改方案"
   }
  },
  "/api/v2/protect-schemes/{kind}/apply": {
   "post": {
    "operationId": "post-protect-schemes-kind-apply",
    "parameters": [
     {
      "in": "path",
      "name": "kind",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "auto_join": {
          "description": "The rule that sites newly entering the range join the scheme automatically; omitted when off.",
          "readOnly": true,
          "type": "object",
          "x-description-zh": "「以后新加入范围的网站自动加入方案」的规则;没开时不返回。"
         },
         "dry_run": {
          "default": false,
          "description": "When true, only return the counts of what would happen; nothing is written.",
          "type": "boolean",
          "x-description-zh": "为 true 只返回会发生什么的计数,不写任何东西。"
         },
         "override_custom": {
          "default": false,
          "description": "When true, sites with their own settings are switched to the scheme too; by default they are left alone and counted in skipped_custom.",
          "type": "boolean",
          "x-description-zh": "为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。"
         },
         "selection": {
          "description": "The range of sites to apply to.",
          "type": "object",
          "x-description-zh": "要应用的网站范围。",
          "x-gocdn-type": "ProtectSchemeSelection"
         }
        },
        "required": [
         "selection"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Apply the scheme to sites in bulk",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "把方案批量应用到网站"
   }
  },
  "/api/v2/protect-schemes/{kind}/sites": {
   "get": {
    "operationId": "get-protect-schemes-kind-sites",
    "parameters": [
     {
      "in": "path",
      "name": "kind",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Fuzzy search by domain or site name (case-insensitive).",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Fuzzy search by domain or site name (case-insensitive).",
       "type": "string",
       "x-description-zh": "按网站域名或站点名模糊搜索(不区分大小写)。"
      }
     },
     {
      "description": "Filter by status.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Filter by status.",
       "enum": [
        "enabled",
        "disabled",
        "pending",
        "capture_failed"
       ],
       "type": "object",
       "x-description-zh": "按状态过滤。",
       "x-gocdn-type": "ProtectSchemeSiteStatus"
      }
     },
     {
      "description": "Filter by source: scheme = follows the scheme; custom = set for the site alone (including turned off).",
      "in": "query",
      "name": "source",
      "schema": {
       "description": "Filter by source: scheme = follows the scheme; custom = set for the site alone (including turned off).",
       "enum": [
        "scheme",
        "custom"
       ],
       "readOnly": true,
       "type": "object",
       "x-description-zh": "按来源过滤:scheme 按方案;custom 单独设置(含单独关闭)。",
       "x-gocdn-type": "ProtectSiteSource"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List the sites that have this protection set up",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出已设置这项防护的网站"
   }
  },
  "/api/v2/protect-schemes/{kind}/sites/bulk": {
   "post": {
    "operationId": "post-protect-schemes-kind-sites-bulk",
    "parameters": [
     {
      "in": "path",
      "name": "kind",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
          "enum": [
           "block",
           "challenge"
          ],
          "type": "object",
          "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
          "x-gocdn-type": "ReplayGuardAction"
         },
         "filter": {
          "description": "The same filters as the list; expanded to a set of sites by the server.",
          "type": "object",
          "x-description-zh": "与列表同样的过滤条件,服务端展开成网站集合。",
          "x-gocdn-type": "ProtectSchemeSiteFilter"
         },
         "ids": {
          "description": "Site ids.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "网站 id 列表。"
         }
        },
        "required": [
         "action"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Reset or turn off this protection for many sites",
    "tags": [
     "protect-schemes"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量重设或关闭网站的这项防护"
   }
  },
  "/api/v2/regions": {
   "get": {
    "operationId": "get-regions",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List regions",
    "tags": [
     "regions"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出区域"
   },
   "post": {
    "operationId": "post-regions",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create region",
    "tags": [
     "regions"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建区域"
   }
  },
  "/api/v2/regions/{id}": {
   "delete": {
    "operationId": "delete-regions-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete region",
    "tags": [
     "regions"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除区域"
   },
   "get": {
    "operationId": "get-regions-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get region",
    "tags": [
     "regions"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取区域"
   },
   "put": {
    "operationId": "put-regions-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "des": "east"
       },
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update region",
    "tags": [
     "regions"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改区域"
   }
  },
  "/api/v2/registration-info": {
   "get": {
    "operationId": "get-registration-info",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Get registration info",
    "tags": [
     "registration-info"
    ],
    "x-summary-zh": "注册须知"
   }
  },
  "/api/v2/registrations": {
   "post": {
    "operationId": "post-registrations",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "accept_agreement": true,
        "email": "alice@example.com",
        "email_code": "123456",
        "password": "${PASSWORD}",
        "username": "alice"
       },
       "schema": {
        "properties": {
         "accept_agreement": {
          "description": "Must be true",
          "type": "boolean",
          "x-description-zh": "须为 true。"
         },
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "email_code": {
          "description": "Code sent to the email (POST /verify-codes, purpose=bind); required when the email must be verified",
          "type": "string",
          "x-description-zh": "发到该邮箱的验证码(POST /verify-codes,purpose=bind);邮箱要验证时必填。"
         },
         "password": {
          "description": "Login password, 8 to 128 characters",
          "type": "string",
          "x-description-zh": "登录口令,8 到 128 个字符。"
         },
         "phone": {
          "description": "Phone number",
          "type": "string",
          "x-description-zh": "手机号"
         },
         "phone_code": {
          "description": "Code sent to the phone number (POST /verify-codes, purpose=bind); required when the phone number must be verified",
          "type": "string",
          "x-description-zh": "发到该手机号的验证码(POST /verify-codes,purpose=bind);手机号要验证时必填。"
         },
         "username": {
          "description": "Required if registration info demands it, otherwise generated automatically. Must not look like a phone number (all digits)",
          "type": "string",
          "x-description-zh": "须注册须知要求时必填;不填则自动生成。不能像手机号(纯数字)。"
         }
        },
        "required": [
         "accept_agreement",
         "password"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Register",
    "tags": [
     "registrations"
    ],
    "x-summary-zh": "注册"
   }
  },
  "/api/v2/reports/access-log-export-quota": {
   "get": {
    "operationId": "get-reports-access-log-export-quota",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get today's access log download quota",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "查看今天的访问日志下载额度"
   }
  },
  "/api/v2/reports/access-log-exports": {
   "get": {
    "operationId": "get-reports-access-log-exports",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List access log download requests",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "列出访问日志下载申请"
   },
   "post": {
    "operationId": "post-reports-access-log-exports",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Exact match on request Host (case-insensitive).",
      "in": "query",
      "name": "host",
      "schema": {
       "description": "Exact match on request Host (case-insensitive).",
       "type": "string",
       "x-description-zh": "按请求 Host 精确过滤(不分大小写)。"
      }
     },
     {
      "description": "Filter by access port.",
      "in": "query",
      "name": "server_port",
      "schema": {
       "description": "Filter by access port.",
       "type": "integer",
       "x-description-zh": "按接入端口过滤。"
      }
     },
     {
      "description": "Exact match on client address.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Exact match on client address.",
       "type": "string",
       "x-description-zh": "按客户端地址精确过滤。"
      }
     },
     {
      "description": "Filter by request URI prefix (must start with /).",
      "in": "query",
      "name": "uri",
      "schema": {
       "description": "Filter by request URI prefix (must start with /).",
       "type": "string",
       "x-description-zh": "按请求 URI 前缀过滤(须以 / 开头)。"
      }
     },
     {
      "description": "Exact, case-sensitive match on the Referer request header; an empty value (referer=) selects direct visits that sent no Referer.",
      "in": "query",
      "name": "referer",
      "schema": {
       "description": "Exact, case-sensitive match on the Referer request header; an empty value (referer=) selects direct visits that sent no Referer.",
       "type": "string",
       "x-description-zh": "按来源页(Referer 请求头)精确过滤,区分大小写;给空值(referer=)= 只看没带来源的直接访问。"
      }
     },
     {
      "description": "Filter by HTTP protocol version (same spelling as http_ver in the response).",
      "in": "query",
      "name": "http_ver",
      "schema": {
       "description": "Filter by HTTP protocol version (same spelling as http_ver in the response).",
       "enum": [
        "1.0",
        "1.1",
        "2",
        "3"
       ],
       "type": "string",
       "x-description-zh": "按 HTTP 协议版本过滤(与响应的 http_ver 同写法)。"
      }
     },
     {
      "description": "Filter by request method (upper case, such as GET or POST).",
      "in": "query",
      "name": "method",
      "schema": {
       "description": "Filter by request method (upper case, such as GET or POST).",
       "type": "string",
       "x-description-zh": "按请求方法过滤(大写,如 GET、POST)。"
      }
     },
     {
      "description": "Filter by status code.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Filter by status code.",
       "type": "integer",
       "x-description-zh": "按状态码过滤。"
      }
     },
     {
      "description": "Filter by node.",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by node.",
       "type": "integer",
       "x-description-zh": "按节点过滤。"
      }
     },
     {
      "description": "Filter by cache status.",
      "in": "query",
      "name": "cache_status",
      "schema": {
       "description": "Filter by cache status.",
       "enum": [
        "NONE",
        "HIT",
        "MISS",
        "EXPIRED",
        "STALE",
        "UPDATING",
        "REVALIDATED",
        "BYPASS"
       ],
       "type": "string",
       "x-description-zh": "按缓存状态过滤。"
      }
     },
     {
      "description": "Filter by client country (ISO 3166-1 alpha-2, e.g. CN).",
      "in": "query",
      "name": "country",
      "schema": {
       "description": "Filter by client country (ISO 3166-1 alpha-2, e.g. CN).",
       "type": "string",
       "x-description-zh": "按客户端归属国家过滤(ISO 3166-1 两位码,如 CN)。"
      }
     },
     {
      "description": "Filter by client province (first two digits of GB/T 2260, e.g. 44).",
      "in": "query",
      "name": "prov",
      "schema": {
       "description": "Filter by client province (first two digits of GB/T 2260, e.g. 44).",
       "type": "string",
       "x-description-zh": "按客户端归属省份过滤(GB/T 2260 前两位,如 44)。"
      }
     },
     {
      "description": "Filter by client ISP (telecom, unicom, mobile, cbn, edu, cloud, other).",
      "in": "query",
      "name": "isp",
      "schema": {
       "description": "Filter by client ISP (telecom, unicom, mobile, cbn, edu, cloud, other).",
       "type": "string",
       "x-description-zh": "按客户端运营商过滤(telecom、unicom、mobile、cbn、edu、cloud、other)。"
      }
     },
     {
      "description": "true = only blocked requests (action = block).",
      "in": "query",
      "name": "blocked",
      "schema": {
       "description": "true = only blocked requests (action = block).",
       "type": "boolean",
       "x-description-zh": "true = 只看被拦截的请求(action = block)。"
      }
     },
     {
      "description": "Filter by block reason, same meaning as block_reason on a log row: region = blocked by region limit, region_log = region limit log-only hit (not blocked), acl = blocked by ACL, other = blocked by other protection.",
      "in": "query",
      "name": "block_reason",
      "schema": {
       "description": "Filter by block reason, same meaning as block_reason on a log row: region = blocked by region limit, region_log = region limit log-only hit (not blocked), acl = blocked by ACL, other = blocked by other protection.",
       "enum": [
        "region",
        "region_log",
        "acl",
        "other"
       ],
       "type": "string",
       "x-description-zh": "按拦截原因过滤,口径同日志行的 block_reason:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截。"
      }
     },
     {
      "description": "Filter by status class: 1xx / 2xx / 3xx / 4xx / 5xx; error = failed requests (status ≥ 400 and not a blocked request). Intersected with status when both are given.",
      "in": "query",
      "name": "status_class",
      "schema": {
       "description": "Filter by status class: 1xx / 2xx / 3xx / 4xx / 5xx; error = failed requests (status ≥ 400 and not a blocked request). Intersected with status when both are given.",
       "enum": [
        "1xx",
        "2xx",
        "3xx",
        "4xx",
        "5xx",
        "error"
       ],
       "type": "string",
       "x-description-zh": "按状态码类别过滤:1xx / 2xx / 3xx / 4xx / 5xx;error = 出错(状态码 ≥ 400 且不是被拦截的请求)。与 status 同给时取交集。"
      }
     },
     {
      "description": "Only slow requests, i.e. request time (request_time_ms) greater than this many milliseconds.",
      "in": "query",
      "name": "slow_ms",
      "schema": {
       "description": "Only slow requests, i.e. request time (request_time_ms) greater than this many milliseconds.",
       "type": "integer",
       "x-description-zh": "只看慢请求:请求耗时(request_time_ms)大于该毫秒数。"
      }
     },
     {
      "description": "Exclude this cache status (negation of cache_status); the miss count in facets equals cache_status_not=HIT. Intersected with cache_status when both are given.",
      "in": "query",
      "name": "cache_status_not",
      "schema": {
       "description": "Exclude this cache status (negation of cache_status); the miss count in facets equals cache_status_not=HIT. Intersected with cache_status when both are given.",
       "enum": [
        "NONE",
        "HIT",
        "MISS",
        "EXPIRED",
        "STALE",
        "UPDATING",
        "REVALIDATED",
        "BYPASS"
       ],
       "type": "string",
       "x-description-zh": "排除该缓存状态(cache_status 的取反);facets 的 miss 就是 cache_status_not=HIT。与 cache_status 同给时取交集。"
      }
     },
     {
      "description": "Contains search: a hit on any of status code (exactly three digits matches the status; 1xx to 5xx matches the class), client IP (contains), URL (contains) or host (contains, case-insensitive) counts; intersected with the other filters.",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Contains search: a hit on any of status code (exactly three digits matches the status; 1xx to 5xx matches the class), client IP (contains), URL (contains) or host (contains, case-insensitive) counts; intersected with the other filters.",
       "type": "string",
       "x-description-zh": "包含搜索:状态码(恰为 3 位数字时按状态码相等;1xx~5xx 按类别)、客户端 IP(包含)、URL(包含)、域名(包含,不分大小写)任一命中即算;与其他条件取交集。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Request an access log download",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "申请下载访问日志"
   }
  },
  "/api/v2/reports/access-log-exports/{id}": {
   "get": {
    "operationId": "get-reports-access-log-exports-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get an access log download request",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "查看访问日志下载申请"
   }
  },
  "/api/v2/reports/access-log-exports/{id}/file": {
   "get": {
    "operationId": "get-reports-access-log-exports-id-file",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Download the access log file",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "user",
    "x-summary-zh": "下载访问日志文件"
   }
  },
  "/api/v2/reports/access-logs": {
   "get": {
    "operationId": "get-reports-access-logs",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Time cursor; pass back next_cursor of the previous page (same sort and filters). page is ignored when set.",
      "in": "query",
      "name": "cursor",
      "schema": {
       "description": "Time cursor; pass back next_cursor of the previous page (same sort and filters). page is ignored when set.",
       "type": "string",
       "x-description-zh": "时间游标:上一页响应的 next_cursor 原样带回(须同一 sort 与筛选),从那条之后续读;带上时忽略 page。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Exact match on request Host (case-insensitive).",
      "in": "query",
      "name": "host",
      "schema": {
       "description": "Exact match on request Host (case-insensitive).",
       "type": "string",
       "x-description-zh": "按请求 Host 精确过滤(不分大小写)。"
      }
     },
     {
      "description": "Filter by access port.",
      "in": "query",
      "name": "server_port",
      "schema": {
       "description": "Filter by access port.",
       "type": "integer",
       "x-description-zh": "按接入端口过滤。"
      }
     },
     {
      "description": "Exact match on client address.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Exact match on client address.",
       "type": "string",
       "x-description-zh": "按客户端地址精确过滤。"
      }
     },
     {
      "description": "Filter by request URI prefix (must start with /).",
      "in": "query",
      "name": "uri",
      "schema": {
       "description": "Filter by request URI prefix (must start with /).",
       "type": "string",
       "x-description-zh": "按请求 URI 前缀过滤(须以 / 开头)。"
      }
     },
     {
      "description": "Exact, case-sensitive match on the Referer request header; an empty value (referer=) selects direct visits that sent no Referer.",
      "in": "query",
      "name": "referer",
      "schema": {
       "description": "Exact, case-sensitive match on the Referer request header; an empty value (referer=) selects direct visits that sent no Referer.",
       "type": "string",
       "x-description-zh": "按来源页(Referer 请求头)精确过滤,区分大小写;给空值(referer=)= 只看没带来源的直接访问。"
      }
     },
     {
      "description": "Filter by HTTP protocol version (same spelling as http_ver in the response).",
      "in": "query",
      "name": "http_ver",
      "schema": {
       "description": "Filter by HTTP protocol version (same spelling as http_ver in the response).",
       "enum": [
        "1.0",
        "1.1",
        "2",
        "3"
       ],
       "type": "string",
       "x-description-zh": "按 HTTP 协议版本过滤(与响应的 http_ver 同写法)。"
      }
     },
     {
      "description": "Filter by request method (upper case, such as GET or POST).",
      "in": "query",
      "name": "method",
      "schema": {
       "description": "Filter by request method (upper case, such as GET or POST).",
       "type": "string",
       "x-description-zh": "按请求方法过滤(大写,如 GET、POST)。"
      }
     },
     {
      "description": "Filter by status code.",
      "in": "query",
      "name": "status",
      "schema": {
       "description": "Filter by status code.",
       "type": "integer",
       "x-description-zh": "按状态码过滤。"
      }
     },
     {
      "description": "Filter by node.",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by node.",
       "type": "integer",
       "x-description-zh": "按节点过滤。"
      }
     },
     {
      "description": "Filter by cache status.",
      "in": "query",
      "name": "cache_status",
      "schema": {
       "description": "Filter by cache status.",
       "enum": [
        "NONE",
        "HIT",
        "MISS",
        "EXPIRED",
        "STALE",
        "UPDATING",
        "REVALIDATED",
        "BYPASS"
       ],
       "type": "string",
       "x-description-zh": "按缓存状态过滤。"
      }
     },
     {
      "description": "Filter by client country (ISO 3166-1 alpha-2, e.g. CN).",
      "in": "query",
      "name": "country",
      "schema": {
       "description": "Filter by client country (ISO 3166-1 alpha-2, e.g. CN).",
       "type": "string",
       "x-description-zh": "按客户端归属国家过滤(ISO 3166-1 两位码,如 CN)。"
      }
     },
     {
      "description": "Filter by client province (first two digits of GB/T 2260, e.g. 44).",
      "in": "query",
      "name": "prov",
      "schema": {
       "description": "Filter by client province (first two digits of GB/T 2260, e.g. 44).",
       "type": "string",
       "x-description-zh": "按客户端归属省份过滤(GB/T 2260 前两位,如 44)。"
      }
     },
     {
      "description": "Filter by client ISP (telecom, unicom, mobile, cbn, edu, cloud, other).",
      "in": "query",
      "name": "isp",
      "schema": {
       "description": "Filter by client ISP (telecom, unicom, mobile, cbn, edu, cloud, other).",
       "type": "string",
       "x-description-zh": "按客户端运营商过滤(telecom、unicom、mobile、cbn、edu、cloud、other)。"
      }
     },
     {
      "description": "true = only blocked requests (action = block).",
      "in": "query",
      "name": "blocked",
      "schema": {
       "description": "true = only blocked requests (action = block).",
       "type": "boolean",
       "x-description-zh": "true = 只看被拦截的请求(action = block)。"
      }
     },
     {
      "description": "Filter by block reason, same meaning as block_reason on a log row: region = blocked by region limit, region_log = region limit log-only hit (not blocked), acl = blocked by ACL, other = blocked by other protection.",
      "in": "query",
      "name": "block_reason",
      "schema": {
       "description": "Filter by block reason, same meaning as block_reason on a log row: region = blocked by region limit, region_log = region limit log-only hit (not blocked), acl = blocked by ACL, other = blocked by other protection.",
       "enum": [
        "region",
        "region_log",
        "acl",
        "other"
       ],
       "type": "string",
       "x-description-zh": "按拦截原因过滤,口径同日志行的 block_reason:region = 地区限制拦截、region_log = 地区限制只记录(未拦)、acl = ACL 拦截、other = 其他防护拦截。"
      }
     },
     {
      "description": "Filter by status class: 1xx / 2xx / 3xx / 4xx / 5xx; error = failed requests (status ≥ 400 and not a blocked request). Intersected with status when both are given.",
      "in": "query",
      "name": "status_class",
      "schema": {
       "description": "Filter by status class: 1xx / 2xx / 3xx / 4xx / 5xx; error = failed requests (status ≥ 400 and not a blocked request). Intersected with status when both are given.",
       "enum": [
        "1xx",
        "2xx",
        "3xx",
        "4xx",
        "5xx",
        "error"
       ],
       "type": "string",
       "x-description-zh": "按状态码类别过滤:1xx / 2xx / 3xx / 4xx / 5xx;error = 出错(状态码 ≥ 400 且不是被拦截的请求)。与 status 同给时取交集。"
      }
     },
     {
      "description": "Only slow requests, i.e. request time (request_time_ms) greater than this many milliseconds.",
      "in": "query",
      "name": "slow_ms",
      "schema": {
       "description": "Only slow requests, i.e. request time (request_time_ms) greater than this many milliseconds.",
       "type": "integer",
       "x-description-zh": "只看慢请求:请求耗时(request_time_ms)大于该毫秒数。"
      }
     },
     {
      "description": "Exclude this cache status (negation of cache_status); the miss count in facets equals cache_status_not=HIT. Intersected with cache_status when both are given.",
      "in": "query",
      "name": "cache_status_not",
      "schema": {
       "description": "Exclude this cache status (negation of cache_status); the miss count in facets equals cache_status_not=HIT. Intersected with cache_status when both are given.",
       "enum": [
        "NONE",
        "HIT",
        "MISS",
        "EXPIRED",
        "STALE",
        "UPDATING",
        "REVALIDATED",
        "BYPASS"
       ],
       "type": "string",
       "x-description-zh": "排除该缓存状态(cache_status 的取反);facets 的 miss 就是 cache_status_not=HIT。与 cache_status 同给时取交集。"
      }
     },
     {
      "description": "Contains search: a hit on any of status code (exactly three digits matches the status; 1xx to 5xx matches the class), client IP (contains), URL (contains) or host (contains, case-insensitive) counts; intersected with the other filters.",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Contains search: a hit on any of status code (exactly three digits matches the status; 1xx to 5xx matches the class), client IP (contains), URL (contains) or host (contains, case-insensitive) counts; intersected with the other filters.",
       "type": "string",
       "x-description-zh": "包含搜索:状态码(恰为 3 位数字时按状态码相等;1xx~5xx 按类别)、客户端 IP(包含)、URL(包含)、域名(包含,不分大小写)任一命中即算;与其他条件取交集。"
      }
     },
     {
      "description": "true / 1 = include facets (counts for each quick filter) in the response. Counted under all filters except the quick ones (status_class, slow_ms, cache_status_not, blocked, block_reason), so they do not move with the quick filter.",
      "in": "query",
      "name": "facets",
      "schema": {
       "description": "true / 1 = include facets (counts for each quick filter) in the response. Counted under all filters except the quick ones (status_class, slow_ms, cache_status_not, blocked, block_reason), so they do not move with the quick filter.",
       "type": "boolean",
       "x-description-zh": "true / 1 = 响应带 facets(快捷筛选各项的条数)。条数在除快捷筛选(status_class、slow_ms、cache_status_not、blocked、block_reason)外的其余条件下统计,不受快捷筛选影响。"
      }
     },
     {
      "description": "false / 0 = skip counting the total (the response omits total, saving one full count); defaults to true.",
      "in": "query",
      "name": "total",
      "schema": {
       "description": "false / 0 = skip counting the total (the response omits total, saving one full count); defaults to true.",
       "type": "boolean",
       "x-description-zh": "false / 0 = 不统计总条数(响应不带 total,省一次全表计数);缺省 true。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List access logs",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出访问日志"
   }
  },
  "/api/v2/reports/checkup": {
   "get": {
    "operationId": "get-reports-checkup",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Search by site name or domain (substring match).",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Search by site name or domain (substring match).",
       "type": "string",
       "x-description-zh": "按网站名称或域名搜索(包含匹配)。"
      }
     },
     {
      "description": "Sort: score ascending (worst first, default) or name.",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort: score ascending (worst first, default) or name.",
       "enum": [
        "score",
        "name"
       ],
       "type": "string",
       "x-description-zh": "排序:score 按得分升序(最差在前,缺省),name 按名称。"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site checkup overview",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "网站体检总览"
   }
  },
  "/api/v2/reports/checkup/history": {
   "get": {
    "operationId": "get-reports-checkup-history",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Checkup score history",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "体检历史得分"
   }
  },
  "/api/v2/reports/checkup/ignores": {
   "get": {
    "operationId": "get-reports-checkup-ignores",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Checkup ignores",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "体检忽略项"
   }
  },
  "/api/v2/reports/checkup/ignores/batch": {
   "post": {
    "operationId": "post-reports-checkup-ignores-batch",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "keys": {
          "description": "Check keys.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "检查项键。"
         },
         "op": {
          "description": "add puts keys on the ignore list (existing ones are untouched); remove takes them off.",
          "enum": [
           "add",
           "remove"
          ],
          "type": "string",
          "x-description-zh": "add 补上 keys(已有的不动);remove 去掉 keys。"
         },
         "site_ids": {
          "description": "Sites to process, at most 500.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要处理的网站,最多 500 个。"
         }
        },
        "required": [
         "keys",
         "op",
         "site_ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Add or remove checkup ignores in bulk",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量增减体检忽略项"
   }
  },
  "/api/v2/reports/checkup/issues": {
   "get": {
    "operationId": "get-reports-checkup-issues",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Search by site name or domain (substring match); only matching sites are counted.",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Search by site name or domain (substring match); only matching sites are counted.",
       "type": "string",
       "x-description-zh": "按网站名称或域名搜索(包含匹配),汇总只算匹配的网站。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Checkup problems grouped by check",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "体检问题汇总"
   }
  },
  "/api/v2/reports/checkup/issues/{key}/sites": {
   "get": {
    "operationId": "get-reports-checkup-issues-key-sites",
    "parameters": [
     {
      "in": "path",
      "name": "key",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Search by site name or domain (substring match).",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Search by site name or domain (substring match).",
       "type": "string",
       "x-description-zh": "按网站名称或域名搜索(包含匹配)。"
      }
     },
     {
      "description": "Sort order: score is lowest checkup score first (default); attacks is most attacks in the last 7 days first (WAF and default-CC problems carry the count, other checks count as 0; ties fall back to score).",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort order: score is lowest checkup score first (default); attacks is most attacks in the last 7 days first (WAF and default-CC problems carry the count, other checks count as 0; ties fall back to score).",
       "enum": [
        "score",
        "attacks"
       ],
       "type": "string",
       "x-description-zh": "排序:score 体检得分从低到高(缺省);attacks 近 7 天攻击数从多到少(WAF 类与 CC 默认档的问题带这个数,其余检查项都按 0,同数再按得分)。"
      }
     },
     {
      "description": "rec_type only - filter by site type; undecided lists sites whose type could not be determined (the checkup only noted them and did not count them as problems; this is the only place they are listed). 422 when key is not rec_type.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "rec_type only - filter by site type; undecided lists sites whose type could not be determined (the checkup only noted them and did not count them as problems; this is the only place they are listed). 422 when key is not rec_type.",
       "enum": [
        "corporate",
        "shop",
        "content",
        "api",
        "admin",
        "download",
        "undecided"
       ],
       "type": "string",
       "x-description-zh": "只用于 rec_type:按网站类型筛选;undecided 是判不出类型的网站(体检只给了说明、不算问题,只能在这里列出)。key 不是 rec_type 时给了 422。"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Sites affected by a checkup problem",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "受某类体检问题影响的网站"
   }
  },
  "/api/v2/reports/checkup/recheck": {
   "post": {
    "operationId": "post-reports-checkup-recheck",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "site_ids": {
          "description": "Sites to process, at most 500.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要处理的网站,最多 500 个。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Run the checkup again",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "重新体检"
   }
  },
  "/api/v2/reports/checkup/runs/active": {
   "get": {
    "operationId": "get-reports-checkup-runs-active",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "The checkup batch in progress",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "进行中的体检批次"
   }
  },
  "/api/v2/reports/checkup/runs/{id}": {
   "get": {
    "operationId": "get-reports-checkup-runs-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Checkup batch progress",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "体检批次进度"
   }
  },
  "/api/v2/reports/checkup/settings": {
   "get": {
    "operationId": "get-reports-checkup-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get checkup settings",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "读体检设置"
   },
   "put": {
    "operationId": "put-reports-checkup-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "frequency": {
          "description": "Frequency: daily at 03:00, weekly on Monday at 03:00, or manual only.",
          "enum": [
           "daily",
           "weekly",
           "manual"
          ],
          "type": "string",
          "x-description-zh": "检查频率:每天 03:00、每周一 03:00、仅手动。"
         },
         "notify_critical": {
          "description": "Raise an alert when a critical problem appears (uses the channels in alert settings).",
          "type": "boolean",
          "x-description-zh": "出现严重问题时告警(用告警设置里的渠道)。"
         }
        },
        "required": [
         "frequency",
         "notify_critical"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Save checkup settings",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "保存体检设置"
   }
  },
  "/api/v2/reports/checkup/sites/{id}": {
   "get": {
    "operationId": "get-reports-checkup-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site checkup report",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "网站体检报告"
   }
  },
  "/api/v2/reports/checkup/sites/{id}/app": {
   "put": {
    "operationId": "put-reports-checkup-sites-id-app",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "name": {
          "description": "Site name.",
          "type": "string",
          "x-description-zh": "网站名称。"
         },
         "reset": {
          "description": "true clears the override and returns to automatic detection (name and version are ignored).",
          "type": "boolean",
          "x-description-zh": "true = 撤销人工改写、回到自动识别(此时忽略 name 与 version)。"
         },
         "version": {
          "description": "Application version; may be left empty.",
          "type": "string",
          "x-description-zh": "程序版本;不知道可留空。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Override a site's detected application",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "改写网站识别到的程序"
   }
  },
  "/api/v2/reports/checkup/sites/{id}/ignores": {
   "put": {
    "operationId": "put-reports-checkup-sites-id-ignores",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "keys": {
          "description": "Check keys.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "检查项键。"
         }
        },
        "required": [
         "keys"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set a site's checkup ignores",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置网站的体检忽略项"
   }
  },
  "/api/v2/reports/host-not-found/top": {
   "get": {
    "operationId": "get-reports-host-not-found-top",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only entries reported by this node.",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Only entries reported by this node.",
       "type": "integer",
       "x-description-zh": "只看这个节点上报的。"
      }
     },
     {
      "description": "Filter by host substring (case-insensitive, literal match).",
      "in": "query",
      "name": "domain",
      "schema": {
       "description": "Filter by host substring (case-insensitive, literal match).",
       "type": "string",
       "x-description-zh": "按 host 子串过滤(不分大小写,字面匹配)。"
      }
     },
     {
      "description": "Only this kind (kinds are judged by the master, not stored; the top 500 domains by count are judged and filtered before paging, total counts the filtered rows).",
      "in": "query",
      "name": "kind",
      "schema": {
       "description": "Only this kind (kinds are judged by the master, not stored; the top 500 domains by count are judged and filtered before paging, total counts the filtered rows).",
       "enum": [
        "site",
        "pointed_here",
        "not_pointed",
        "typo",
        "scanner",
        "unknown"
       ],
       "type": "object",
       "x-description-zh": "只看这一类(类型由主控判定、不在库里:先取次数最高的 500 个域名判定、按类型过滤后再分页,total 为过滤后行数)。",
       "x-gocdn-type": "HostNotFoundKind"
      }
     },
     {
      "description": "Sort direction by count, default desc.",
      "in": "query",
      "name": "order",
      "schema": {
       "description": "Sort direction by count, default desc.",
       "enum": [
        "desc",
        "asc"
       ],
       "type": "string",
       "x-description-zh": "按次数排序方向,缺省 desc。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Unconfigured domain Top",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "未配置域名 Top"
   }
  },
  "/api/v2/reports/ip-seen": {
   "get": {
    "operationId": "get-reports-ip-seen",
    "parameters": [
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Client address to look up (IPv4 or IPv6).",
      "in": "query",
      "name": "ip",
      "required": true,
      "schema": {
       "description": "Client address to look up (IPv4 or IPv6).",
       "type": "string",
       "x-description-zh": "要查的客户端地址(IPv4 或 IPv6)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "First and last time a visitor IP was seen",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "访客 IP 的首次与最近出现"
   }
  },
  "/api/v2/reports/nodes/realtime": {
   "get": {
    "operationId": "get-reports-nodes-realtime",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Node. A sub-IP id returns the curves of the main node it belongs to (metrics are collected per main node).",
      "in": "query",
      "name": "node_id",
      "required": true,
      "schema": {
       "description": "Node. A sub-IP id returns the curves of the main node it belongs to (metrics are collected per main node).",
       "type": "integer",
       "x-description-zh": "节点。给子 IP 的 id 时取它所属主节点的曲线(指标按主节点采集)。"
      }
     },
     {
      "description": "Node metric (same as node_metrics.metric). tls_hs_reject is the number of TLS handshakes rejected by handshake-flood protection; worker_drain_killed is the number of draining old nginx workers force-terminated (SIGTERM).",
      "in": "query",
      "name": "metric",
      "required": true,
      "schema": {
       "description": "Node metric (same as node_metrics.metric). tls_hs_reject is the number of TLS handshakes rejected by handshake-flood protection; worker_drain_killed is the number of draining old nginx workers force-terminated (SIGTERM).",
       "enum": [
        "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"
       ],
       "type": "string",
       "x-description-zh": "节点指标(同 node_metrics.metric)。tls_hs_reject 为握手洪水防御拦掉的 TLS 握手数;worker_drain_killed 为被强关(SIGTERM)的排空中旧 nginx worker 数。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node real-time curves",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点实时曲线"
   }
  },
  "/api/v2/reports/nodes/realtime-batch": {
   "get": {
    "operationId": "get-reports-nodes-realtime-batch",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Node. A sub-IP id returns the curves of the main node it belongs to (metrics are collected per main node).",
      "in": "query",
      "name": "node_id",
      "required": true,
      "schema": {
       "description": "Node. A sub-IP id returns the curves of the main node it belongs to (metrics are collected per main node).",
       "type": "integer",
       "x-description-zh": "节点。给子 IP 的 id 时取它所属主节点的曲线(指标按主节点采集)。"
      }
     },
     {
      "description": "Node metrics, comma-separated.",
      "in": "query",
      "name": "metrics",
      "required": true,
      "schema": {
       "description": "Node metrics, comma-separated.",
       "type": "string",
       "x-description-zh": "节点指标列表,逗号分隔。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node real-time curves (several metrics in one call)",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点实时曲线(多指标一次取)"
   }
  },
  "/api/v2/reports/nodes/summary": {
   "get": {
    "operationId": "get-reports-nodes-summary",
    "parameters": [
     {
      "description": "Averaging window in minutes; 5 by default.",
      "in": "query",
      "name": "window",
      "schema": {
       "description": "Averaging window in minutes; 5 by default.",
       "enum": [
        1,
        5,
        30,
        60
       ],
       "type": "integer",
       "x-description-zh": "取均值的窗口(分钟),缺省 5。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node ranking table",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点排行总表"
   }
  },
  "/api/v2/reports/nodes/top": {
   "get": {
    "operationId": "get-reports-nodes-top",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Node metric (same as node_metrics.metric). tls_hs_reject is the number of TLS handshakes rejected by handshake-flood protection; worker_drain_killed is the number of draining old nginx workers force-terminated (SIGTERM).",
      "in": "query",
      "name": "metric",
      "required": true,
      "schema": {
       "description": "Node metric (same as node_metrics.metric). tls_hs_reject is the number of TLS handshakes rejected by handshake-flood protection; worker_drain_killed is the number of draining old nginx workers force-terminated (SIGTERM).",
       "enum": [
        "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"
       ],
       "type": "string",
       "x-description-zh": "节点指标(同 node_metrics.metric)。tls_hs_reject 为握手洪水防御拦掉的 TLS 握手数;worker_drain_killed 为被强关(SIGTERM)的排空中旧 nginx worker 数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node ranking",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点排行"
   }
  },
  "/api/v2/reports/nodes/visitor-rtt": {
   "get": {
    "operationId": "get-reports-nodes-visitor-rtt",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Visitor round-trip time by node",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "节点访客时延"
   }
  },
  "/api/v2/reports/security/overview": {
   "get": {
    "operationId": "get-reports-security-overview",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Security overview",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "安全总览"
   }
  },
  "/api/v2/reports/security/screen": {
   "get": {
    "operationId": "get-reports-security-screen",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Security big-screen aggregate",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "安全大屏聚合"
   }
  },
  "/api/v2/reports/sites/geo": {
   "get": {
    "operationId": "get-reports-sites-geo",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Exact match on client address.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Exact match on client address.",
       "type": "string",
       "x-description-zh": "按客户端地址精确过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Visitor location statistics",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "访问归属地统计"
   }
  },
  "/api/v2/reports/sites/overview": {
   "get": {
    "operationId": "get-reports-sites-overview",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     },
     {
      "description": "Admin only: also include unconfigured traffic (site_id = 0).",
      "in": "query",
      "name": "include_noconfig",
      "schema": {
       "description": "Admin only: also include unconfigured traffic (site_id = 0).",
       "type": "boolean",
       "x-description-zh": "仅管理员:把未配置流量(site_id = 0)也算上。"
      }
     },
     {
      "description": "prev = also return the previous period of the same length (the compare field); omitted by default.",
      "in": "query",
      "name": "compare",
      "schema": {
       "description": "prev = also return the previous period of the same length (the compare field); omitted by default.",
       "enum": [
        "prev"
       ],
       "type": "string",
       "x-description-zh": "prev = 同时返回上一周期同长度的点列与合计(compare 字段);缺省不返回。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site traffic overview",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点流量概览"
   }
  },
  "/api/v2/reports/sites/protocol-config": {
   "get": {
    "operationId": "get-reports-sites-protocol-config",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site protocol configuration distribution",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点协议配置分布"
   }
  },
  "/api/v2/reports/sites/realtime": {
   "get": {
    "operationId": "get-reports-sites-realtime",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Metric.",
      "in": "query",
      "name": "metric",
      "required": true,
      "schema": {
       "description": "Metric.",
       "enum": [
        "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"
       ],
       "type": "string",
       "x-description-zh": "指标。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     },
     {
      "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
      "in": "query",
      "name": "include_noconfig",
      "schema": {
       "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
       "type": "boolean",
       "x-description-zh": "仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site real-time curves",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点实时曲线"
   }
  },
  "/api/v2/reports/sites/realtime-batch": {
   "get": {
    "operationId": "get-reports-sites-realtime-batch",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Metrics, comma-separated.",
      "in": "query",
      "name": "metrics",
      "required": true,
      "schema": {
       "description": "Metrics, comma-separated.",
       "type": "string",
       "x-description-zh": "指标列表,逗号分隔。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     },
     {
      "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
      "in": "query",
      "name": "include_noconfig",
      "schema": {
       "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
       "type": "boolean",
       "x-description-zh": "仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site real-time curves (several metrics in one call)",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点实时曲线(多指标一次取)"
   }
  },
  "/api/v2/reports/sites/top": {
   "get": {
    "operationId": "get-reports-sites-top",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Ranking dimension; use either dim or dims.",
      "in": "query",
      "name": "dim",
      "schema": {
       "description": "Ranking dimension; use either dim or dims.",
       "enum": [
        "ip",
        "prefix",
        "url",
        "referer",
        "site",
        "status",
        "http_ver",
        "scheme",
        "cache_status",
        "ctype",
        "country",
        "prov",
        "isp",
        "port",
        "block_reason"
       ],
       "type": "string",
       "x-description-zh": "排行维度;与 dims 二选一。"
      }
     },
     {
      "description": "Fetch the top limit rows of several dimensions at once, comma-separated dimension names (values as for dim, at most 12); use either dim or dims.",
      "in": "query",
      "name": "dims",
      "schema": {
       "description": "Fetch the top limit rows of several dimensions at once, comma-separated dimension names (values as for dim, at most 12); use either dim or dims.",
       "type": "string",
       "x-description-zh": "一次取多个维度的前 limit 名,逗号分隔的维度名(取值同 dim,至多 12 个);与 dim 二选一。"
      }
     },
     {
      "description": "Rows per dimension; defaults to and capped by the reports.top_size system setting.",
      "in": "query",
      "name": "limit",
      "schema": {
       "description": "Rows per dimension; defaults to and capped by the reports.top_size system setting.",
       "type": "integer",
       "x-description-zh": "每个维度取前几名,缺省与上限为系统配置 reports.top_size。"
      }
     },
     {
      "description": "Which item to sort by and use as value, default count.",
      "in": "query",
      "name": "metric",
      "schema": {
       "description": "Which item to sort by and use as value, default count.",
       "enum": [
        "count",
        "bytes"
       ],
       "type": "string",
       "x-description-zh": "排序与 value 取哪一项,缺省 count。"
      }
     },
     {
      "description": "Only count requests with this action (pass = allowed, challenge = challenged, block = blocked).",
      "in": "query",
      "name": "action",
      "schema": {
       "description": "Only count requests with this action (pass = allowed, challenge = challenged, block = blocked).",
       "enum": [
        "pass",
        "challenge",
        "block"
       ],
       "type": "string",
       "x-description-zh": "只算该处置动作的请求(pass 放行、challenge 质询、block 拦截)。"
      }
     },
     {
      "description": "Only count requests to this listening port; not supported for the prefix dimension (422).",
      "in": "query",
      "name": "server_port",
      "schema": {
       "description": "Only count requests to this listening port; not supported for the prefix dimension (422).",
       "type": "integer",
       "x-description-zh": "只算该监听端口的请求;prefix 维度不支持(422)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site ranking",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点排行"
   }
  },
  "/api/v2/reports/streams/realtime": {
   "get": {
    "operationId": "get-reports-streams-realtime",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by stream listen port.",
      "in": "query",
      "name": "port",
      "schema": {
       "description": "Filter by stream listen port.",
       "type": "integer",
       "x-description-zh": "按四层监听端口过滤。"
      }
     },
     {
      "description": "Metric.",
      "in": "query",
      "name": "metric",
      "required": true,
      "schema": {
       "description": "Metric.",
       "enum": [
        "bandwidth",
        "bandwidth_in",
        "traffic",
        "traffic_in",
        "req",
        "conn_peak"
       ],
       "type": "string",
       "x-description-zh": "指标。"
      }
     },
     {
      "description": "Bucket width; chosen automatically from the time span by default.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "Bucket width; chosen automatically from the time span by default.",
       "enum": [
        "1m",
        "2m",
        "5m",
        "10m",
        "30m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "桶宽;缺省按时间跨度自动取。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "TCP/UDP forwarding real-time curves",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "四层转发实时曲线"
   }
  },
  "/api/v2/reports/streams/top": {
   "get": {
    "operationId": "get-reports-streams-top",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Ranking dimension, default port.",
      "in": "query",
      "name": "dim",
      "schema": {
       "description": "Ranking dimension, default port.",
       "enum": [
        "port",
        "ip"
       ],
       "type": "string",
       "x-description-zh": "排行维度,缺省 port。"
      }
     },
     {
      "description": "Which item to sort by and use as value, default count.",
      "in": "query",
      "name": "metric",
      "schema": {
       "description": "Which item to sort by and use as value, default count.",
       "enum": [
        "count",
        "bytes"
       ],
       "type": "string",
       "x-description-zh": "排序与 value 取哪一项,缺省 count。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "TCP/UDP forwarding ranking",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "四层转发排行"
   }
  },
  "/api/v2/reports/tmp-whitelist": {
   "get": {
    "operationId": "get-reports-tmp-whitelist",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Exact match on client address (IPv6 as /64 prefix address).",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Exact match on client address (IPv6 as /64 prefix address).",
       "type": "string",
       "x-description-zh": "按客户端地址精确过滤(IPv6 为 /64 前缀地址)。"
      }
     },
     {
      "description": "true = only entries not yet expired.",
      "in": "query",
      "name": "active",
      "schema": {
       "description": "true = only entries not yet expired.",
       "type": "boolean",
       "x-description-zh": "true = 只看未到期的。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List node temporary whitelist records",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出节点临时白名单记录"
   }
  },
  "/api/v2/reports/usage": {
   "get": {
    "operationId": "get-reports-usage",
    "parameters": [
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     },
     {
      "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
      "in": "query",
      "name": "site_ids",
      "schema": {
       "description": "Only these sites: comma-separated positive integers, at most 200 after deduplication (more returns 422); for more than 200 sites send a filter (group_id / upid / tenant_ids) instead. Intersected with group_id, upid and tenant_ids; sites a tenant cannot see have no data.",
       "type": "string",
       "x-description-zh": "只看这些站点:逗号分隔的正整数,去重后至多 200 个(超了 422);超过 200 个站点时改传 group_id / upid / tenant_ids 等筛选条件。与 group_id、upid、tenant_ids 取交集;租户看不到的站点没有数据。"
      }
     },
     {
      "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only sites in this site group (expanded to a site set on the server and intersected with the other scope filters; a tenant only expands its own sites).",
       "type": "integer",
       "x-description-zh": "只看该站点分组里的站点(服务端展开成站点集合,与其他范围条件取交集;租户只展开自己的站点)。"
      }
     },
     {
      "description": "Only sites under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only sites under this user package.",
       "type": "integer",
       "x-description-zh": "只看该用户套餐下的站点。"
      }
     },
     {
      "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
      "in": "query",
      "name": "tenant_ids",
      "schema": {
       "description": "Admin only: only these tenants, comma-separated positive integers, at most 200 after deduplication (more returns 422); tenant credentials sending it get 403.",
       "type": "string",
       "x-description-zh": "仅管理员:只看这些租户,逗号分隔的正整数,去重后至多 200 个(超了 422);租户凭据带它回 403。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "site (default) = sites; stream = TCP/UDP forwarding.",
      "in": "query",
      "name": "kind",
      "schema": {
       "description": "site (default) = sites; stream = TCP/UDP forwarding.",
       "enum": [
        "site",
        "stream"
       ],
       "type": "string",
       "x-description-zh": "site(缺省)= 站点;stream = 四层转发。"
      }
     },
     {
      "description": "Metric.",
      "in": "query",
      "name": "metric",
      "required": true,
      "schema": {
       "description": "Metric.",
       "enum": [
        "bandwidth",
        "traffic",
        "req",
        "qps",
        "req_hit_ratio",
        "status_5xx_ratio",
        "status_4xx_ratio",
        "backend_bandwidth",
        "backend_traffic",
        "backend_resp_time",
        "blocked"
       ],
       "type": "string",
       "x-description-zh": "指标。"
      }
     },
     {
      "description": "auto (default), 5m or 1h.",
      "in": "query",
      "name": "interval",
      "schema": {
       "description": "auto (default), 5m or 1h.",
       "enum": [
        "auto",
        "5m",
        "1h"
       ],
       "type": "string",
       "x-description-zh": "auto(缺省)、5m 或 1h。"
      }
     },
     {
      "description": "Filter by stream listen port.",
      "in": "query",
      "name": "port",
      "schema": {
       "description": "Filter by stream listen port.",
       "type": "integer",
       "x-description-zh": "按四层监听端口过滤。"
      }
     },
     {
      "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
      "in": "query",
      "name": "include_noconfig",
      "schema": {
       "description": "Admin only: when no site scope (site_ids / group_id) is given, also include unconfigured traffic (site_id = 0).",
       "type": "boolean",
       "x-description-zh": "仅管理员:不带站点范围(site_ids / group_id) 时把未配置流量(site_id = 0)也算上。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Usage curves",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "用量曲线"
   }
  },
  "/api/v2/reports/waf-events": {
   "get": {
    "operationId": "get-reports-waf-events",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339; no lower bound when omitted (events are kept for 7 days).",
      "in": "query",
      "name": "start",
      "schema": {
       "description": "Start time (inclusive), RFC 3339; no lower bound when omitted (events are kept for 7 days).",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339;缺省不限(事件只保留 7 天)。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339; no upper bound when omitted.",
      "in": "query",
      "name": "end",
      "schema": {
       "description": "End time (exclusive), RFC 3339; no upper bound when omitted.",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339;缺省不限。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
       "type": "string",
       "x-description-zh": "按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。"
      }
     },
     {
      "description": "URL contains (case-sensitive substring of the masked path and query string).",
      "in": "query",
      "name": "url",
      "schema": {
       "description": "URL contains (case-sensitive substring of the masked path and query string).",
       "type": "string",
       "x-description-zh": "URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。"
      }
     },
     {
      "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
      "in": "query",
      "name": "ja4",
      "schema": {
       "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
       "type": "string",
       "x-description-zh": "按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。"
      }
     },
     {
      "description": "Filter by the matched rule id.",
      "in": "query",
      "name": "rule_id",
      "schema": {
       "description": "Filter by the matched rule id.",
       "type": "integer",
       "x-description-zh": "按命中规则号过滤。"
      }
     },
     {
      "description": "Filter by action: block, log, challenge, mask or replace.",
      "in": "query",
      "name": "action",
      "schema": {
       "description": "Filter by action: block, log, challenge, mask or replace.",
       "enum": [
        "block",
        "log",
        "challenge",
        "mask",
        "replace"
       ],
       "type": "string",
       "x-description-zh": "按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。"
      }
     },
     {
      "description": "Filter by event type; repeat to select several, omit for all.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by event type; repeat to select several, omit for all.",
       "items": {
        "type": "string"
       },
       "type": "array",
       "x-description-zh": "按事件类型过滤,可重复多选,不给 = 全部。"
      }
     },
     {
      "description": "Filter by country name as recorded by the node geo database (exact match).",
      "in": "query",
      "name": "country",
      "schema": {
       "description": "Filter by country name as recorded by the node geo database (exact match).",
       "type": "string",
       "x-description-zh": "按国家过滤(节点归属地库给的名称,精确匹配)。"
      }
     },
     {
      "description": "Filter by province (exact match).",
      "in": "query",
      "name": "province",
      "schema": {
       "description": "Filter by province (exact match).",
       "type": "string",
       "x-description-zh": "按省份过滤(精确匹配)。"
      }
     },
     {
      "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
       "type": "integer",
       "x-description-zh": "按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。"
      }
     },
     {
      "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
      "in": "query",
      "name": "observe",
      "schema": {
       "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
       "type": "boolean",
       "x-description-zh": "true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。"
      }
     },
     {
      "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
      "in": "query",
      "name": "blocked",
      "schema": {
       "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
       "type": "boolean",
       "x-description-zh": "true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。"
      }
     },
     {
      "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
      "in": "query",
      "name": "disposition",
      "schema": {
       "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
       "enum": [
        "other"
       ],
       "type": "string",
       "x-description-zh": "other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List WAF events",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出 WAF 事件"
   }
  },
  "/api/v2/reports/waf-events/export": {
   "get": {
    "operationId": "get-reports-waf-events-export",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339; no lower bound when omitted (events are kept for 7 days).",
      "in": "query",
      "name": "start",
      "schema": {
       "description": "Start time (inclusive), RFC 3339; no lower bound when omitted (events are kept for 7 days).",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339;缺省不限(事件只保留 7 天)。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339; no upper bound when omitted.",
      "in": "query",
      "name": "end",
      "schema": {
       "description": "End time (exclusive), RFC 3339; no upper bound when omitted.",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339;缺省不限。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
       "type": "string",
       "x-description-zh": "按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。"
      }
     },
     {
      "description": "URL contains (case-sensitive substring of the masked path and query string).",
      "in": "query",
      "name": "url",
      "schema": {
       "description": "URL contains (case-sensitive substring of the masked path and query string).",
       "type": "string",
       "x-description-zh": "URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。"
      }
     },
     {
      "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
      "in": "query",
      "name": "ja4",
      "schema": {
       "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
       "type": "string",
       "x-description-zh": "按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。"
      }
     },
     {
      "description": "Filter by the matched rule id.",
      "in": "query",
      "name": "rule_id",
      "schema": {
       "description": "Filter by the matched rule id.",
       "type": "integer",
       "x-description-zh": "按命中规则号过滤。"
      }
     },
     {
      "description": "Filter by action: block, log, challenge, mask or replace.",
      "in": "query",
      "name": "action",
      "schema": {
       "description": "Filter by action: block, log, challenge, mask or replace.",
       "enum": [
        "block",
        "log",
        "challenge",
        "mask",
        "replace"
       ],
       "type": "string",
       "x-description-zh": "按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。"
      }
     },
     {
      "description": "Filter by event type; repeat to select several, omit for all.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by event type; repeat to select several, omit for all.",
       "items": {
        "type": "string"
       },
       "type": "array",
       "x-description-zh": "按事件类型过滤,可重复多选,不给 = 全部。"
      }
     },
     {
      "description": "Filter by country name as recorded by the node geo database (exact match).",
      "in": "query",
      "name": "country",
      "schema": {
       "description": "Filter by country name as recorded by the node geo database (exact match).",
       "type": "string",
       "x-description-zh": "按国家过滤(节点归属地库给的名称,精确匹配)。"
      }
     },
     {
      "description": "Filter by province (exact match).",
      "in": "query",
      "name": "province",
      "schema": {
       "description": "Filter by province (exact match).",
       "type": "string",
       "x-description-zh": "按省份过滤(精确匹配)。"
      }
     },
     {
      "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
       "type": "integer",
       "x-description-zh": "按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。"
      }
     },
     {
      "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
      "in": "query",
      "name": "observe",
      "schema": {
       "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
       "type": "boolean",
       "x-description-zh": "true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。"
      }
     },
     {
      "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
      "in": "query",
      "name": "blocked",
      "schema": {
       "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
       "type": "boolean",
       "x-description-zh": "true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。"
      }
     },
     {
      "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
      "in": "query",
      "name": "disposition",
      "schema": {
       "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
       "enum": [
        "other"
       ],
       "type": "string",
       "x-description-zh": "other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Export WAF events as CSV",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "导出 WAF 事件 CSV"
   }
  },
  "/api/v2/reports/waf-events/summary": {
   "get": {
    "operationId": "get-reports-waf-events-summary",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Start of the time window (inclusive), RFC 3339.",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start of the time window (inclusive), RFC 3339.",
       "type": "string",
       "x-description-zh": "时间窗起点(含),RFC 3339。"
      }
     },
     {
      "description": "End of the time window (exclusive), RFC 3339; must be after start, at most 31 days apart.",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End of the time window (exclusive), RFC 3339; must be after start, at most 31 days apart.",
       "type": "string",
       "x-description-zh": "时间窗终点(不含),RFC 3339;须晚于 start,跨度最长 31 天。"
      }
     },
     {
      "description": "Filter by site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Filter by site.",
       "type": "integer",
       "x-description-zh": "按站点过滤。"
      }
     },
     {
      "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
      "in": "query",
      "name": "ip",
      "schema": {
       "description": "Filter by client address: a single IPv4/IPv6 address matches exactly; a CIDR range (IPv4-mapped notation accepted) matches by address interval. Prefixes shorter than /8 (IPv4) or /32 (IPv6) are rejected with 422.",
       "type": "string",
       "x-description-zh": "按客户端地址过滤:单个 IPv4/IPv6 地址精确匹配,或 CIDR 网段(含 IPv4 映射写法)按地址区间匹配;网段前缀 IPv4 不短于 /8、IPv6 不短于 /32,否则 422。"
      }
     },
     {
      "description": "URL contains (case-sensitive substring of the masked path and query string).",
      "in": "query",
      "name": "url",
      "schema": {
       "description": "URL contains (case-sensitive substring of the masked path and query string).",
       "type": "string",
       "x-description-zh": "URL 包含(区分大小写的子串,匹配已脱敏的 路径 + 查询串)。"
      }
     },
     {
      "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
      "in": "query",
      "name": "ja4",
      "schema": {
       "description": "Exact match on the client TLS fingerprint JA4 (events without a fingerprint never match).",
       "type": "string",
       "x-description-zh": "按客户端 TLS 指纹 JA4 精确过滤(事件没取到指纹的不匹配)。"
      }
     },
     {
      "description": "Filter by the matched rule id.",
      "in": "query",
      "name": "rule_id",
      "schema": {
       "description": "Filter by the matched rule id.",
       "type": "integer",
       "x-description-zh": "按命中规则号过滤。"
      }
     },
     {
      "description": "Filter by action: block, log, challenge, mask or replace.",
      "in": "query",
      "name": "action",
      "schema": {
       "description": "Filter by action: block, log, challenge, mask or replace.",
       "enum": [
        "block",
        "log",
        "challenge",
        "mask",
        "replace"
       ],
       "type": "string",
       "x-description-zh": "按处置过滤:block 拦截、log 只记录、challenge 验证、mask 打码、replace 替换。"
      }
     },
     {
      "description": "Filter by event type; repeat to select several, omit for all.",
      "in": "query",
      "name": "type",
      "schema": {
       "description": "Filter by event type; repeat to select several, omit for all.",
       "items": {
        "type": "string"
       },
       "type": "array",
       "x-description-zh": "按事件类型过滤,可重复多选,不给 = 全部。"
      }
     },
     {
      "description": "Filter by country name as recorded by the node geo database (exact match).",
      "in": "query",
      "name": "country",
      "schema": {
       "description": "Filter by country name as recorded by the node geo database (exact match).",
       "type": "string",
       "x-description-zh": "按国家过滤(节点归属地库给的名称,精确匹配)。"
      }
     },
     {
      "description": "Filter by province (exact match).",
      "in": "query",
      "name": "province",
      "schema": {
       "description": "Filter by province (exact match).",
       "type": "string",
       "x-description-zh": "按省份过滤(精确匹配)。"
      }
     },
     {
      "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
      "in": "query",
      "name": "node_id",
      "schema": {
       "description": "Filter by reporting node; tenants cannot see node ids, so the parameter is ignored for them (no error).",
       "type": "integer",
       "x-description-zh": "按上报节点过滤;租户看不到节点编号,传了当没传(不报错)。"
      }
     },
     {
      "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
      "in": "query",
      "name": "observe",
      "schema": {
       "description": "true = only events recorded in observe mode; false or omitted = no such filter.",
       "type": "boolean",
       "x-description-zh": "true = 只看观察期(只记录不处置)的事件;false 或不给 = 不按此过滤。"
      }
     },
     {
      "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
      "in": "query",
      "name": "blocked",
      "schema": {
       "description": "true = only blocks in block mode (action = block, not observe); false = only the rest.",
       "type": "boolean",
       "x-description-zh": "true = 只看拦截模式的拦截(action = block 且非观察);false = 只看其余。"
      }
     },
     {
      "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
      "in": "query",
      "name": "disposition",
      "schema": {
       "description": "other = only events outside blocked / challenge / observe-only (not observe mode and action is neither block nor challenge, i.e. log, mask, replace); omitted = no such filter.",
       "enum": [
        "other"
       ],
       "type": "string",
       "x-description-zh": "other = 只看处置不在「已拦截 / 验证 / 仅观察」里的事件(非观察期且 action 不是 block、challenge,即只记录、打码、替换);不给 = 不按此过滤。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Summarize WAF events",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "WAF 事件汇总"
   }
  },
  "/api/v2/reports/waf-events/{event_id}": {
   "get": {
    "operationId": "get-reports-waf-events-event-id",
    "parameters": [
     {
      "in": "path",
      "name": "event_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get a WAF event",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取 WAF 事件详情"
   }
  },
  "/api/v2/reports/waf-events/{event_id}/allow": {
   "post": {
    "operationId": "post-reports-waf-events-event-id-allow",
    "parameters": [
     {
      "in": "path",
      "name": "event_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "param": {
          "description": "Name of the matched parameter, header or cookie; empty for unnamed locations.",
          "type": "string",
          "x-description-zh": "命中的参数名/请求头名/Cookie 名;无名部位为空。"
         },
         "path": {
          "description": "Limit to this path prefix; must equal the event URL path or be a prefix ending in / (e.g. /api/); a bare / must be combined with a rule or parameter. Omit for any path.",
          "type": "string",
          "x-description-zh": "仅限该路径前缀;须等于事件 URL 路径,或是以 / 结尾的前缀(如 /api/);单独的 / 须同时选规则号或参数。不给 = 不限路径。"
         },
         "rule": {
          "default": false,
          "description": "Skip only the matched rule (rule_ids); not allowed for non-rule events (rule id 0) or semantic events.",
          "type": "boolean",
          "x-description-zh": "仅跳过事件命中的这条规则(rule_ids);非规则类事件(规则号 0)与语义事件不能勾。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Allow-list a WAF event",
    "tags": [
     "reports"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "一键加白 WAF 事件"
   }
  },
  "/api/v2/site-groups": {
   "get": {
    "operationId": "get-site-groups",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
       "type": "string",
       "x-description-zh": "只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List site groups",
    "tags": [
     "site-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出站点分组"
   },
   "post": {
    "operationId": "post-site-groups",
    "parameters": [
     {
      "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create site group",
    "tags": [
     "site-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建站点分组"
   }
  },
  "/api/v2/site-groups/{id}": {
   "delete": {
    "operationId": "delete-site-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete site group",
    "tags": [
     "site-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除站点分组"
   },
   "get": {
    "operationId": "get-site-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site group",
    "tags": [
     "site-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点分组"
   },
   "put": {
    "operationId": "put-site-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update site group",
    "tags": [
     "site-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改站点分组"
   }
  },
  "/api/v2/site-ip-lists/{site_id}": {
   "get": {
    "operationId": "get-site-ip-lists-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site IP blacklist and whitelist",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点黑白名单"
   },
   "put": {
    "operationId": "put-site-ip-lists-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "black": [
         "198.51.100.0/24"
        ],
        "white": [
         "203.0.113.9"
        ]
       },
       "schema": {
        "properties": {
         "black": {
          "description": "Permanent blacklist (a match = connection dropped); the count is limited by protect.black_ip_max.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "永久黑名单(命中 = 断开);条数受 protect.black_ip_max 约束。"
         },
         "black_items": {
          "description": "Blacklist entries with expiry, reason and source; expired entries are not returned.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpListItem"
          },
          "type": "array",
          "x-description-zh": "黑名单条目(含到期时间、原因、来源);已到期的不返回。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when the read updated_at is null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "white": {
          "description": "Permanent whitelist (a match = CC and other protections are skipped); the count is limited by protect.white_ip_max.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "永久白名单(命中 = 跳过 CC 等防护);条数受 protect.white_ip_max 约束。"
         },
         "white_items": {
          "description": "Whitelist entries with expiry, reason and source; expired entries are not returned.",
          "items": {
           "type": "object",
           "x-gocdn-type": "IpListItem"
          },
          "type": "array",
          "x-description-zh": "白名单条目(含到期时间、原因、来源);已到期的不返回。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set site IP blacklist and whitelist",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置站点黑白名单"
   }
  },
  "/api/v2/site-ip-lists/{site_id}/export": {
   "get": {
    "operationId": "get-site-ip-lists-site-id-export",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Which list to export.",
      "in": "query",
      "name": "list",
      "required": true,
      "schema": {
       "description": "Which list to export.",
       "enum": [
        "black",
        "white"
       ],
       "type": "string",
       "x-description-zh": "导出哪张名单。"
      }
     },
     {
      "description": "Only export entries from this source; omit for all.",
      "in": "query",
      "name": "source",
      "schema": {
       "description": "Only export entries from this source; omit for all.",
       "enum": [
        "manual",
        "import",
        "ip_detail",
        "api"
       ],
       "type": "object",
       "x-description-zh": "只导出该来源的条目;不带为全部。",
       "x-gocdn-type": "IpListSource"
      }
     },
     {
      "description": "txt (default, one entry per line) or csv (with header, a source column and a UTF-8 BOM).",
      "in": "query",
      "name": "format",
      "schema": {
       "default": "txt",
       "description": "txt (default, one entry per line) or csv (with header, a source column and a UTF-8 BOM).",
       "enum": [
        "txt",
        "csv"
       ],
       "type": "string",
       "x-description-zh": "txt(缺省,纯文本每行一条)或 csv(带表头与来源列、UTF-8 BOM)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Export site IP list entries",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "导出站点黑白名单"
   }
  },
  "/api/v2/site-ip-lists/{site_id}/import": {
   "post": {
    "operationId": "post-site-ip-lists-site-id-import",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "dry_run": true,
        "list": "black",
        "mode": "merge",
        "text": "198.51.100.0/24,2030-01-01T00:00:00Z,scanner\n"
       },
       "schema": {
        "properties": {
         "dry_run": {
          "default": false,
          "description": "true only checks the file and saves nothing.",
          "type": "boolean",
          "x-description-zh": "true 只预检,不保存。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when the read updated_at is null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到 updated_at 为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "list": {
          "description": "Which list to import into.",
          "enum": [
           "black",
           "white"
          ],
          "type": "string",
          "x-description-zh": "导入到哪张名单。"
         },
         "mode": {
          "default": "merge",
          "description": "merge adds to the current list (the imported row wins for the same IP); replace swaps the whole list for the imported rows.",
          "enum": [
           "merge",
           "replace"
          ],
          "type": "string",
          "x-description-zh": "merge 并进现有名单(同 IP 以导入行为准);replace 用导入行替换整张名单。"
         },
         "text": {
          "description": "File content (txt/csv), one entry per line: IP/CIDR[,expiry][,reason].",
          "type": "string",
          "x-description-zh": "文件内容(txt/csv),每行 IP/CIDR[,到期时间][,原因]。"
         }
        },
        "required": [
         "list",
         "text"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Bulk import site IP list entries",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量导入站点黑白名单"
   }
  },
  "/api/v2/site-ip-lists/{site_id}/ip-detail": {
   "get": {
    "operationId": "get-site-ip-lists-site-id-ip-detail",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "IPv4 or IPv6 address.",
      "in": "query",
      "name": "ip",
      "required": true,
      "schema": {
       "description": "IPv4 or IPv6 address.",
       "type": "string",
       "x-description-zh": "IPv4 或 IPv6 地址。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "IP detail",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "IP 详情"
   },
   "post": {
    "operationId": "post-site-ip-lists-site-id-ip-detail",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "expires_at": {
          "description": "Expiry time; empty = permanent. Must be in the future.",
          "type": "string",
          "x-description-zh": "到期时间;空 = 永久。须晚于当前时刻。"
         },
         "ip": {
          "description": "Normalized address (IPv4-mapped addresses shown as IPv4).",
          "type": "string",
          "x-description-zh": "规范化后的地址(IPv4 映射地址还原成 IPv4)。"
         },
         "list": {
          "description": "Which list to import into.",
          "enum": [
           "black",
           "white"
          ],
          "type": "string",
          "x-description-zh": "导入到哪张名单。"
         },
         "reason": {
          "description": "Reason (note), at most 200 characters.",
          "type": "string",
          "x-description-zh": "原因(备注),最长 200 个字符。"
         },
         "scope": {
          "description": "site = this site's list; global = the global list (admins only).",
          "enum": [
           "site",
           "global"
          ],
          "type": "string",
          "x-description-zh": "site 本站名单;global 全局名单(仅管理员)。"
         }
        },
        "required": [
         "ip",
         "list",
         "scope"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Blacklist or whitelist from IP detail",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "从 IP 详情拉黑或加白"
   }
  },
  "/api/v2/site-ip-lists/{site_id}/tmp-white-clear": {
   "post": {
    "operationId": "post-site-ip-lists-site-id-tmp-white-clear",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Clear site temporary whitelist",
    "tags": [
     "site-ip-lists"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "清空站点临时白名单"
   }
  },
  "/api/v2/site-leak-guards/{site_id}": {
   "delete": {
    "operationId": "delete-site-leak-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Restore site data leak protection to the scheme",
    "tags": [
     "site-leak-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点防泄露恢复按方案"
   },
   "get": {
    "operationId": "get-site-leak-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site data leak protection settings",
    "tags": [
     "site-leak-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点防泄露设置"
   },
   "put": {
    "operationId": "put-site-leak-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "custom": {
          "description": "Custom regular expressions, at most 16.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteLeakGuardCustom"
          },
          "type": "array",
          "x-description-zh": "自定义正则,最多 16 条。"
         },
         "detect": {
          "description": "Action per built-in pattern; omit a pattern to not check it.",
          "type": "object",
          "x-description-zh": "内置识别各类的处置;不写 = 不查这一类。",
          "x-gocdn-type": "SiteLeakGuardDetect"
         },
         "enabled": {
          "description": "Whether enabled.",
          "type": "boolean",
          "x-description-zh": "是否开启。"
         },
         "exclude": {
          "description": "Path prefixes that are not checked, at most 32.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "不检测的路径前缀,最多 32 条。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "observe_days": {
          "description": "Days observed after turning on.",
          "type": "integer",
          "x-description-zh": "新开启时观察的天数。"
         }
        },
        "required": [
         "enabled"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set site data leak protection",
    "tags": [
     "site-leak-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置站点防泄露"
   }
  },
  "/api/v2/site-replay-guards/{site_id}": {
   "delete": {
    "operationId": "delete-site-replay-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Restore site replay protection to the scheme",
    "tags": [
     "site-replay-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点防重放恢复按方案"
   },
   "get": {
    "operationId": "get-site-replay-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site replay protection settings",
    "tags": [
     "site-replay-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点防重放设置"
   },
   "put": {
    "operationId": "put-site-replay-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "Without a token or on replay: block = 403; challenge = JS challenge. Omitted = block.",
          "enum": [
           "block",
           "challenge"
          ],
          "type": "object",
          "x-description-zh": "没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。",
          "x-gocdn-type": "ReplayGuardAction"
         },
         "app_salt": {
          "description": "Signing salt (app key, 32-byte hex); with app_sign on but no salt, signed headers are never accepted.",
          "example": "0000000000000000000000000000000000000000000000000000000000000000",
          "type": "string",
          "x-description-zh": "签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。"
         },
         "app_sign": {
          "description": "App signed-header mode - requests carrying the signature headers are checked by signature, no token needed.",
          "type": "boolean",
          "x-description-zh": "App 签名头模式:请求带签名头即按签名校验,不需要令牌。"
         },
         "bind_ip": {
          "description": "Also bind the token to the client IP (a new IP invalidates it).",
          "type": "boolean",
          "x-description-zh": "令牌再绑客户端 IP(换 IP 即失效)。"
         },
         "enabled": {
          "description": "Whether enabled.",
          "type": "boolean",
          "x-description-zh": "是否开启。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "methods": {
          "description": "Protected methods; omitted = POST/PUT/PATCH/DELETE.",
          "items": {
           "type": "object",
           "x-gocdn-type": "ReplayGuardMethod"
          },
          "type": "array",
          "x-description-zh": "受保护方法;不写 = POST/PUT/PATCH/DELETE。"
         },
         "paths": {
          "description": "Protected API paths, at most 64; empty = nothing protected.",
          "items": {
           "type": "object",
           "x-gocdn-type": "ReplayGuardPath"
          },
          "type": "array",
          "x-description-zh": "保护接口路径表,最多 64 条;空 = 不保护。"
         },
         "ttl_s": {
          "description": "Token lifetime in seconds, also used for signed-header timestamps; omitted = 120.",
          "type": "integer",
          "x-description-zh": "令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。"
         }
        },
        "required": [
         "enabled"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set site replay protection",
    "tags": [
     "site-replay-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置站点防重放"
   }
  },
  "/api/v2/site-tamper-guards/{site_id}": {
   "delete": {
    "operationId": "delete-site-tamper-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Restore site web tamper protection to the scheme",
    "tags": [
     "site-tamper-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点防篡改恢复按方案"
   },
   "get": {
    "operationId": "get-site-tamper-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site web tamper protection settings",
    "tags": [
     "site-tamper-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点防篡改设置"
   },
   "put": {
    "operationId": "put-site-tamper-guards-site-id",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "Action on tampering.",
          "enum": [
           "restore",
           "log"
          ],
          "type": "string",
          "x-description-zh": "篡改时的处置。"
         },
         "enabled": {
          "description": "Whether enabled.",
          "type": "boolean",
          "x-description-zh": "是否开启。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (when null, i.e. never set, use 1970-01-01T00:00:00Z). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空 = 还没设置过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "mode": {
          "description": "What counts as tampering.",
          "enum": [
           "structure",
           "full"
          ],
          "type": "string",
          "x-description-zh": "检查范围。"
         },
         "observe_days": {
          "description": "Days observed after turning on.",
          "type": "integer",
          "x-description-zh": "新开启时观察的天数。"
         },
         "scopes": {
          "description": "Protected scopes.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteTamperScope"
          },
          "type": "array",
          "x-description-zh": "保护范围。"
         }
        },
        "required": [
         "enabled"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set site web tamper protection",
    "tags": [
     "site-tamper-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置站点防篡改"
   }
  },
  "/api/v2/site-tamper-guards/{site_id}/diff": {
   "get": {
    "operationId": "get-site-tamper-guards-site-id-diff",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Baseline page path (e.g. /, /about.html).",
      "in": "query",
      "name": "path",
      "required": true,
      "schema": {
       "description": "Baseline page path (e.g. /, /about.html).",
       "type": "string",
       "x-description-zh": "基准页路径(如 /、/about.html)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site web tamper protection diff",
    "tags": [
     "site-tamper-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "看站点防篡改差异"
   }
  },
  "/api/v2/site-tamper-guards/{site_id}/rebase": {
   "post": {
    "operationId": "post-site-tamper-guards-site-id-rebase",
    "parameters": [
     {
      "in": "path",
      "name": "site_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update site web tamper protection baseline",
    "tags": [
     "site-tamper-guards"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "更新站点防篡改基准"
   }
  },
  "/api/v2/sites": {
   "get": {
    "operationId": "get-sites",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
       "type": "string",
       "x-description-zh": "只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。"
      }
     },
     {
      "description": "Filter by domain substring (case-insensitive); a.example.com also matches www.a.example.com. Use domains for exact matching.",
      "in": "query",
      "name": "domain",
      "schema": {
       "description": "Filter by domain substring (case-insensitive); a.example.com also matches www.a.example.com. Use domains for exact matching.",
       "type": "string",
       "x-description-zh": "按域名子串过滤(不分大小写):a.example.com 也会命中 www.a.example.com;精确查用 domains。"
      }
     },
     {
      "description": "Comma-separated domains; matches sites having any domain exactly equal to one of them (case-insensitive, no substring match).",
      "in": "query",
      "name": "domains",
      "schema": {
       "description": "Comma-separated domains; matches sites having any domain exactly equal to one of them (case-insensitive, no substring match).",
       "type": "string",
       "x-description-zh": "多个域名逗号分隔,站点任一域名与其中之一整项相同即命中(不分大小写,不做子串匹配)。"
      }
     },
     {
      "description": "Only list sites in this group.",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only list sites in this group.",
       "type": "integer",
       "x-description-zh": "只列该分组里的站点。"
      }
     },
     {
      "description": "Comma-separated group IDs (positive integers, at most 200 after deduplication); a site in any of them matches. May be combined with group_id (both must hold).",
      "in": "query",
      "name": "group_ids",
      "schema": {
       "description": "Comma-separated group IDs (positive integers, at most 200 after deduplication); a site in any of them matches. May be combined with group_id (both must hold).",
       "type": "string",
       "x-description-zh": "多个分组 id 逗号分隔(正整数,去重后至多 200 个),站点在其中任一分组里即命中;可与 group_id 同用(两者都要满足)。"
      }
     },
     {
      "description": "Filter by the application identified by the checkup (exact match, e.g. wordpress); sites never checked do not match.",
      "in": "query",
      "name": "app",
      "schema": {
       "description": "Filter by the application identified by the checkup (exact match, e.g. wordpress); sites never checked do not match.",
       "type": "string",
       "x-description-zh": "按体检识别出的程序(report_checkup_sites.app,如 wordpress)精确过滤;还没体检过的站点不命中。"
      }
     },
     {
      "description": "Filter by enabled state.",
      "in": "query",
      "name": "enabled",
      "schema": {
       "description": "Filter by enabled state.",
       "type": "boolean",
       "x-description-zh": "按启停过滤。"
      }
     },
     {
      "description": "Filter by exact site id (panel search box \"Site ID\").",
      "in": "query",
      "name": "id",
      "schema": {
       "description": "Filter by exact site id (panel search box \"Site ID\").",
       "type": "integer",
       "x-description-zh": "按站点 id 精确过滤。"
      }
     },
     {
      "description": "Filter by name substring.",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Filter by name substring.",
       "type": "string",
       "x-description-zh": "按名称子串过滤。"
      }
     },
     {
      "description": "Filter by origin host substring (panel search box \"Origin IP\").",
      "in": "query",
      "name": "origin",
      "schema": {
       "description": "Filter by origin host substring (panel search box \"Origin IP\").",
       "type": "string",
       "x-description-zh": "按源站主机子串过滤。"
      }
     },
     {
      "description": "Filter by stop code; 0 = normal (panel search box \"Site status\").",
      "in": "query",
      "name": "stop_code",
      "schema": {
       "description": "Filter by stop code; 0 = normal (panel search box \"Site status\").",
       "type": "integer",
       "x-description-zh": "按停服码过滤;0 = 正常。"
      }
     },
     {
      "description": "Filter by user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Filter by user package.",
       "type": "integer",
       "x-description-zh": "按用户套餐过滤。"
      }
     },
     {
      "description": "Only list sites whose HTTP listen ports (config.http_ports) include this port; exact match (80 does not match 8080).",
      "in": "query",
      "name": "http_port",
      "schema": {
       "description": "Only list sites whose HTTP listen ports (config.http_ports) include this port; exact match (80 does not match 8080).",
       "type": "integer",
       "x-description-zh": "只列 HTTP 监听端口(config.http_ports)里有这个端口的站点,整段匹配。"
      }
     },
     {
      "description": "Only list sites whose HTTPS listen ports (config.https.ports) include this port; sites without HTTPS never match.",
      "in": "query",
      "name": "https_port",
      "schema": {
       "description": "Only list sites whose HTTPS listen ports (config.https.ports) include this port; sites without HTTPS never match.",
       "type": "integer",
       "x-description-zh": "只列 HTTPS 监听端口(config.https.ports)里有这个端口的站点;没开 HTTPS 的不算,整段匹配。"
      }
     },
     {
      "description": "true lists only sites with HTTPS enabled (config.https has listen ports); false lists only sites without HTTPS.",
      "in": "query",
      "name": "https_enabled",
      "schema": {
       "description": "true lists only sites with HTTPS enabled (config.https has listen ports); false lists only sites without HTTPS.",
       "type": "boolean",
       "x-description-zh": "true 只列开了 HTTPS(config.https 有监听端口)的站点,false 只列没开的。"
      }
     },
     {
      "description": "Filter by base package (the owning user package was bought from it).",
      "in": "query",
      "name": "package_id",
      "schema": {
       "description": "Filter by base package (the owning user package was bought from it).",
       "type": "integer",
       "x-description-zh": "按基础套餐过滤。"
      }
     },
     {
      "description": "Filter by region (the CNAME's primary line group belongs to it); owners without their own CNAME use their user package's shared one.",
      "in": "query",
      "name": "region_id",
      "schema": {
       "description": "Filter by region (the CNAME's primary line group belongs to it); owners without their own CNAME use their user package's shared one.",
       "type": "integer",
       "x-description-zh": "按区域过滤:接入名的主线路分组属于该区域;没有自己接入名的按所属已售套餐的共用接入名算。"
      }
     },
     {
      "description": "Filter by line group (the CNAME's primary or backup line group).",
      "in": "query",
      "name": "node_group_id",
      "schema": {
       "description": "Filter by line group (the CNAME's primary or backup line group).",
       "type": "integer",
       "x-description-zh": "按线路分组过滤:接入名的主线路分组或备用线路分组是它。"
      }
     },
     {
      "description": "Filter by CNAME root domain.",
      "in": "query",
      "name": "cname_domain_id",
      "schema": {
       "description": "Filter by CNAME root domain.",
       "type": "integer",
       "x-description-zh": "按接入根域过滤。"
      }
     },
     {
      "description": "Filter by CNAME host label, exact match (case-insensitive, without the root domain).",
      "in": "query",
      "name": "cname_hostname",
      "schema": {
       "description": "Filter by CNAME host label, exact match (case-insensitive, without the root domain).",
       "type": "string",
       "x-description-zh": "按接入名主机记录精确过滤。"
      }
     },
     {
      "description": "Filter by config sync state: behind = some online node has not yet installed the config version containing its latest change;",
      "in": "query",
      "name": "sync_state",
      "schema": {
       "description": "Filter by config sync state: behind = some online node has not yet installed the config version containing its latest change;",
       "enum": [
        "behind",
        "synced"
       ],
       "type": "string",
       "x-description-zh": "按配置同步状态过滤:behind = 配置落后(还有在线节点没装上它最近一次修改后的配置版本);"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List sites",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出站点"
   },
   "post": {
    "operationId": "post-sites",
    "parameters": [
     {
      "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "domains": [
         "www.example.com"
        ],
        "name": "demo",
        "origins": [
         {
          "host": "203.0.113.10"
         }
        ]
       },
       "schema": {
        "properties": {
         "cname": {
          "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
          "type": "object",
          "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
          "x-gocdn-type": "CnameBinding"
         },
         "config": {
          "description": "Node config fields (top-level fields of schema/site.json, without id, uid, upid, domains, origins, enabled, stop_code and rulesets).",
          "type": "object",
          "x-description-zh": "节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。"
         },
         "domains": {
          "description": "Domains served by the site.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "站点绑定的域名。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_ids": {
          "description": "Ids of the site groups the site belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "站点所属分组的 id。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origins": {
          "description": "Origin servers.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = every request is answered with this status code (set by admin or billing).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
         },
         "upid": {
          "description": "User package id (may be empty before the package domain goes live; falls back to tenant_id in the snapshot when empty).",
          "type": "integer",
          "x-description-zh": "用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。"
         }
        },
        "required": [
         "domains",
         "origins"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create site",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建站点"
   }
  },
  "/api/v2/sites/batch": {
   "post": {
    "operationId": "post-sites-batch",
    "parameters": [
     {
      "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owning tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, whose own account is always the owner.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "action": "set_enabled",
        "enabled": false,
        "ids": [
         1
        ]
       },
       "schema": {
        "properties": {
         "action": {
          "description": "Batch action: set_enabled, delete, set_groups, update_config or create.",
          "enum": [
           "set_enabled",
           "delete",
           "set_groups",
           "update_config",
           "create"
          ],
          "type": "string",
          "x-description-zh": "批量动作:set_enabled(启停)、delete(删除)、set_groups(设置分组)、update_config(合并配置)、create(批量新建)。"
         },
         "config": {
          "description": "Node config fields (top-level fields of schema/site.json, without id, uid, upid, domains, origins, enabled, stop_code and rulesets).",
          "type": "object",
          "x-description-zh": "节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_ids": {
          "description": "Ids of the site groups the site belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "站点所属分组的 id。"
         },
         "ids": {
          "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
         },
         "items": {
          "description": "Used by create: the sites to create (up to 100), each shaped like the POST /sites request body.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteWrite"
          },
          "type": "array",
          "x-description-zh": "create 用:要新建的站点(最多 100 个),每条同 POST /sites 的请求体。"
         }
        },
        "required": [
         "action"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch update sites",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量操作站点"
   }
  },
  "/api/v2/sites/checkup-fix-batch": {
   "post": {
    "operationId": "post-sites-checkup-fix-batch",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "batch": {
          "description": "rec_type only - pass the batch returned by the first segment so all segments share one undo batch; omit to start a new batch.",
          "type": "string",
          "x-description-zh": "只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。"
         },
         "ids": {
          "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
         },
         "key": {
          "description": "Key of the checkup problem to fix, same meaning as the single-site fix.",
          "enum": [
           "no_https",
           "tls_old",
           "sec_headers",
           "waf_block",
           "cc_mid",
           "rec_type"
          ],
          "type": "string",
          "x-description-zh": "要修复的体检项键,含义同单站一键修复。"
         }
        },
        "required": [
         "ids",
         "key"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch one-click fix for a checkup problem",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量一键修复体检问题"
   }
  },
  "/api/v2/sites/checkup-fix-batches": {
   "get": {
    "operationId": "get-sites-checkup-fix-batches",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List recent checkup fix batches",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出最近的体检修复批次"
   }
  },
  "/api/v2/sites/origin-alerts": {
   "get": {
    "operationId": "get-sites-origin-alerts",
    "parameters": [
     {
      "description": "Only this site.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Only this site.",
       "type": "integer",
       "x-description-zh": "只看该站点。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Origin inconsistency alerts",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "源站内容不一致告警"
   }
  },
  "/api/v2/sites/protect-recommend/apply": {
   "post": {
    "operationId": "post-sites-protect-recommend-apply",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "ids": {
          "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
         },
         "observe_days": {
          "description": "Overrides the observe-first days of waf_mode in the table (0 blocks immediately); defaults to the table value.",
          "type": "integer",
          "x-description-zh": "覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。"
         },
         "skip": {
          "description": "Recommended items the user unticked and that must not be applied this time.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "用户取消勾选、本次不套用的推荐项。"
         },
         "type": {
          "description": "Site type - corporate, shop, content, api, admin or download.",
          "enum": [
           "corporate",
           "shop",
           "content",
           "api",
           "admin",
           "download"
          ],
          "type": "string",
          "x-description-zh": "网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。"
         }
        },
        "required": [
         "ids",
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch apply the recommended protection settings",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量套用推荐防护配置"
   }
  },
  "/api/v2/sites/protect-recommend/preview": {
   "post": {
    "operationId": "post-sites-protect-recommend-preview",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "ids": {
          "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
         },
         "observe_days": {
          "description": "Overrides the observe-first days of waf_mode in the table (0 blocks immediately); defaults to the table value.",
          "type": "integer",
          "x-description-zh": "覆盖推荐表里 waf_mode 的先观察天数(0 = 直接拦截);缺省按推荐表。"
         },
         "skip": {
          "description": "Recommended items the user unticked and that must not be applied this time.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "用户取消勾选、本次不套用的推荐项。"
         },
         "type": {
          "description": "Site type - corporate, shop, content, api, admin or download.",
          "enum": [
           "corporate",
           "shop",
           "content",
           "api",
           "admin",
           "download"
          ],
          "type": "string",
          "x-description-zh": "网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。"
         }
        },
        "required": [
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Preview the impact of the recommended protection settings",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "预览推荐防护配置的影响"
   }
  },
  "/api/v2/sites/protect-recommend/undo": {
   "post": {
    "operationId": "post-sites-protect-recommend-undo",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "batch": {
          "description": "rec_type only - pass the batch returned by the first segment so all segments share one undo batch; omit to start a new batch.",
          "type": "string",
          "x-description-zh": "只用于 rec_type:分段修复时带上第一段返回的批次号,各段的撤销快照记在同一批里;不带则新开一批。"
         },
         "ids": {
          "description": "Ids of the sites to operate on (up to 100; required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的站点 id(最多 100 个;create 以外的动作必填)。"
         }
        },
        "required": [
         "batch",
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Undo a batch of recommended protection settings",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "撤销一批推荐防护配置"
   }
  },
  "/api/v2/sites/region-check": {
   "post": {
    "operationId": "post-sites-region-check",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "region_limit": {
         "country": [
          "JP"
         ],
         "mode": "block"
        }
       },
       "schema": {
        "properties": {
         "region_limit": {
          "description": "The region limit to check (same as Site.config.region_limit).",
          "type": "object",
          "x-description-zh": "要检查的地区限制(同 Site.config.region_limit)。"
         }
        },
        "required": [
         "region_limit"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Pre-save check of a region limit",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "地区限制保存前检查"
   }
  },
  "/api/v2/sites/select-ids": {
   "post": {
    "operationId": "post-sites-select-ids",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "app": {
          "description": "Filter by the application identified by the checkup (exact match).",
          "type": "string",
          "x-description-zh": "按体检识别出的程序精确过滤。"
         },
         "domain": {
          "description": "Filter by domain substring (case-insensitive).",
          "type": "string",
          "x-description-zh": "按域名子串过滤(不分大小写)。"
         },
         "domains": {
          "description": "Domains served by the site.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "站点绑定的域名。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_id": {
          "description": "Only sites in this group.",
          "type": "integer",
          "x-description-zh": "只取该分组里的站点。"
         },
         "group_ids": {
          "description": "Ids of the site groups the site belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "站点所属分组的 id。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origin": {
          "description": "Filter by origin host substring.",
          "type": "string",
          "x-description-zh": "按源站主机子串过滤。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = every request is answered with this status code (set by admin or billing).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
         },
         "upid": {
          "description": "User package id (may be empty before the package domain goes live; falls back to tenant_id in the snapshot when empty).",
          "type": "integer",
          "x-description-zh": "用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get all site IDs matching a filter",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "取筛选结果的全部站点 id"
   }
  },
  "/api/v2/sites/{id}": {
   "delete": {
    "operationId": "delete-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete site",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除站点"
   },
   "get": {
    "operationId": "get-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取站点"
   },
   "put": {
    "operationId": "put-sites-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "enabled": false
       },
       "schema": {
        "properties": {
         "cname": {
          "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
          "type": "object",
          "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
          "x-gocdn-type": "CnameBinding"
         },
         "config": {
          "description": "Node config fields (top-level fields of schema/site.json, without id, uid, upid, domains, origins, enabled, stop_code and rulesets).",
          "type": "object",
          "x-description-zh": "节点配置字段(schema/site.json 的顶层字段,去掉 id、uid、upid、domains、origins、enabled、stop_code、rulesets)。"
         },
         "domains": {
          "description": "Domains served by the site.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "站点绑定的域名。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "group_ids": {
          "description": "Ids of the site groups the site belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "站点所属分组的 id。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origins": {
          "description": "Origin servers.",
          "items": {
           "type": "object",
           "x-gocdn-type": "SiteOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = every request is answered with this status code (set by admin or billing).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 所有请求回这个状态码(管理员/计费设置)。"
         },
         "upid": {
          "description": "User package id (may be empty before the package domain goes live; falls back to tenant_id in the snapshot when empty).",
          "type": "integer",
          "x-description-zh": "用户套餐 id(套餐域上线前可空;快照里空时取 tenant_id)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update site",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改站点"
   }
  },
  "/api/v2/sites/{id}/checkup-fix": {
   "post": {
    "operationId": "post-sites-id-checkup-fix",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "key": "no_https"
       },
       "schema": {
        "properties": {
         "key": {
          "description": "Key of the checkup problem to fix, same meaning as the single-site fix.",
          "enum": [
           "no_https",
           "tls_old",
           "sec_headers",
           "waf_block",
           "cc_mid",
           "rec_type"
          ],
          "type": "string",
          "x-description-zh": "要修复的体检项键,含义同单站一键修复。"
         }
        },
        "required": [
         "key"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "One-click fix for a checkup problem",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "一键修复体检问题"
   }
  },
  "/api/v2/sites/{id}/health": {
   "get": {
    "operationId": "get-sites-id-health",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site origin health status",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点回源健康状态"
   }
  },
  "/api/v2/sites/{id}/l2": {
   "get": {
    "operationId": "get-sites-id-l2",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get site tiered origin",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "查看网站分层回源"
   },
   "patch": {
    "operationId": "patch-sites-id-l2",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "l2_group_id": {
          "description": "L2 group used; null for region default.",
          "type": "integer",
          "x-description-zh": "使用的 L2 组;null = 区域默认。"
         },
         "l2_pick": {
          "description": "How L2 is picked for this site; null to follow the defaults.",
          "enum": [
           "region",
           "near"
          ],
          "type": "string",
          "x-description-zh": "本站选 L2 的方式;null = 跟默认设置。"
         },
         "origin_l2_only": {
          "description": "Origin allows only L2: dynamic requests also go via L2, borrowing other regions when needed.",
          "type": "boolean",
          "x-description-zh": "源站只允许 L2 访问:动态请求也经 L2,本区域没 L2 时借用其他区域。"
         },
         "origin_max_conns": {
          "description": "Max origin concurrency per node; 0 for unlimited. Excess requests queue instead of failing with 503.",
          "type": "integer",
          "x-description-zh": "源站最大并发(每节点在途);0 = 不限,超了排队不报 503。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update site tiered origin",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改网站分层回源"
   }
  },
  "/api/v2/sites/{id}/l2-egress-ips": {
   "get": {
    "operationId": "get-sites-id-l2-egress-ips",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Format of text: ip one per line, nginx allow lines, or iptables rules; defaults to ip.",
      "in": "query",
      "name": "fmt",
      "schema": {
       "default": "ip",
       "description": "Format of text: ip one per line, nginx allow lines, or iptables rules; defaults to ip.",
       "enum": [
        "ip",
        "nginx",
        "iptables"
       ],
       "type": "string",
       "x-description-zh": "text 的格式:ip 每行一个、nginx allow 行、iptables 规则;缺省 ip。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Origin allowlist",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "源站放行清单"
   }
  },
  "/api/v2/sites/{id}/l2-stats": {
   "get": {
    "operationId": "get-sites-id-l2-stats",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Start time (inclusive), RFC 3339",
      "in": "query",
      "name": "start",
      "required": true,
      "schema": {
       "description": "Start time (inclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "起始时间(含),RFC 3339。"
      }
     },
     {
      "description": "End time (exclusive), RFC 3339",
      "in": "query",
      "name": "end",
      "required": true,
      "schema": {
       "description": "End time (exclusive), RFC 3339",
       "type": "string",
       "x-description-zh": "结束时间(不含),RFC 3339。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site tiered origin statistics",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "网站的分层回源统计"
   }
  },
  "/api/v2/sites/{id}/site-type": {
   "put": {
    "operationId": "put-sites-id-site-type",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "type": "shop"
       },
       "schema": {
        "properties": {
         "type": {
          "description": "Site type - corporate, shop, content, api, admin or download.",
          "enum": [
           "corporate",
           "shop",
           "content",
           "api",
           "admin",
           "download"
          ],
          "type": "string",
          "x-description-zh": "网站类型:企业官网、电商、内容资讯、API 服务、后台管理、下载分发。"
         }
        },
        "required": [
         "type"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Set the site type",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "设置网站类型"
   }
  },
  "/api/v2/sites/{id}/speed": {
   "get": {
    "operationId": "get-sites-id-speed",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Statistics window, default 24h.",
      "in": "query",
      "name": "range",
      "schema": {
       "default": "24h",
       "description": "Statistics window, default 24h.",
       "enum": [
        "1h",
        "24h",
        "7d"
       ],
       "type": "string",
       "x-description-zh": "统计窗口,缺省 24h。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Site acceleration statistics",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "站点加速效果"
   }
  },
  "/api/v2/sites/{id}/upload-scan/exceptions": {
   "get": {
    "operationId": "get-sites-id-upload-scan-exceptions",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List a site's upload scan exceptions",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出站点的上传扫描例外"
   }
  },
  "/api/v2/sites/{id}/upload-scan/false-positive": {
   "delete": {
    "operationId": "delete-sites-id-upload-scan-false-positive",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Path prefix of the exception.",
      "in": "query",
      "name": "path",
      "required": true,
      "schema": {
       "description": "Path prefix of the exception.",
       "type": "string",
       "x-description-zh": "例外的路径前缀。"
      }
     },
     {
      "description": "Signature name of the exception; omitted or empty = a whole-path exception.",
      "in": "query",
      "name": "sig",
      "schema": {
       "description": "Signature name of the exception; omitted or empty = a whole-path exception.",
       "type": "string",
       "x-description-zh": "例外的特征名;不给或空 = 路径整段例外。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Revoke a site's upload scan false-positive mark",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "撤销站点标记的上传扫描误报"
   },
   "post": {
    "operationId": "post-sites-id-upload-scan-false-positive",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "path": "/upload/avatar/",
        "sig": "ext:php"
       },
       "schema": {
        "properties": {
         "path": {
          "description": "Path prefix (starting with /); defaults to /.",
          "type": "string",
          "x-description-zh": "路径前缀(以 / 开头);不给取 /。"
         },
         "sha256": {
          "description": "sha256 of the hit file (lowercase hex); a tenant's value must appear in the site's upload hit events; if given, intelligence sharing is on and sig is not empty, a false-positive intelligence item is queued in the same transaction.",
          "type": "string",
          "x-description-zh": "命中文件的 sha256(小写十六进制);租户提交时须是本站上传命中事件里出现过的指纹;给了且情报共享开着、sig 非空时同事务内记一条误报情报待上报。"
         },
         "sig": {
          "description": "Signature name of the false positive (the rule name in the event); empty = the whole path is not scanned (path is then required).",
          "type": "string",
          "x-description-zh": "误报的特征名(事件规则名,如 webshell.php.eval);空 = 该路径整段不扫描(此时必须给 path)。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Mark a site's upload scan hit as a false positive",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "标记站点的上传扫描误报"
   }
  },
  "/api/v2/sites/{id}/url-guard/active": {
   "get": {
    "operationId": "get-sites-id-url-guard-active",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List a site's URL protections in effect",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出站点在途的全网 URL 防护"
   }
  },
  "/api/v2/sites/{id}/url-guard/revoke": {
   "post": {
    "operationId": "post-sites-id-url-guard-revoke",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "path": {
          "description": "Path prefix (starting with /); defaults to /.",
          "type": "string",
          "x-description-zh": "路径前缀(以 / 开头);不给取 /。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Manually revoke a site's URL protections in effect",
    "tags": [
     "sites"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "手动撤销站点在途的全网 URL 防护"
   }
  },
  "/api/v2/stream-groups": {
   "get": {
    "operationId": "get-stream-groups",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List forwarding groups",
    "tags": [
     "stream-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出四层转发分组"
   },
   "post": {
    "operationId": "post-stream-groups",
    "parameters": [
     {
      "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create forwarding group",
    "tags": [
     "stream-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建四层转发分组"
   }
  },
  "/api/v2/stream-groups/{id}": {
   "delete": {
    "operationId": "delete-stream-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete forwarding group",
    "tags": [
     "stream-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除四层转发分组"
   },
   "get": {
    "operationId": "get-stream-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get forwarding group",
    "tags": [
     "stream-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取四层转发分组"
   },
   "put": {
    "operationId": "put-stream-groups-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "des": {
          "description": "Description",
          "type": "string",
          "x-description-zh": "备注说明"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         }
        },
        "required": [
         "name"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update forwarding group",
    "tags": [
     "stream-groups"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改四层转发分组"
   }
  },
  "/api/v2/streams": {
   "get": {
    "operationId": "get-streams",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list forwarding rules listening on this port.",
      "in": "query",
      "name": "port",
      "schema": {
       "description": "Only list forwarding rules listening on this port.",
       "type": "integer",
       "x-description-zh": "只列监听该端口的转发。"
      }
     },
     {
      "description": "Only list rules in this group.",
      "in": "query",
      "name": "group_id",
      "schema": {
       "description": "Only list rules in this group.",
       "type": "integer",
       "x-description-zh": "只列该分组里的转发。"
      }
     },
     {
      "description": "Only list rules under this user package.",
      "in": "query",
      "name": "upid",
      "schema": {
       "description": "Only list rules under this user package.",
       "type": "integer",
       "x-description-zh": "只列该用户套餐下的转发。"
      }
     },
     {
      "description": "Filter by enabled state.",
      "in": "query",
      "name": "enabled",
      "schema": {
       "description": "Filter by enabled state.",
       "type": "boolean",
       "x-description-zh": "按启停过滤。"
      }
     },
     {
      "description": "Filter by exact forwarding rule ID.",
      "in": "query",
      "name": "id",
      "schema": {
       "description": "Filter by exact forwarding rule ID.",
       "type": "integer",
       "x-description-zh": "按转发 id 精确过滤。"
      }
     },
     {
      "description": "Filter by substring of the origin IP.",
      "in": "query",
      "name": "origin",
      "schema": {
       "description": "Filter by substring of the origin IP.",
       "type": "string",
       "x-description-zh": "按源站 IP 子串过滤。"
      }
     },
     {
      "description": "Only list rules that have a listener with this protocol.",
      "in": "query",
      "name": "protocol",
      "schema": {
       "description": "Only list rules that have a listener with this protocol.",
       "enum": [
        "tcp",
        "udp"
       ],
       "type": "string",
       "x-description-zh": "只列有该协议监听的转发。"
      }
     },
     {
      "description": "Filter by stop code; 0 = normal.",
      "in": "query",
      "name": "stop_code",
      "schema": {
       "description": "Filter by stop code; 0 = normal.",
       "type": "integer",
       "x-description-zh": "按停用码过滤;0 = 正常。"
      }
     },
     {
      "description": "Filter by base package (the owning user package was bought from it).",
      "in": "query",
      "name": "package_id",
      "schema": {
       "description": "Filter by base package (the owning user package was bought from it).",
       "type": "integer",
       "x-description-zh": "按基础套餐过滤。"
      }
     },
     {
      "description": "Filter by region (the CNAME's primary line group belongs to it); owners without their own CNAME use their user package's shared one.",
      "in": "query",
      "name": "region_id",
      "schema": {
       "description": "Filter by region (the CNAME's primary line group belongs to it); owners without their own CNAME use their user package's shared one.",
       "type": "integer",
       "x-description-zh": "按区域过滤:接入名的主线路分组属于该区域;没有自己接入名的按所属已售套餐的共用接入名算。"
      }
     },
     {
      "description": "Filter by line group (the CNAME's primary or backup line group).",
      "in": "query",
      "name": "node_group_id",
      "schema": {
       "description": "Filter by line group (the CNAME's primary or backup line group).",
       "type": "integer",
       "x-description-zh": "按线路分组过滤:接入名的主线路分组或备用线路分组是它。"
      }
     },
     {
      "description": "Filter by CNAME root domain.",
      "in": "query",
      "name": "cname_domain_id",
      "schema": {
       "description": "Filter by CNAME root domain.",
       "type": "integer",
       "x-description-zh": "按接入根域过滤。"
      }
     },
     {
      "description": "Filter by CNAME host label, exact match (case-insensitive, without the root domain).",
      "in": "query",
      "name": "cname_hostname",
      "schema": {
       "description": "Filter by CNAME host label, exact match (case-insensitive, without the root domain).",
       "type": "string",
       "x-description-zh": "按接入名主机记录精确过滤。"
      }
     },
     {
      "description": "Filter by config sync state: behind = some online node has not yet installed the config version containing its latest change;",
      "in": "query",
      "name": "sync_state",
      "schema": {
       "description": "Filter by config sync state: behind = some online node has not yet installed the config version containing its latest change;",
       "enum": [
        "behind",
        "synced"
       ],
       "type": "string",
       "x-description-zh": "按配置同步状态过滤:behind = 配置落后(还有在线节点没装上它最近一次修改后的配置版本);"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List streams",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出四层转发"
   },
   "post": {
    "operationId": "post-streams",
    "parameters": [
     {
      "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "listen": [
         {
          "port": 30001
         }
        ],
        "name": "demo",
        "origin_port": 22,
        "origins": [
         {
          "host": "203.0.113.10"
         }
        ]
       },
       "schema": {
        "properties": {
         "acl": {
          "description": "Layer-4 access control. Rules match the source IP or CIDR in order and the first hit decides; if none match, default_action applies; deny drops the connection immediately.",
          "type": "object",
          "x-description-zh": "四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。",
          "x-gocdn-type": "StreamAcl"
         },
         "balance": {
          "description": "Load balancing method. rr is round robin, ip_hash hashes the source IP, least_conn picks the fewest connections, random picks at random.",
          "enum": [
           "rr",
           "ip_hash",
           "least_conn",
           "random"
          ],
          "type": "object",
          "x-description-zh": "负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。",
          "x-gocdn-type": "StreamBalance"
         },
         "cname": {
          "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
          "type": "object",
          "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
          "x-gocdn-type": "CnameBinding"
         },
         "conn_limit": {
          "description": "Per-IP concurrent connection limit; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "单 IP 并发连接上限,0 = 不限。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "group_ids": {
          "description": "IDs of the forwarding groups this rule belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "所属转发分组 id 列表。"
         },
         "listen": {
          "description": "Listener list. Each item is a port and a protocol.",
          "items": {
           "type": "object",
           "x-gocdn-type": "StreamListen"
          },
          "type": "array",
          "x-description-zh": "监听列表:每项为端口与协议。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origin_port": {
          "description": "Origin port to connect to.",
          "type": "integer",
          "x-description-zh": "回源端口。"
         },
         "origins": {
          "description": "Origin list. Each item has an origin IP, a weight, and backup/down flags.",
          "items": {
           "type": "object",
           "x-gocdn-type": "StreamOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表:每项为源站 IP、权重与备用/下线标记。"
         },
         "proxy_protocol": {
          "description": "Whether to send a PROXY protocol header to the origin.",
          "type": "boolean",
          "x-description-zh": "是否向源站发送 PROXY protocol 头。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = new connections are dropped immediately (set by admin or billing; 512 in the snapshot when the user package has expired).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。"
         },
         "udp_responses": {
          "description": "UDP responses. 1-100 = end each UDP session after this many packets from the origin (instead of waiting for the UDP idle timeout); 0 = not set. Only for request/response traffic (DNS, probes); do not set it for games or voice that send many replies per request, or their sessions get cut short.",
          "type": "integer",
          "x-description-zh": "UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。"
         },
         "upid": {
          "description": "User package ID (empty = no quota check; empty falls back to tenant_id in the snapshot).",
          "type": "integer",
          "x-description-zh": "用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。"
         }
        },
        "required": [
         "listen",
         "origin_port",
         "origins"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create stream",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "创建四层转发"
   }
  },
  "/api/v2/streams/batch": {
   "post": {
    "operationId": "post-streams-batch",
    "parameters": [
     {
      "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Owner tenant when an admin creates on behalf of a tenant (required); ignored for tenant callers, where the owner is always the caller.",
       "type": "integer",
       "x-description-zh": "管理员代建时的属主租户(必填);租户调用时忽略,属主恒为本人。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "action": "set_enabled",
        "enabled": false,
        "ids": [
         1
        ]
       },
       "schema": {
        "properties": {
         "action": {
          "description": "Operation. set_enabled toggles enabled state, delete removes, set_groups replaces groups, update edits fields in bulk, create adds new ones, set_lines changes the CNAME's primary/backup line groups (admin only), set_cname_domain changes the CNAME root domain (admin only, host label kept).",
          "enum": [
           "set_enabled",
           "delete",
           "set_groups",
           "update",
           "create",
           "set_lines",
           "set_cname_domain"
          ],
          "type": "string",
          "x-description-zh": "操作类型:set_enabled 启停、delete 删除、set_groups 换分组、update 批量修改、create 批量新建、 set_lines 改接入名的主/备线路分组(仅管理员)、set_cname_domain 改接入名的根域(仅管理员,主机记录不变)。"
         },
         "backup_group_id": {
          "description": "Used by set_lines: backup line group; 0 clears it, omitted leaves it unchanged.",
          "type": "integer",
          "x-description-zh": "set_lines 用:备用线路分组;0 = 清空,不给 = 不动。"
         },
         "cname_domain_id": {
          "description": "Used by set_cname_domain: the new CNAME root domain.",
          "type": "integer",
          "x-description-zh": "set_cname_domain 用:新的接入根域。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "group_ids": {
          "description": "IDs of the forwarding groups this rule belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "所属转发分组 id 列表。"
         },
         "ids": {
          "description": "IDs of the forwarding rules to operate on, at most 100 per call (required by every action except create).",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的转发 id 列表,一次最多 100 条(create 以外的操作必填)。"
         },
         "items": {
          "description": "Used by create: the forwarding rules to create (up to 100), each shaped like the POST /streams request body.",
          "items": {
           "type": "object",
           "x-gocdn-type": "StreamWrite"
          },
          "type": "array",
          "x-description-zh": "create 用:要新建的转发(最多 100 条),每条同 POST /streams 的请求体。"
         },
         "node_group_id": {
          "description": "Used by set_lines: primary line group (required).",
          "type": "integer",
          "x-description-zh": "set_lines 用:主线路分组(必填)。"
         },
         "patch": {
          "description": "For batch update. Fields that are given are applied to every rule, with the same rules as a single update.",
          "type": "object",
          "x-description-zh": "批量 update 用:给了的字段改到每一条上,规则同单条修改。",
          "x-gocdn-type": "StreamPatch"
         },
         "region_id": {
          "description": "Used by set_lines: region; when given, both line groups must belong to it.",
          "type": "integer",
          "x-description-zh": "set_lines 用:区域;给了就校验主/备线路分组都属于它(不给不校验)。"
         }
        },
        "required": [
         "action"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch operate streams",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "批量操作四层转发"
   }
  },
  "/api/v2/streams/{id}": {
   "delete": {
    "operationId": "delete-streams-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete stream",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除四层转发"
   },
   "get": {
    "operationId": "get-streams-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get stream",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取四层转发"
   },
   "put": {
    "operationId": "put-streams-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "listen": [
         {
          "port": 30001
         }
        ],
        "name": "demo",
        "origin_port": 22,
        "origins": [
         {
          "host": "203.0.113.10"
         }
        ]
       },
       "schema": {
        "properties": {
         "acl": {
          "description": "Layer-4 access control. Rules match the source IP or CIDR in order and the first hit decides; if none match, default_action applies; deny drops the connection immediately.",
          "type": "object",
          "x-description-zh": "四层访问控制:逐条按来源 IP/网段匹配,首条命中定结果,都不中按 default_action;deny 直接断开连接。",
          "x-gocdn-type": "StreamAcl"
         },
         "balance": {
          "description": "Load balancing method. rr is round robin, ip_hash hashes the source IP, least_conn picks the fewest connections, random picks at random.",
          "enum": [
           "rr",
           "ip_hash",
           "least_conn",
           "random"
          ],
          "type": "object",
          "x-description-zh": "负载方式:rr 轮询、ip_hash 按来源 IP 哈希、least_conn 最少连接、random 随机。",
          "x-gocdn-type": "StreamBalance"
         },
         "cname": {
          "description": "Access name (CNAME). Users point their domain to fqdn with a CNAME record; the platform generates its DNS records from the node group. null when there is no access name.",
          "type": "object",
          "x-description-zh": "接入名(CNAME):用户把域名 CNAME 到 fqdn,解析由平台按节点组生成;没有接入名时为 null。",
          "x-gocdn-type": "CnameBinding"
         },
         "conn_limit": {
          "description": "Per-IP concurrent connection limit; 0 = unlimited.",
          "type": "integer",
          "x-description-zh": "单 IP 并发连接上限,0 = 不限。"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "expected_updated_at": {
          "description": "Optimistic lock (used on update) - the updated_at of the resource as the caller read it. If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check; ignored on create.",
          "type": "string",
          "x-description-zh": "乐观锁(修改时用):调用方读到的该资源 updated_at。与库里当前值不等则回 409 stale_version、不保存;不带则不检查;创建时忽略。"
         },
         "group_ids": {
          "description": "IDs of the forwarding groups this rule belongs to.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "所属转发分组 id 列表。"
         },
         "listen": {
          "description": "Listener list. Each item is a port and a protocol.",
          "items": {
           "type": "object",
           "x-gocdn-type": "StreamListen"
          },
          "type": "array",
          "x-description-zh": "监听列表:每项为端口与协议。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "origin_port": {
          "description": "Origin port to connect to.",
          "type": "integer",
          "x-description-zh": "回源端口。"
         },
         "origins": {
          "description": "Origin list. Each item has an origin IP, a weight, and backup/down flags.",
          "items": {
           "type": "object",
           "x-gocdn-type": "StreamOrigin"
          },
          "type": "array",
          "x-description-zh": "源站列表:每项为源站 IP、权重与备用/下线标记。"
         },
         "proxy_protocol": {
          "description": "Whether to send a PROXY protocol header to the origin.",
          "type": "boolean",
          "x-description-zh": "是否向源站发送 PROXY protocol 头。"
         },
         "stop_code": {
          "description": "0 = normal; non-zero = new connections are dropped immediately (set by admin or billing; 512 in the snapshot when the user package has expired).",
          "type": "integer",
          "x-description-zh": "0 = 正常;非 0 = 新连接直接断开(管理员/计费设置;用户套餐到期时快照里为 512)。"
         },
         "udp_responses": {
          "description": "UDP responses. 1-100 = end each UDP session after this many packets from the origin (instead of waiting for the UDP idle timeout); 0 = not set. Only for request/response traffic (DNS, probes); do not set it for games or voice that send many replies per request, or their sessions get cut short.",
          "type": "integer",
          "x-description-zh": "UDP 应答数:1~100 = 每个 UDP 会话收到源站这么多个包就结束(不再等 UDP 空闲超时),0 = 不设。只适合一问一答(DNS、探测);一问多答的游戏/语音别设,会被提前断开。"
         },
         "upid": {
          "description": "User package ID (empty = no quota check; empty falls back to tenant_id in the snapshot).",
          "type": "integer",
          "x-description-zh": "用户套餐 id(空 = 不核配额;快照里空时取 tenant_id)。"
         }
        },
        "required": [
         "listen",
         "origin_port",
         "origins"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update stream",
    "tags": [
     "streams"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改四层转发"
   }
  },
  "/api/v2/tamper-guard/pages": {
   "get": {
    "operationId": "get-tamper-guard-pages",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only this site; an empty list when the site is not the caller's.",
      "in": "query",
      "name": "site_id",
      "schema": {
       "description": "Only this site; an empty list when the site is not the caller's.",
       "type": "integer",
       "x-description-zh": "只看该网站;不属于调用方租户时为空列表。"
      }
     },
     {
      "description": "Fuzzy search by site domain or page path (case-insensitive).",
      "in": "query",
      "name": "q",
      "schema": {
       "description": "Fuzzy search by site domain or page path (case-insensitive).",
       "type": "string",
       "x-description-zh": "按网站域名或页面路径模糊搜索(不区分大小写)。"
      }
     },
     {
      "description": "When true, only pages with a detected tampering (a non-empty last change).",
      "in": "query",
      "name": "changed",
      "schema": {
       "description": "When true, only pages with a detected tampering (a non-empty last change).",
       "type": "boolean",
       "x-description-zh": "为 true 只看检出过篡改的页面(最近变化不为空的页)。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List protected pages of all sites",
    "tags": [
     "tamper-guard"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出全部网站的防篡改保护页面"
   }
  },
  "/api/v2/upload-scan-settings": {
   "get": {
    "operationId": "get-upload-scan-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get upload scan settings",
    "tags": [
     "upload-scan-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取上传防护设置"
   },
   "put": {
    "operationId": "put-upload-scan-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "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"
       },
       "schema": {
        "properties": {
         "action": {
          "description": "On a hit - block, log only, or observe for 3 days (log only, then block); dangerous files have no observation period.",
          "enum": [
           "block",
           "log",
           "observe"
          ],
          "type": "string",
          "x-description-zh": "命中后:block 拦截、log 只记录、observe 先观察 3 天(期间只记录,之后拦截);危险文件不设观察期。"
         },
         "disguise": {
          "description": "Disguised file detection (image extension but the magic bytes are a script or an executable).",
          "type": "boolean",
          "x-description-zh": "伪装文件检测(扩展名为图片、文件头魔数为脚本或可执行程序)。"
         },
         "double_ext": {
          "description": "Double extension detection (e.g. a.php.jpg, a.asp;.jpg).",
          "type": "boolean",
          "x-description-zh": "双扩展名检测(如 a.php.jpg、a.asp;.jpg)。"
         },
         "enabled": {
          "description": "Master switch; false = no site is scanned.",
          "type": "boolean",
          "x-description-zh": "总开关;false = 所有站点都不扫描。"
         },
         "enhanced": {
          "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; enhanced items still work but are read-only) or basic (not purchased or past the buffer; enhanced items are off, settings kept); ignored on update.",
          "enum": [
           "full",
           "readonly",
           "basic"
          ],
          "readOnly": true,
          "type": "string",
          "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;增强项照常生效但只读)、basic 未开通或缓冲已过(增强项不生效,设置保留);修改时忽略。"
         },
         "exceptions": {
          "description": "Exceptions - skip the signature when the site and path prefix match (empty sig = the path is not scanned). Entries that tenants added by marking false positives (source=false_positive) must be sent back unchanged on replace, otherwise they are overwritten.",
          "items": {
           "type": "object",
           "x-gocdn-type": "UploadScanException"
          },
          "type": "array",
          "x-description-zh": "例外:网站与路径前缀命中时跳过该特征(sig 空 = 该路径不扫描)。租户标记误报加的条目(source=false_positive)整体替换时请原样带回,否则被覆盖。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared with CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(配置 node.global 的版本,与 CC/WAF 设置共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "exts": {
          "description": "Dangerous extensions (lowercase, without the dot); defaults to php phtml jsp jspx asp aspx ashx cer war sh cgi when omitted. A site may override with waf.upload_exts.",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "危险扩展名(小写、不带点);没带回缺省 php phtml jsp jspx asp aspx ashx cer war sh cgi。站点 waf.upload_exts 可覆盖。"
         },
         "max_file_mb": {
          "description": "Per-file scan limit in MB (default 20); larger files only get the extension check and are handled per oversize.",
          "type": "integer",
          "x-description-zh": "单个文件扫描上限(MB,缺省 20);超出的只查扩展名,按 oversize 处置。"
         },
         "observe_until": {
          "description": "End of the observation period (set when action is observe); ignored on update, written by the server.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "观察期截止(action 为 observe 时有值);修改时忽略,由服务端写。"
         },
         "on_parse_error": {
          "description": "On multipart parse errors (bad delimiter, oversized header, truncated body, too many parts) - block or allow (pass and log); default block.",
          "enum": [
           "allow",
           "block"
          ],
          "type": "string",
          "x-description-zh": "multipart 解析出错(定界符不对、头过大、体被截断、段数超限等)时:block 拦截、allow 放行并记录(缺省 block)。"
         },
         "on_timeout": {
          "description": "On scan timeout (or failure to read the body) - allow (pass and log) or block (default allow).",
          "enum": [
           "allow",
           "block"
          ],
          "type": "string",
          "x-description-zh": "扫描超时(或读请求体失败)时:allow 放行并记录、block 拦截(缺省 allow)。"
         },
         "oversize": {
          "description": "Files over the limit - allow (pass and log) or block.",
          "enum": [
           "allow",
           "block"
          ],
          "type": "string",
          "x-description-zh": "超过单文件上限:allow 放行并记录、block 拦截。"
         },
         "sha256": {
          "description": "Local sha256 blocklist (WAF enhanced).",
          "items": {
           "type": "object"
          },
          "type": "array",
          "x-description-zh": "本主控 sha256 黑名单(WAF 增强)。"
         },
         "sig": {
          "description": "Webshell signatures (WAF enhanced).",
          "type": "boolean",
          "x-description-zh": "木马 / Webshell 特征(WAF 增强)。"
         },
         "timeout_s": {
          "description": "Scan timeout per request in seconds (default 2).",
          "type": "integer",
          "x-description-zh": "每个请求的扫描超时(秒,缺省 2)。"
         },
         "updated_at": {
          "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略。"
         },
         "virus": {
          "description": "Antivirus (ClamAV, WAF enhanced) - off, mem4g (nodes with at least 4 GB memory) or all nodes.",
          "enum": [
           "off",
           "mem4g",
           "all"
          ],
          "type": "string",
          "x-description-zh": "病毒库(ClamAV,WAF 增强):off 关、mem4g 内存 ≥4GB 的节点、all 所有节点。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update upload scan settings",
    "tags": [
     "upload-scan-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改上传防护设置"
   }
  },
  "/api/v2/upload-scan-stats": {
   "get": {
    "operationId": "get-upload-scan-stats",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get upload scan stats",
    "tags": [
     "upload-scan-stats"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取上传扫描统计"
   }
  },
  "/api/v2/url-guard-settings": {
   "get": {
    "operationId": "get-url-guard-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get network-wide URL protection settings",
    "tags": [
     "url-guard-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取全网 URL 防护设置"
   },
   "put": {
    "operationId": "put-url-guard-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "action": "challenge",
        "baseline_ratio": 5,
        "enabled": true,
        "hold_s": 600,
        "kind": "js",
        "max_per_site": 20,
        "qps": 300,
        "rate": 20
       },
       "schema": {
        "properties": {
         "action": {
          "description": "Action on the URL once triggered - challenge, block or per-IP rate limit.",
          "enum": [
           "challenge",
           "block",
           "limit"
          ],
          "type": "string",
          "x-description-zh": "触发后对该 URL 的动作:挑战验证、拦截、每 IP 限速。"
         },
         "baseline_ratio": {
          "description": "Triggering also requires this many times the usual level (usual = the URL's average QPS over the past hour, excluding the last minute). The panel asks for at least 1, default 5; 0 = ignore the multiple (legacy configs lack the field and keep the old rule). Applies to new triggers only - renewing an active rule looks at QPS alone. Omit on update to keep the stored value.",
          "type": "integer",
          "x-description-zh": "触发还须达到平时的这么多倍(平时 = 该 URL 过去 1 小时的平均 QPS,不含最近 1 分钟);面板最小填 1,缺省 5;0 = 不看倍数(旧配置没有该字段,按 0 沿用原判定)。只管新触发,已在途规则续期只看 QPS。修改时不带则保持原值。"
         },
         "enabled": {
          "description": "Global default switch, used by sites that do not set their own.",
          "type": "boolean",
          "x-description-zh": "全局默认开关;站点未单独设置时按它。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "gate": {
          "description": "WAF enhanced (waf_enhanced) gate - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; still effective, settings read-only), basic (not purchased or fallen back, nothing is pushed); ignored on update.",
          "enum": [
           "full",
           "readonly",
           "basic"
          ],
          "readOnly": true,
          "type": "string",
          "x-description-zh": "WAF 增强(waf_enhanced)判定档:full 开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;照常生效、设置只读)、basic 未开通或已回落(不下发);修改时忽略。"
         },
         "gate_expired_at": {
          "description": "Administrator responses with gate_reason=expired only - when the platform WAF Enhanced license expired; not present in tenant responses.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "仅管理员响应且 gate_reason=expired 时带:平台 WAF 增强授权的到期时刻;租户响应不带。"
         },
         "gate_owner": {
          "description": "The owner of the site, in administrator responses only; tenant responses carry no one else's information.",
          "readOnly": true,
          "type": "object",
          "x-description-zh": "站点属主,仅管理员响应带;租户响应不带别人的信息。",
          "x-gocdn-type": "WafGateOwner"
         },
         "gate_packages": {
          "description": "Administrator responses only - names of the owner's unexpired packages (at most 20); not present in tenant responses.",
          "items": {
           "type": "string"
          },
          "readOnly": true,
          "type": "array",
          "x-description-zh": "仅管理员响应带:属主名下未到期的套餐名(最多 20 个);租户响应不带。"
         },
         "gate_reason": {
          "description": "Why WAF Enhanced (waf_enhanced) is not in effect; absent when gate is full or readonly. package = the platform is licensed but the owner has no unexpired package that includes WAF Enhanced; license = the platform has not enabled it (never licensed, revoked by the provider, or the license was disabled); expired = the platform license has expired and its read-only buffer period (License.readonly_days, default 7 days) has passed, so it fell back to basic.",
          "enum": [
           "package",
           "license",
           "expired"
          ],
          "readOnly": true,
          "type": "object",
          "x-description-zh": "WAF 增强(waf_enhanced)没生效的原因,gate 为 full 或 readonly 时不带。package = 平台已授权但属主没有未到期且含 WAF 增强的套餐;license = 平台没开通(从未授权、服务商撤销、授权被停用);expired = 平台授权已到期且只读缓冲期(License.readonly_days,缺省 7 天)已过,已回落基础。",
          "x-gocdn-type": "WafGateReason"
         },
         "hold_s": {
          "description": "Seconds the rule is held; it is renewed while still over the threshold and lapses once traffic drops.",
          "type": "integer",
          "x-description-zh": "规则保持秒数;到期前仍超阈会自动续期,降下来就到期撤销。"
         },
         "kind": {
          "description": "Challenge type for action=challenge (default js); must be empty for other actions.",
          "enum": [
           "js",
           "redirect",
           "delay_jump",
           "cookie",
           "captcha",
           "slide",
           "click",
           "rotate"
          ],
          "type": "string",
          "x-description-zh": "action=challenge 的挑战类型,缺省 js;其它动作须为空。"
         },
         "max_per_site": {
          "description": "Max rules in effect at the same time per site.",
          "type": "integer",
          "x-description-zh": "同一站点同时生效的规则条数上限。"
         },
         "qps": {
          "description": "Trigger only when the network-wide total QPS of a URL is at least this (and at least baseline_ratio times its usual level).",
          "type": "integer",
          "x-description-zh": "某 URL 全网合计 QPS 不低于它(且达到平时的 baseline_ratio 倍)才触发。"
         },
         "rate": {
          "description": "Max requests per IP per 10 seconds for action=limit; must be 0 for other actions.",
          "type": "integer",
          "x-description-zh": "action=limit 的每 IP 每 10 秒最多请求数;其它动作须为 0。"
         },
         "updated_at": {
          "description": "Version in the response (null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "响应里的版本(没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
         }
        },
        "required": [
         "action",
         "enabled",
         "hold_s",
         "max_per_site",
         "qps"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update network-wide URL protection settings",
    "tags": [
     "url-guard-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改全网 URL 防护设置"
   }
  },
  "/api/v2/url-guard/active": {
   "get": {
    "operationId": "get-url-guard-active",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List URL protections in effect",
    "tags": [
     "url-guard"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出生效中的全网 URL 防护"
   }
  },
  "/api/v2/user-packages": {
   "get": {
    "operationId": "get-user-packages",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     },
     {
      "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
       "type": "string",
       "x-description-zh": "只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。"
      }
     },
     {
      "description": "Only list purchased packages of this base package.",
      "in": "query",
      "name": "package_id",
      "schema": {
       "description": "Only list purchased packages of this base package.",
       "type": "integer",
       "x-description-zh": "只列这个基础套餐的用户套餐。"
      }
     },
     {
      "description": "Only list purchased packages expiring within this many days (including already expired ones).",
      "in": "query",
      "name": "expire_within_days",
      "schema": {
       "description": "Only list purchased packages expiring within this many days (including already expired ones).",
       "type": "integer",
       "x-description-zh": "只列这么多天内到期(含已到期)的用户套餐。"
      }
     },
     {
      "description": "Purchased package name contains (% and _ match literally).",
      "in": "query",
      "name": "name",
      "schema": {
       "description": "Purchased package name contains (% and _ match literally).",
       "type": "string",
       "x-description-zh": "用户套餐名称包含(% _ 按字面匹配)。"
      }
     },
     {
      "description": "true lists only purchased packages with individually edited quotas or not following the base package; false lists only those following it unchanged.",
      "in": "query",
      "name": "customized",
      "schema": {
       "description": "true lists only purchased packages with individually edited quotas or not following the base package; false lists only those following it unchanged.",
       "type": "boolean",
       "x-description-zh": "true 只列单独改过额度或不跟随基础套餐的已购套餐,false 只列跟随中且没单独改过的。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List purchased packages",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出用户套餐"
   },
   "post": {
    "operationId": "post-user-packages",
    "parameters": [
     {
      "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
      "in": "query",
      "name": "tenant_id",
      "schema": {
       "description": "Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data",
       "type": "integer",
       "x-description-zh": "仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "duration": "month",
        "package_id": 1
       },
       "schema": {
        "properties": {
         "dry_run": {
          "description": "Quote only, do not save.",
          "type": "boolean",
          "x-description-zh": "只报价不落库"
         },
         "duration": {
          "description": "Duration: month/quarter/year (adds 1/3/12 months; at month end the last day of the target month is used).",
          "enum": [
           "month",
           "quarter",
           "year"
          ],
          "type": "string",
          "x-description-zh": "时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。"
         },
         "end_at": {
          "description": "Expiry time of the purchased package.",
          "type": "string",
          "x-description-zh": "套餐到期时间。"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "package_id": {
          "description": "Base package id.",
          "type": "integer",
          "x-description-zh": "基础套餐 id"
         }
        },
        "required": [
         "package_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Purchase package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "购买用户套餐"
   }
  },
  "/api/v2/user-packages/{id}": {
   "delete": {
    "operationId": "delete-user-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete purchased package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "删除用户套餐"
   },
   "get": {
    "operationId": "get-user-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get purchased package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "获取用户套餐"
   },
   "put": {
    "operationId": "put-user-packages-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "name": "主站套餐"
       },
       "schema": {
        "properties": {
         "backup_group_id": {
          "description": "Backup node group; null = none.",
          "type": "integer",
          "x-description-zh": "备用线路分组;null = 没有"
         },
         "bandwidth_mbps": {
          "description": "Bandwidth in Mbps, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "带宽 Mbps,-1 不限"
         },
         "cname_domain_id": {
          "description": "CNAME root domain; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "接入根域(CNAME 域名);null = 套餐不绑线路"
         },
         "cname_hostname": {
          "description": "Host record of the shared access name (used by sites and streams in per-package mode); empty = none yet.",
          "type": "string",
          "x-description-zh": "共用接入名的主机记录(按套餐生成时下属站点/转发共用);空 = 还没有"
         },
         "cname_mode": {
          "description": "CNAME mode. site = one access name per site or stream; package = sites and streams of a purchased package share one access name.",
          "enum": [
           "site",
           "package"
          ],
          "type": "object",
          "x-description-zh": "CNAME 模式:site = 按站点生成(每个站点/四层转发各一个接入名);package = 按套餐生成(已售套餐下的站点/四层转发共用一个接入名)。",
          "x-gocdn-type": "PackageCnameMode"
         },
         "connections": {
          "description": "Concurrent connections, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "并发连接数,-1 不限"
         },
         "custom_cc_rule": {
          "description": "Allows custom CC rules.",
          "type": "boolean",
          "x-description-zh": "可自定义 CC 规则"
         },
         "domains": {
          "description": "Number of domains (each IP site counts as 1), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "域名数(IP 站每站占 1),-1 不限"
         },
         "end_at": {
          "description": "Expiry time of the purchased package.",
          "type": "string",
          "x-description-zh": "套餐到期时间。"
         },
         "follow_base": {
          "description": "Follows the base package; quota changes on the base package are synced here automatically (except fields in overrides).",
          "readOnly": true,
          "type": "boolean",
          "x-description-zh": "跟随基础套餐:改基础套餐的配额类字段时自动同步到本套餐(overrides 里的字段除外)"
         },
         "http_ports": {
          "description": "Number of non-standard HTTP/HTTPS ports (other than 80/443), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "HTTP/HTTPS 非标端口数(80/443 之外),-1 不限"
         },
         "ip_num": {
          "description": "Number of selectable IPs (\"My IPs\"), -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "可选 IP 数(「我的 IP」),-1 不限"
         },
         "ip_pool_id": {
          "description": "IP pool used to provision IP sites (IP product line); null = not provisioned.",
          "type": "integer",
          "x-description-zh": "开通 IP 站点用的 IP 池(IP 产品线);null = 不开通"
         },
         "ip_site_port": {
          "description": "IP-site ports: distinct ports across all IP sites of the package (80/443 included), -1 = unlimited; IP-site ports do not count toward non-standard ports.",
          "type": "integer",
          "x-description-zh": "IP 站端口数:套餐下全部 IP 站点去重后的端口个数(含 80/443),-1 不限;IP 站端口不占非标端口数"
         },
         "l2": {
          "description": "Includes tiered origin (tenant switch of the paid feature l2): tenants can turn on tiered origin for sites, and nodes use it, only while the master license l2 is active; existing packages are false (on upgrade, purchased packages of tenants already using tiered origin are set to true).",
          "type": "boolean",
          "x-description-zh": "含分层回源(付费项 l2 的租户开关):租户还要主控授权的分层回源已开通,才能给网站打开分层回源、节点才按它回源;存量套餐为 false(升级时已开分层回源的租户,其已售套餐置 true)"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "node_group_id": {
          "description": "Primary node group; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "主线路分组;null = 套餐不绑线路"
         },
         "price_month_cents": {
          "description": "Monthly price locked at purchase.",
          "type": "integer",
          "x-description-zh": "购买时锁定的月价"
         },
         "price_quarter_cents": {
          "description": "Quarterly price locked at purchase.",
          "type": "integer",
          "x-description-zh": "锁定季价"
         },
         "price_year_cents": {
          "description": "Yearly price locked at purchase.",
          "type": "integer",
          "x-description-zh": "锁定年价"
         },
         "region_id": {
          "description": "Region; null = the package binds no lines.",
          "type": "integer",
          "x-description-zh": "区域;null = 套餐不绑线路"
         },
         "reset_to_base": {
          "description": "Admin only; true = reset quota fields to the base package values, clear overrides and follow again (cannot be combined with other fields).",
          "type": "boolean",
          "x-description-zh": "仅管理员:true = 配额类字段恢复为基础套餐的值、清空 overrides 并恢复跟随(不能与其它字段同时给)"
         },
         "stream_ports": {
          "description": "Number of TCP/UDP forwarding ports, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "四层转发端口数,-1 不限"
         },
         "traffic_gb": {
          "description": "Traffic in GB per billing cycle, -1 = unlimited.",
          "type": "integer",
          "x-description-zh": "每计费周期流量 GB,-1 不限"
         },
         "waf_enhanced": {
          "description": "Includes WAF Enhanced (tenant switch of the paid feature waf_enhanced): tenants can use standard/strict levels, big screen, deep Bot, anti-tamper and so on only while the master license WAF Enhanced is not degraded; existing packages are false.",
          "type": "boolean",
          "x-description-zh": "含 WAF 增强(付费项 waf_enhanced 的租户开关):租户还要主控授权的 WAF 增强未降级才能用标准/严格等级、大屏、Bot 深度、防篡改等;存量套餐为 false"
         },
         "websocket": {
          "description": "Allows WebSocket.",
          "type": "boolean",
          "x-description-zh": "可开 WebSocket"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update purchased package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改用户套餐"
   }
  },
  "/api/v2/user-packages/{id}/changes": {
   "post": {
    "operationId": "post-user-packages-id-changes",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "package_id": 2
       },
       "schema": {
        "properties": {
         "dry_run": {
          "description": "Quote only, do not save.",
          "type": "boolean",
          "x-description-zh": "只报价不落库"
         },
         "package_id": {
          "description": "Base package id.",
          "type": "integer",
          "x-description-zh": "基础套餐 id"
         }
        },
        "required": [
         "package_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Change package (upgrade or downgrade)",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "更换套餐(升级/降级)"
   }
  },
  "/api/v2/user-packages/{id}/ips": {
   "get": {
    "operationId": "get-user-packages-id-ips",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "My IPs",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "我的 IP"
   },
   "post": {
    "operationId": "post-user-packages-id-ips",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "ip_ids": {
          "description": "IDs of the pool IPs to select.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要选的池内 IP ID 列表。"
         }
        },
        "required": [
         "ip_ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Select IPs",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "选择 IP"
   }
  },
  "/api/v2/user-packages/{id}/ips/{ip_id}": {
   "delete": {
    "operationId": "delete-user-packages-id-ips-ip-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "ip_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Remove selected IP",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "移除已选 IP"
   },
   "put": {
    "operationId": "put-user-packages-id-ips-ip-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "ip_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         }
        },
        "required": [
         "remark"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update note of selected IP",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "修改已选 IP 的备注"
   }
  },
  "/api/v2/user-packages/{id}/node-groups": {
   "get": {
    "operationId": "get-user-packages-id-node-groups",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Node groups of a purchased package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "用户套餐的线路分组"
   }
  },
  "/api/v2/user-packages/{id}/renewals": {
   "post": {
    "operationId": "post-user-packages-id-renewals",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "duration": "month"
       },
       "schema": {
        "properties": {
         "dry_run": {
          "description": "Quote only, do not save.",
          "type": "boolean",
          "x-description-zh": "只报价不落库"
         },
         "duration": {
          "description": "Duration: month/quarter/year (adds 1/3/12 months; at month end the last day of the target month is used).",
          "enum": [
           "month",
           "quarter",
           "year"
          ],
          "type": "string",
          "x-description-zh": "时长:月/季/年(加 1/3/12 个月,月末按当月最后一天)。"
         }
        },
        "required": [
         "duration"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Renew purchased package",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "续费用户套餐"
   }
  },
  "/api/v2/user-packages/{id}/upgrades": {
   "get": {
    "operationId": "get-user-packages-id-upgrades",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List purchased upgrade packs",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "列出已购升级包"
   },
   "post": {
    "operationId": "post-user-packages-id-upgrades",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "amount": 1,
        "upgrade_id": 1
       },
       "schema": {
        "properties": {
         "amount": {
          "description": "Number of units, default 1.",
          "type": "integer",
          "x-description-zh": "份数,默认 1"
         },
         "dry_run": {
          "description": "Quote only, do not save.",
          "type": "boolean",
          "x-description-zh": "只报价不落库"
         },
         "upgrade_id": {
          "description": "Id of the upgrade pack to buy.",
          "type": "integer",
          "x-description-zh": "要加购的升级包 id。"
         }
        },
        "required": [
         "upgrade_id"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Buy upgrade pack",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "加购升级包"
   }
  },
  "/api/v2/user-packages/{id}/upgrades/{upgrade_id}": {
   "delete": {
    "operationId": "delete-user-packages-id-upgrades-upgrade-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "upgrade_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Number of units to reduce; omitted = remove the whole item.",
      "in": "query",
      "name": "amount",
      "schema": {
       "description": "Number of units to reduce; omitted = remove the whole item.",
       "type": "integer",
       "x-description-zh": "减少的份数;不带 = 整项移除。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Reduce or remove purchased upgrade pack",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "减少或移除已购升级包"
   }
  },
  "/api/v2/user-packages/{id}/usage": {
   "get": {
    "operationId": "get-user-packages-id-usage",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Purchased package usage",
    "tags": [
     "user-packages"
    ],
    "x-gocdn-auth": "admin-conditional",
    "x-summary-zh": "用户套餐用量"
   }
  },
  "/api/v2/users": {
   "get": {
    "operationId": "get-users",
    "parameters": [
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     },
     {
      "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
      "in": "query",
      "name": "ids",
      "schema": {
       "description": "Only list these IDs: comma-separated positive integers, at most 200 after deduplication (same as the page_size limit; more returns 400); an empty value is the same as omitting it. Combined with other filters as an intersection; IDs you cannot see are silently left out. Pagination is unchanged: set page_size to at least the number of IDs to get them in one page",
       "type": "string",
       "x-description-zh": "只列这些 id:逗号分隔的正整数,去重后至多 200 个(同 page_size 上限,超了 400);空串等同不传。与其他条件取交集;看不到的 id 不返回也不报错。分页照旧,一次取回要把 page_size 设成不少于 id 个数。"
      }
     },
     {
      "description": "Email",
      "in": "query",
      "name": "email",
      "schema": {
       "description": "Email",
       "type": "string",
       "x-description-zh": "邮箱"
      }
     },
     {
      "description": "Phone number",
      "in": "query",
      "name": "phone",
      "schema": {
       "description": "Phone number",
       "type": "string",
       "x-description-zh": "手机号"
      }
     },
     {
      "description": "Username",
      "in": "query",
      "name": "username",
      "schema": {
       "description": "Username",
       "type": "string",
       "x-description-zh": "用户名"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List users",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出用户"
   },
   "post": {
    "operationId": "post-users",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "login_ip_allow": {
          "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
         },
         "login_verify": {
          "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
          "enum": [
           "none",
           "email",
           "sms"
          ],
          "type": "object",
          "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
          "x-gocdn-type": "LoginVerify"
         },
         "password": {
          "description": "Required on create; on update, providing it resets the password and revokes all sessions of the user",
          "type": "string",
          "x-description-zh": "创建时必填;修改时给了即重设口令并吊销该用户全部会话。"
         },
         "phone": {
          "description": "Phone number",
          "type": "string",
          "x-description-zh": "手机号"
         },
         "role": {
          "description": "Account role: admin or tenant",
          "enum": [
           "admin",
           "tenant"
          ],
          "type": "string",
          "x-description-zh": "账号角色:admin 管理员,tenant 租户。"
         },
         "totp_enabled": {
          "description": "Whether TOTP is enabled",
          "type": "boolean",
          "x-description-zh": "是否已启用动态口令。"
         },
         "username": {
          "description": "Username",
          "type": "string",
          "x-description-zh": "用户名"
         }
        },
        "required": [
         "username"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create user",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "创建用户"
   }
  },
  "/api/v2/users/batch": {
   "post": {
    "operationId": "post-users-batch",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "action": {
          "description": "enable, disable or delete.",
          "enum": [
           "enable",
           "disable",
           "delete"
          ],
          "type": "string",
          "x-description-zh": "enable 启用、disable 停用、delete 删除。"
         },
         "ids": {
          "description": "User IDs to operate on, 1 to 100 per call.",
          "items": {
           "type": "integer"
          },
          "type": "array",
          "x-description-zh": "要操作的用户 id,一次 1~100 个。"
         }
        },
        "required": [
         "action",
         "ids"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Batch enable, disable or delete users",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "批量启停或删除用户"
   }
  },
  "/api/v2/users/{id}": {
   "delete": {
    "operationId": "delete-users-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete user",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除用户"
   },
   "get": {
    "operationId": "get-users-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get user",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取用户"
   },
   "put": {
    "operationId": "put-users-id",
    "parameters": [
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "email": {
          "description": "Email",
          "type": "string",
          "x-description-zh": "邮箱"
         },
         "enabled": {
          "description": "Whether enabled",
          "type": "boolean",
          "x-description-zh": "是否启用"
         },
         "login_ip_allow": {
          "description": "Login IP allowlist (IPs or CIDRs); empty means no restriction",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "登录 IP 白名单(IP 或 CIDR);空 = 不限。"
         },
         "login_verify": {
          "description": "Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound)",
          "enum": [
           "none",
           "email",
           "sms"
          ],
          "type": "object",
          "x-description-zh": "登录二次验证:none 不要求;email / sms 登录时还要邮件/短信验证码(须平台允许且已绑定对应地址)。",
          "x-gocdn-type": "LoginVerify"
         },
         "password": {
          "description": "Required on create; on update, providing it resets the password and revokes all sessions of the user",
          "type": "string",
          "x-description-zh": "创建时必填;修改时给了即重设口令并吊销该用户全部会话。"
         },
         "phone": {
          "description": "Phone number",
          "type": "string",
          "x-description-zh": "手机号"
         },
         "role": {
          "description": "Account role: admin or tenant",
          "enum": [
           "admin",
           "tenant"
          ],
          "type": "string",
          "x-description-zh": "账号角色:admin 管理员,tenant 租户。"
         },
         "totp_enabled": {
          "description": "Whether TOTP is enabled",
          "type": "boolean",
          "x-description-zh": "是否已启用动态口令。"
         },
         "username": {
          "description": "Username",
          "type": "string",
          "x-description-zh": "用户名"
         }
        },
        "required": [
         "username"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update user",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改用户"
   }
  },
  "/api/v2/users/{user_id}/account": {
   "get": {
    "operationId": "get-users-user-id-account",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get user account",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "查看用户账户"
   },
   "put": {
    "operationId": "put-users-user-id-account",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "freeze_reason": "风控核查",
        "frozen": true
       },
       "schema": {
        "properties": {
         "freeze_reason": {
          "description": "Freeze reason; empty if not frozen.",
          "type": "string",
          "x-description-zh": "冻结原因;未冻结为空。"
         },
         "frozen": {
          "description": "Whether the account is frozen; deductions are rejected while frozen.",
          "type": "boolean",
          "x-description-zh": "是否已冻结;冻结后扣款一律被拒。"
         }
        },
        "required": [
         "frozen"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Freeze or unfreeze user account",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "冻结或解冻用户账户"
   }
  },
  "/api/v2/users/{user_id}/api-keys": {
   "get": {
    "operationId": "get-users-user-id-api-keys",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "description": "Page number, starting from 1",
      "in": "query",
      "name": "page",
      "schema": {
       "default": 1,
       "description": "Page number, starting from 1",
       "type": "integer",
       "x-description-zh": "页码,从 1 开始。"
      }
     },
     {
      "description": "Items per page",
      "in": "query",
      "name": "page_size",
      "schema": {
       "default": 20,
       "description": "Items per page",
       "type": "integer",
       "x-description-zh": "每页条数。"
      }
     },
     {
      "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
      "in": "query",
      "name": "sort",
      "schema": {
       "description": "Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id`",
       "example": "-created_at",
       "type": "string",
       "x-description-zh": "排序字段,逗号分隔,前缀 `-` 表示降序,如 `-created_at,id`。"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "List a user's API keys",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "列出指定用户的 API Key"
   },
   "post": {
    "operationId": "post-users-user-id-api-keys",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "properties": {
         "allow_ips": {
          "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
          "type": "object",
          "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
          "x-gocdn-type": "ApiKeyAllowIps"
         },
         "expires_at": {
          "description": "Expires at",
          "type": "string",
          "x-description-zh": "过期时间"
         },
         "name": {
          "description": "Name",
          "type": "string",
          "x-description-zh": "名称"
         },
         "scopes": {
          "description": "Granted scopes, same values as scopes at creation",
          "items": {
           "type": "string"
          },
          "type": "array",
          "x-description-zh": "授权范围,取值同创建时的 scopes。"
         }
        },
        "required": [
         "name",
         "scopes"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Create an API key for a user",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "为指定用户开通 API Key"
   }
  },
  "/api/v2/users/{user_id}/api-keys/{id}": {
   "delete": {
    "operationId": "delete-users-user-id-api-keys-id",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Delete a user's API key",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "删除指定用户的 API Key"
   },
   "put": {
    "operationId": "put-users-user-id-api-keys-id",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "reset": true
       },
       "schema": {
        "properties": {
         "allow_ips": {
          "description": "Caller IP allowlist (single IPs only, at most 200); empty means no restriction. Calls from other IPs get 401 as invalid credentials",
          "type": "object",
          "x-description-zh": "调用 IP 白名单(只收单个 IP,最多 200 个);空 = 不限。不在名单里的调用按凭据无效回 401。",
          "x-gocdn-type": "ApiKeyAllowIps"
         },
         "reset": {
          "description": "When true, issue a new key; the old one stops working at once",
          "type": "boolean",
          "x-description-zh": "为 true 时换新 key,旧 key 立即失效。"
         }
        },
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update a user's API key IP allowlist or reset it",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "改指定用户 API Key 的 IP 白名单或重置"
   }
  },
  "/api/v2/users/{user_id}/recharges": {
   "post": {
    "operationId": "post-users-user-id-recharges",
    "parameters": [
     {
      "in": "path",
      "name": "user_id",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "amount_cents": 10000,
        "direction": "credit",
        "remark": "线下转账"
       },
       "schema": {
        "properties": {
         "amount_cents": {
          "description": "Amount in cents; must be a positive integer.",
          "type": "integer",
          "x-description-zh": "金额(分),须为正整数。"
         },
         "direction": {
          "default": "credit",
          "description": "credit = recharge (default), debit = deduct.",
          "enum": [
           "credit",
           "debit"
          ],
          "type": "string",
          "x-description-zh": "credit 充值(缺省)、debit 扣款。"
         },
         "remark": {
          "description": "Remark",
          "type": "string",
          "x-description-zh": "备注"
         }
        },
        "required": [
         "amount_cents"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Recharge or deduct user balance",
    "tags": [
     "users"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "给用户充值或扣款"
   }
  },
  "/api/v2/verify-codes": {
   "post": {
    "operationId": "post-verify-codes",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "channel": "email",
        "purpose": "bind",
        "target": "alice@example.com"
       },
       "schema": {
        "properties": {
         "account": {
          "description": "Login name (required for login)",
          "type": "string",
          "x-description-zh": "登录名(login 必填)。"
         },
         "captcha_code": {
          "description": "Characters shown in the captcha image (required when sending SMS)",
          "type": "string",
          "x-description-zh": "图形验证码上显示的字符(发短信必填)。"
         },
         "captcha_id": {
          "description": "Captcha id (required when sending SMS)",
          "type": "string",
          "x-description-zh": "图形验证码 id(发短信必填)。"
         },
         "channel": {
          "description": "Delivery channel: email or sms",
          "enum": [
           "email",
           "sms"
          ],
          "type": "string",
          "x-description-zh": "发送通道:email 邮件,sms 短信。"
         },
         "purpose": {
          "description": "Purpose: bind (registration or rebinding), reset_password, or login (second factor)",
          "enum": [
           "bind",
           "reset_password",
           "login"
          ],
          "type": "string",
          "x-description-zh": "用途:bind 注册或改绑,reset_password 找回密码,login 登录二次验证。"
         },
         "target": {
          "description": "Email or phone number (required for bind and reset_password)",
          "type": "string",
          "x-description-zh": "邮箱或手机号(bind、reset_password 必填)。"
         }
        },
        "required": [
         "channel",
         "purpose"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "security": [],
    "summary": "Send verification code",
    "tags": [
     "verify-codes"
    ],
    "x-summary-zh": "发邮件/短信验证码"
   }
  },
  "/api/v2/waf-settings": {
   "get": {
    "operationId": "get-waf-settings",
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Get WAF settings",
    "tags": [
     "waf-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "获取 WAF 设置"
   },
   "put": {
    "operationId": "put-waf-settings",
    "requestBody": {
     "content": {
      "application/json": {
       "example": {
        "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"
       },
       "schema": {
        "properties": {
         "body_max_kb": {
          "description": "Only the first this many KiB of the request body are inspected; 0 = body not inspected.",
          "type": "integer",
          "x-description-zh": "请求体只查前多少 KiB;0 = 不查请求体。"
         },
         "enabled": {
          "description": "Platform-wide master switch; false = no site is inspected.",
          "type": "boolean",
          "x-description-zh": "全网总开关;false = 所有站点都不查。"
         },
         "engine_unavailable_nodes": {
          "description": "Number of online primary nodes reporting the WAF engine (libinjection) unavailable (the sqli/xss rules do not take effect there); ignored on update.",
          "readOnly": true,
          "type": "integer",
          "x-description-zh": "在线主节点里报 WAF 引擎(libinjection)不可用的台数(缺库时 sqli/xss 规则不生效);修改时忽略。"
         },
         "enhanced": {
          "description": "WAF enhanced state - full (active), readonly (expired but within the read-only buffer, License.readonly_days, 7 days by default; standard/strict level and semantic detection still work but are read-only) or basic (not purchased or past the buffer; not in effect, settings kept); ignored on update.",
          "enum": [
           "full",
           "readonly",
           "basic"
          ],
          "readOnly": true,
          "type": "string",
          "x-description-zh": "WAF 增强判定档:full 已开通、readonly 到期只读缓冲内(License.readonly_days,缺省 7 天;标准/严格等级与语义检测照常生效但只读)、basic 未开通或缓冲已过(不生效,设置保留);修改时忽略。"
         },
         "expected_updated_at": {
          "description": "Optimistic lock - the updated_at as the caller read it (the version of the node.global config key, shared by CC and WAF settings; use 1970-01-01T00:00:00Z when the read value is null). If it differs from the stored one, 409 stale_version is returned and nothing is saved; omit to skip the check.",
          "type": "string",
          "x-description-zh": "乐观锁:调用方读到的 updated_at(即配置 node.global 的版本,CC/WAF 设置与该键共用;读到为空用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。"
         },
         "intel_share": {
          "description": "Threat intelligence sharing - anonymously report auto-banned risky IPs, upload-scan hits/false positives and new file fingerprints to the provider (records via GET /intel-reports). Omit to keep the stored value; on when never set (on by default; can be turned off anytime, reporting stops immediately).",
          "type": "boolean",
          "x-description-zh": "威胁情报共享:把自动封禁的高危 IP、上传扫描命中/误报与新出现的文件指纹匿名上报服务商(记录见 GET /intel-reports)。不带 = 保持原值,没设过为开(默认开启,可随时关闭,关闭后立即停止上报)。"
         },
         "level": {
          "description": "Platform default protection level (used by sites that did not pick one); standard/strict are WAF enhanced and go through the enhanced gate (while read-only or not purchased the level can only be lowered, not raised). Omit to keep the stored value; basic when never set.",
          "enum": [
           "basic",
           "standard",
           "strict"
          ],
          "type": "string",
          "x-description-zh": "全网缺省防护等级(站点没单独选时用它);standard/strict 属 WAF 增强,改动过增强门(到期只读期与未开通只许调低,调高拒)。不带 = 保持原值,没设过为 basic。"
         },
         "observe_days": {
          "description": "Observation days for new rules/levels (log only, no blocking); 0 = no observation. Omit to keep the stored value; 3 when never set.",
          "type": "integer",
          "x-description-zh": "新规则/新等级的观察天数(只记录不拦);0 = 不观察。不带 = 保持原值,没设过为 3。"
         },
         "rule_lib": {
          "description": "Rule library overview (read-only, ignored on update) - whether the paid feature rules_update is on, package version, counts per class and node alignment; without it nodes use the 23 built-in rules. Details via GET /waf-protections.",
          "readOnly": true,
          "type": "object",
          "x-description-zh": "规则库对照表(只读,修改时忽略):付费项 rules_update 是否开通、规则包版本与各类条数、节点对齐;没开通时用节点内置 23 条。明细见 GET /waf-protections。",
          "x-gocdn-type": "WafRuleLib"
         },
         "scanner": {
          "description": "Scanner protection (scan section of the built-in guard) - master switch, action and ban duration, plus the five judging rules (any one triggers) each with its own switch and thresholds/custom lists. A rule that is switched off is not judged; custom paths live on the master and survive rule-pack updates.",
          "type": "object",
          "x-description-zh": "扫描器防护(内置防护 protect.builtin_guard 的 scan 段):总开关、处置与封禁时长,以及「判定(满足任一)」五项各自的勾选与阈值/自定义名单。任一项关掉即不判该项;自定义路径保存在主控,换规则版本不受影响。",
          "x-gocdn-type": "WafScanner"
         },
         "semantic": {
          "description": "Semantic detection (WAF enhanced) - judges attacks by meaning on top of rule scoring; the node enforces it.",
          "type": "object",
          "x-description-zh": "语义检测(WAF 增强):在规则打分之外再按语义判攻击;节点按观察期只记不拦、过期后拦截。",
          "x-gocdn-type": "WafSemantic"
         },
         "threshold": {
          "description": "Default blocking threshold (sum of anomaly scores of matched rules); a non-zero site waf.threshold takes precedence.",
          "type": "integer",
          "x-description-zh": "缺省拦截阈值(命中规则的异常分累计);站点 waf.threshold 非 0 时以站点为准。"
         },
         "trunc_action": {
          "description": "Action when part of a request was not inspected (rule 920901) - more than 1024 parameters, more than 256 headers, JSON/XML items over the limit, form fields over the budget, or a non-binary body larger than body_max_kb. Whatever can be re-checked is re-checked first; only what is still uncovered is handled by this setting. log only records (event tagged body_trunc) and never blocks; strict_block blocks at the strict level and only records at basic/standard; block blocks at every level. Default strict_block: at the strict level a non-binary body above body_max_kb (64 KB by default, e.g. a large JSON) is blocked by 920901 - raise body_max_kb, set log, or exempt 920901 in the site WAF exceptions. Note 920901 counts toward the repeated-hit ban (site waf.ban_on_repeat); on sites where it is enabled, client IPs that routinely send large JSON get banned. Sites in observe mode only record. Omit to keep the stored value; strict_block when never set.",
          "enum": [
           "log",
           "strict_block",
           "block"
          ],
          "type": "string",
          "x-description-zh": "请求内容有一部分没查到时的处置(规则号 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。"
         },
         "updated_at": {
          "description": "Version in the response (updated_at of the node.global config key; null if never changed); ignored on update - use expected_updated_at for the optimistic lock.",
          "readOnly": true,
          "type": "string",
          "x-description-zh": "响应里的版本(node.global 配置键的 updated_at,没改过为空);修改时忽略,乐观锁用 expected_updated_at。"
         }
        },
        "required": [
         "body_max_kb",
         "enabled",
         "threshold"
        ],
        "type": "object"
       }
      }
     }
    },
    "responses": {
     "2XX": {
      "description": "OK"
     },
     "default": {
      "description": "application/problem+json"
     }
    },
    "summary": "Update WAF settings",
    "tags": [
     "waf-settings"
    ],
    "x-gocdn-auth": "admin",
    "x-summary-zh": "修改 WAF 设置"
   }
  }
 },
 "security": [
  {
   "ApiKey": []
  },
  {
   "Bearer": []
  }
 ],
 "servers": [
  {
   "description": "Your controller",
   "url": "https://panel.example.com"
  }
 ],
 "tags": [
  {
   "description": "Login, token refresh, logout, password change, TOTP, password reset, captcha and admin SSO. Login endpoints need no authentication.",
   "name": "auth",
   "x-name-en": "Authentication",
   "x-name-zh": "登录认证"
  },
  {
   "description": "Admins manage platform accounts: create, view, update, enable/disable, reset passwords, turn off TOTP. An account must be disabled before it can be deleted.",
   "name": "users",
   "x-name-en": "Users",
   "x-name-zh": "用户管理"
  },
  {
   "description": "The signed-in user views or edits their own profile, real-name verification and UI preferences.",
   "name": "me",
   "x-name-en": "Current user",
   "x-name-zh": "当前用户"
  },
  {
   "description": "API keys of the current user. The plaintext key is returned only once at creation, and scopes can be limited per domain.",
   "name": "api-keys",
   "x-name-en": "API keys",
   "x-name-zh": "API 密钥"
  },
  {
   "description": "No authentication needed. Returns whether registration is open, which fields are required or need verification, and the user agreement.",
   "name": "registration-info",
   "x-name-en": "Registration info",
   "x-name-zh": "注册须知"
  },
  {
   "description": "No authentication needed. Submits registration details to create a tenant account; the agreement must be accepted and verified email or phone needs a code.",
   "name": "registrations",
   "x-name-en": "Registrations",
   "x-name-zh": "注册"
  },
  {
   "description": "No authentication needed. Sends email or SMS codes for binding at registration, password reset and second-factor login; SMS needs a captcha.",
   "name": "verify-codes",
   "x-name-en": "Verification codes",
   "x-name-zh": "验证码"
  },
  {
   "description": "No authentication needed. Tells whether an account needs an email or SMS code to log in, with the masked destination.",
   "name": "login-policy",
   "x-name-en": "Login policy",
   "x-name-zh": "登录策略"
  },
  {
   "description": "Admin only: merchant credentials of Alipay identity verification and Tencent Cloud FaceID (WeChat face verification); the channel in use is chosen by certify_provider in account settings.",
   "name": "certify-channels",
   "x-name-en": "Identity verification channels",
   "x-name-zh": "实名通道"
  },
  {
   "description": "The current users own balance and freeze status; admins manage other users accounts through the user account endpoints.",
   "name": "account",
   "x-name-en": "Account",
   "x-name-zh": "我的账户"
  },
  {
   "description": "Orders created by recharges, deductions, online payments and package purchases; tenants see only their own, admins can see all tenants, and only the remark can be edited.",
   "name": "orders",
   "x-name-en": "Orders",
   "x-name-zh": "订单"
  },
  {
   "description": "Every change to an account balance, each with a balance snapshot taken after posting.",
   "name": "ledger-entries",
   "x-name-en": "Ledger entries",
   "x-name-zh": "账户流水"
  },
  {
   "description": "Start an online recharge: creates an unpaid order, pre-orders it at the payment gateway and returns the payment URL.",
   "name": "payments",
   "x-name-en": "Online payments",
   "x-name-zh": "在线支付"
  },
  {
   "description": "The currently enabled online payment methods, the default method and transfer instructions, used to render the recharge page.",
   "name": "payment-methods",
   "x-name-en": "Recharge methods",
   "x-name-zh": "充值方式"
  },
  {
   "description": "Admin settings for which gateway each payment method uses and each gateways merchant parameters; secrets are write-only.",
   "name": "payment-channels",
   "x-name-en": "Payment channels",
   "x-name-zh": "支付通道"
  },
  {
   "description": "Result notification endpoint called by payment gateways; no authentication, signature verified per gateway rules, and repeated notifications are credited only once.",
   "name": "payment-notifications",
   "x-name-en": "Payment notifications",
   "x-name-zh": "支付回调"
  },
  {
   "description": "Admin only. Stores DNS provider accounts (such as Alibaba Cloud or Cloudflare); credentials are verified online before saving and only the last 4 characters are ever returned.",
   "name": "dns-providers",
   "x-name-en": "DNS providers",
   "x-name-zh": "DNS 服务商"
  },
  {
   "description": "Admin only. Root domains used to build CNAME access names, each owned by a DNS provider account; supports migrating everything to a new root domain and checking whether customers have switched their records.",
   "name": "cname-domains",
   "x-name-en": "CNAME access domains",
   "x-name-zh": "CNAME 接入域名"
  },
  {
   "description": "Admin only. Makes the scheduler reconcile all DNS records against the desired state right away (the Record repair button in the panel).",
   "name": "dns-sync",
   "x-name-en": "DNS sync",
   "x-name-zh": "解析同步"
  },
  {
   "description": "Geographic regions used to categorize nodes and node groups.",
   "name": "regions",
   "x-name-en": "Regions",
   "x-name-zh": "区域"
  },
  {
   "description": "Approved edge nodes and sub-IPs; primary nodes self-enroll with an enrollment token, while sub-IPs are added manually by an admin.",
   "name": "nodes",
   "x-name-en": "Nodes",
   "x-name-zh": "节点"
  },
  {
   "description": "Nodes that have enrolled with a token and await admin approval; once approved they become regular nodes.",
   "name": "pending-nodes",
   "x-name-en": "Pending nodes",
   "x-name-zh": "待接入节点"
  },
  {
   "description": "Generates a one-time enrollment token and a one-line node install command; the token is returned only once, when generated.",
   "name": "node-enroll-tokens",
   "x-name-en": "Node enrollment tokens",
   "x-name-zh": "节点接入令牌"
  },
  {
   "description": "Groups lines under one access name; a backup threshold can switch to the backup group automatically when usable lines run low.",
   "name": "node-groups",
   "x-name-en": "Node groups",
   "x-name-zh": "节点分组"
  },
  {
   "description": "A resolution record in a node group, showing which DNS line and weight a node appears with; a line must be disabled before it can be deleted.",
   "name": "lines",
   "x-name-en": "Lines",
   "x-name-zh": "线路"
  },
  {
   "description": "Built-in alert rules of the control plane with their current settings and status; thresholds are changed via system settings.",
   "name": "alert-rules",
   "x-name-en": "Alert rules",
   "x-name-zh": "告警规则"
  },
  {
   "description": "Recent alert and recovery events, kept for 30 days.",
   "name": "alerts",
   "x-name-en": "Alerts",
   "x-name-zh": "告警记录"
  },
  {
   "description": "Results of each probe round the control plane runs against monitored node IPs.",
   "name": "monitor-logs",
   "x-name-en": "Node monitor logs",
   "x-name-zh": "节点监控日志"
  },
  {
   "description": "IP pools and the IPs inside them, maintained by admins. A pool belongs to a region and its name is unique platform-wide.",
   "name": "ip-pools",
   "x-name-en": "IP pools",
   "x-name-zh": "IP 池"
  },
  {
   "description": "Sites served on IPs with custom ports; the IPs must first be selected in the user package.",
   "name": "ip-sites",
   "x-name-en": "IP sites",
   "x-name-zh": "IP 站点"
  },
  {
   "description": "Uploaded or automatically issued HTTPS certificates. They can be bound to sites; a certificate in use by a site cannot be deleted or disabled.",
   "name": "certs",
   "x-name-en": "Certificates",
   "x-name-zh": "证书"
  },
  {
   "description": "CA accounts used for automatic issuance (Let's Encrypt, ZeroSSL). Registered with the CA on first issuance.",
   "name": "acme-accounts",
   "x-name-en": "ACME accounts",
   "x-name-zh": "ACME 账号"
  },
  {
   "description": "DNS provider API credentials used for DNS-01 validation and wildcard certificates. Credentials are write-only; responses return only masks.",
   "name": "dns-apis",
   "x-name-en": "DNS API (cert validation)",
   "x-name-zh": "DNS API(证书验证)"
  },
  {
   "description": "The current user's default certificate type for new certificates; leave empty to follow the platform.",
   "name": "cert-settings",
   "x-name-en": "Certificate settings",
   "x-name-zh": "证书设置"
  },
  {
   "description": "Admin only. Status of the panel's own HTTPS certificate; one click issues a Let's Encrypt certificate for the panel domain, renewed with certificate management.",
   "name": "panel-cert",
   "x-name-en": "Panel certificate",
   "x-name-zh": "面板证书"
  },
  {
   "description": "Admin only. Provides content for the CA file validation, answered by nodes via the controller; no longer served after expiry.",
   "name": "pki-validations",
   "x-name-en": "File validation",
   "x-name-zh": "文件验证"
  },
  {
   "description": "Rule sets that allow or block requests by IP/CIDR and other conditions; the platform provides built-in rules and tenants can create their own.",
   "name": "acls",
   "x-name-en": "Access control lists",
   "x-name-zh": "访问控制(ACL)"
  },
  {
   "description": "Conditions that identify requests in CC protection; reusable across rule groups.",
   "name": "cc-matches",
   "x-name-en": "CC matchers",
   "x-name-zh": "CC 匹配器"
  },
  {
   "description": "How matched requests are handled: rate limiting or a challenge (JS, slider, captcha and so on).",
   "name": "cc-filters",
   "x-name-en": "CC filters",
   "x-name-zh": "CC 过滤器"
  },
  {
   "description": "Ordered combinations of matchers and filters; a site can pick one rule group.",
   "name": "cc-rules",
   "x-name-en": "CC rules",
   "x-name-zh": "CC 规则"
  },
  {
   "description": "Records of blocked IPs: bans created by hand, unban by IP or for a whole site with an unban history, and automatic bans reported by nodes.",
   "name": "bans",
   "x-name-en": "Bans",
   "x-name-zh": "封禁"
  },
  {
   "description": "Permanent IP blacklist and whitelist of one site; blacklisted IPs are dropped and whitelisted IPs skip CC and other protections. The site's temporary whitelist on nodes can also be cleared.",
   "name": "site-ip-lists",
   "x-name-en": "Site IP lists",
   "x-name-zh": "站点黑白名单"
  },
  {
   "description": "Platform-wide IP blacklist and whitelist with optional expiry, reason and source per entry, plus bulk import and export; admin only.",
   "name": "global-ip-lists",
   "x-name-en": "Global IP lists",
   "x-name-zh": "全局黑白名单"
  },
  {
   "description": "Platform-level default CC rule group and automatic switching settings; admin only.",
   "name": "cc-settings",
   "x-name-en": "CC settings",
   "x-name-zh": "CC 设置"
  },
  {
   "description": "Platform-wide bot management: the action per class (search engine / monitor and tool / automation tool / headless browser / malicious bot) and for fake crawlers, the challenge kind, behaviour score bands, protected endpoints and exceptions; admin only. Headless browser, malicious bot and fake crawler actions plus behaviour scoring belong to the paid feature WAF enhanced. Each site may override per class in the site config field bot.",
   "name": "bot-settings",
   "x-name-en": "Bot settings",
   "x-name-zh": "Bot 设置"
  },
  {
   "description": "Stats at the top of the bot management page and the per-class \"requests today\" column: today's requests, requests and action breakdown per bot class, number of sites with replay protection on, and node upgrade progress; tenants see their own sites only.",
   "name": "bot-stats",
   "x-name-en": "Bot stats",
   "x-name-zh": "Bot 统计"
  },
  {
   "description": "Platform-wide WAF master switch, default blocking threshold and request body inspection limit; admin only. Per-site observe/block mode and exceptions live in the site config field waf.",
   "name": "waf-settings",
   "x-name-en": "WAF settings",
   "x-name-zh": "WAF 设置"
  },
  {
   "description": "Platform-wide upload scanning (files in multipart form uploads only): master switch, dangerous extensions, double extensions, disguised files, webshell signatures, antivirus, per-file limit, scan timeout, action and exceptions; admin only. Webshell signatures, antivirus and the sha256 blocklist belong to the paid feature WAF enhanced.",
   "name": "upload-scan-settings",
   "x-name-en": "Upload scan settings",
   "x-name-zh": "上传防护设置"
  },
  {
   "description": "Stats at the top of the upload scan page: today's scanned, blocked and over-limit unscanned counts, plus the list of sites that cannot be scanned; admin only.",
   "name": "upload-scan-stats",
   "x-name-en": "Upload scan stats",
   "x-name-zh": "上传扫描统计"
  },
  {
   "description": "The platform-provided high-risk IP library (paid item rules update, synced hourly): status, platform-wide handling policy, entry lookup, whitelisting a single entry and today's visits that hit it; read-only for tenants.",
   "name": "intel",
   "x-name-en": "High-risk IP library",
   "x-name-zh": "高危 IP 库"
  },
  {
   "description": "One scheme each for replay, data leak and web tamper protection (one per tenant; admins edit the platform scheme); saving also updates sites that follow the scheme, sites with their own settings are left alone; part of WAF Enhanced.",
   "name": "protect-schemes",
   "x-name-en": "Value-added protection schemes",
   "x-name-zh": "增值防护方案"
  },
  {
   "description": "Replay protection of one site: protected APIs need a one-time token or the app signature headers, otherwise the request is blocked or challenged; can be set for the site alone or restored to the scheme; part of WAF Enhanced.",
   "name": "site-replay-guards",
   "x-name-en": "Replay protection",
   "x-name-zh": "防重放"
  },
  {
   "description": "Data leak protection of one site: checks pages, JSON and text returned by the origin for phone numbers, ID card numbers, bank card numbers, keys and error messages, and masks, blocks or replaces them with an error page; part of WAF Enhanced.",
   "name": "site-leak-guards",
   "x-name-en": "Data leak protection",
   "x-name-zh": "防泄露"
  },
  {
   "description": "Platform-wide default switch and thresholds for network-wide URL protection; admin only. Per-site switch and thresholds live in the site security settings.",
   "name": "url-guard-settings",
   "x-name-en": "Network-wide URL protection settings",
   "x-name-zh": "全网 URL 防护设置"
  },
  {
   "description": "Temporary challenge/rate-limit/block rules pushed for a URL once its cross-node request volume exceeds the threshold, revoked automatically on expiry; read-only view of the entries in effect.",
   "name": "url-guard",
   "x-name-en": "Network-wide URL protection",
   "x-name-zh": "全网 URL 防护"
  },
  {
   "description": "Batches of threat intelligence this master reports anonymously to the vendor (auto-banned high-risk IPs, upload scan hits and false positives, newly seen file fingerprints), one batch every 5 minutes; nothing is reported while intelligence sharing is off. Admin only.",
   "name": "intel-reports",
   "x-name-en": "Threat intelligence reports",
   "x-name-zh": "威胁情报上报记录"
  },
  {
   "description": "Web tamper protection of one site: protected scopes (home page, pages, directories), what counts as tampering (structure only / any change), serving the baseline page or alerting only, and the observation period; baseline update and diff; part of WAF Enhanced.",
   "name": "site-tamper-guards",
   "x-name-en": "Web tamper protection",
   "x-name-zh": "防篡改"
  },
  {
   "description": "All protected pages across sites (site, path, scope, baseline time, state, last change) without picking a site first; tenants see their own sites only and may filter by site.",
   "name": "tamper-guard",
   "x-name-en": "Web tamper protection page overview",
   "x-name-zh": "防篡改保护页面总表"
  },
  {
   "description": "Base packages for sale, defining quotas such as traffic, bandwidth and domains, and prices.",
   "name": "packages",
   "x-name-en": "Packages",
   "x-name-zh": "套餐"
  },
  {
   "description": "Groups that organize packages so customers can browse and choose.",
   "name": "package-groups",
   "x-name-en": "Package groups",
   "x-name-zh": "套餐分组"
  },
  {
   "description": "Quotas or features bought per unit on top of a base package.",
   "name": "package-upgrades",
   "x-name-en": "Upgrade packs",
   "x-name-zh": "升级包"
  },
  {
   "description": "The catalog of packages, groups and upgrade packs a customer can buy.",
   "name": "package-catalog",
   "x-name-en": "Package catalog",
   "x-name-zh": "套餐目录"
  },
  {
   "description": "Packages a tenant has bought: purchase, renew, change, add upgrade packs and view usage.",
   "name": "user-packages",
   "x-name-en": "Purchased packages",
   "x-name-zh": "已购套餐"
  },
  {
   "description": "Admin only: bandwidth and connections of each purchased package over the last minute.",
   "name": "package-monitor",
   "x-name-en": "Package monitor",
   "x-name-zh": "套餐监控"
  },
  {
   "description": "CDN-accelerated sites. Creating one needs at least a domain and an origin; admins can manage any tenant's sites.",
   "name": "sites",
   "x-name-en": "Sites",
   "x-name-zh": "网站"
  },
  {
   "description": "Groups for organizing sites; names are unique within a tenant and a group that still contains sites cannot be deleted.",
   "name": "site-groups",
   "x-name-en": "Site groups",
   "x-name-zh": "网站分组"
  },
  {
   "description": "A set of cache rules that many sites can reference; either platform groups or tenant-owned groups.",
   "name": "cache-groups",
   "x-name-en": "Cache groups",
   "x-name-zh": "缓存分组"
  },
  {
   "description": "Sets the tenant's default cache group and can reset all sites to follow it.",
   "name": "cache-policy",
   "x-name-en": "Cache policy",
   "x-name-zh": "缓存策略"
  },
  {
   "description": "Factory default cache rules, usable as a reference when creating a cache group.",
   "name": "cache-presets",
   "x-name-en": "Cache presets",
   "x-name-zh": "缓存标配"
  },
  {
   "description": "View or set the cache group or custom rules used by one site.",
   "name": "cache-sites",
   "x-name-en": "Site cache mode",
   "x-name-zh": "站点缓存方式"
  },
  {
   "description": "Purge cached URLs or directories, and prefetch given URLs.",
   "name": "cache-jobs",
   "x-name-en": "Purge and prefetch",
   "x-name-zh": "刷新与预热"
  },
  {
   "description": "Daily purge and prefetch limits and today's usage.",
   "name": "cache-quota",
   "x-name-en": "Purge and prefetch quota",
   "x-name-zh": "刷新预热限额"
  },
  {
   "description": "TCP/UDP port forwarding rules. Each rule has listen ports and protocols, an origin list and a balancing method; (protocol, port) is unique platform-wide.",
   "name": "streams",
   "x-name-en": "TCP/UDP forwarding",
   "x-name-zh": "四层转发"
  },
  {
   "description": "Groups that organize forwarding rules for bulk management. Group names are unique per tenant, and a group that still has rules cannot be deleted.",
   "name": "stream-groups",
   "x-name-en": "Forwarding groups",
   "x-name-zh": "转发分组"
  },
  {
   "description": "Edges fetch through L2 nodes in their region first, so cached content no longer hits the origin. Paid feature l2; inactive when not licensed.",
   "name": "l2",
   "x-name-en": "Tiered origin (L2)",
   "x-name-zh": "分层回源 L2"
  },
  {
   "description": "In-app messages and announcements; admins publish announcements and tenants read and mark them as read.",
   "name": "messages",
   "x-name-en": "Messages",
   "x-name-zh": "消息"
  },
  {
   "description": "Choose which notification types to receive.",
   "name": "message-subscriptions",
   "x-name-en": "Message subscriptions",
   "x-name-zh": "消息订阅"
  },
  {
   "description": "Configure and test the email (SMTP) and SMS delivery channels.",
   "name": "message-channels",
   "x-name-en": "Delivery channels",
   "x-name-zh": "发信通道"
  },
  {
   "description": "DingTalk, Feishu, WeCom, Telegram and generic JSON alert outputs; several can be configured, and addresses and secrets show only the last 4 characters.",
   "name": "message-webhooks",
   "x-name-en": "Alert webhooks",
   "x-name-zh": "告警 Webhook"
  },
  {
   "description": "Real-time curves, rankings and usage for sites and TCP/UDP forwarding, node monitoring curves and rankings, unconfigured-domain Top, temporary whitelist and access logs; tenants see only their own data.",
   "name": "reports",
   "x-name-en": "Reports",
   "x-name-zh": "报表"
  }
 ]
}