{
  "openapi": "3.0.3",
  "info": {
    "title": "HaoQi Farm Manager API",
    "version": "20260907-r9-rental-api",
    "description": "源码客户端 API 基础地址：https://hq.cdd2d.xin/api。token 请求头支持管理员 Token 或 hqr_ 出租密钥；出租密钥仅限所属客户的扫码与业务接口，运行状态仅管理员可用。hq_ 个人 API Key 使用 /portal-api 的 Bearer 鉴权。"
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "tags": [
    {
      "name": "客户 API"
    },
    {
      "name": "管理员协议"
    }
  ],
  "paths": {
    "/portal-api/accounts": {
      "get": {
        "operationId": "accounts",
        "summary": "我的账号",
        "description": "返回当前 API Key 所属客户的 QQ，不返回其他客户账号。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        }
      }
    },
    "/portal-api/account-delete": {
      "post": {
        "operationId": "account-delete",
        "summary": "删除我的 QQ 账号",
        "description": "删除本人绑定 QQ 的服务器登录态并解除绑定。释放已占用名额，不减少卡密增加的总名额。不可撤销，重新使用需要扫码。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "confirmQQ": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "确认删除，必须与 qq 完全一致",
                    "example": "123456789"
                  }
                },
                "required": [
                  "qq",
                  "confirmQQ"
                ]
              },
              "example": {
                "qq": "123456789",
                "confirmQQ": "123456789"
              }
            }
          }
        }
      }
    },
    "/portal-api/qr": {
      "post": {
        "operationId": "qr-create",
        "summary": "创建扫码会话",
        "description": "新绑定传 {}。已有 QQ 重新授权需传 qq 和 confirmReplace: true，会清除该 QQ 的旧登录态。二维码未就绪时继续查询状态。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "confirmReplace": {
                    "type": "boolean",
                    "description": "仅重新授权时必须为 true",
                    "example": true
                  }
                },
                "required": []
              },
              "example": {}
            }
          }
        }
      }
    },
    "/portal-api/qr/{id}": {
      "get": {
        "operationId": "qr-status",
        "summary": "查询扫码状态",
        "description": "id 取自创建接口返回的 session.id。session.qrImage 是可直接显示的 PNG data URL。success 表示账号已绑定且协议服务已就绪。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "创建接口返回的 session.id"
          }
        ]
      },
      "delete": {
        "operationId": "qr-close",
        "summary": "取消扫码",
        "description": "释放未完成扫码占用的名额，不删除已成功绑定的账号或协议登录数据。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "创建接口返回的 session.id"
          }
        ]
      }
    },
    "/portal-api/call/code": {
      "post": {
        "operationId": "code",
        "summary": "获取小程序 code",
        "description": "获取已绑定 QQ 对指定 AppID 的业务 code。不会扣减绑定名额。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  }
                },
                "required": [
                  "qq"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029"
              }
            }
          }
        }
      }
    },
    "/portal-api/call/openid": {
      "post": {
        "operationId": "openid",
        "summary": "获取自身 OpenID",
        "description": "获取当前 QQ 在指定 AppID 下的自身 OpenID。不同 AppID 的结果可能不同。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  }
                },
                "required": [
                  "qq"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029"
              }
            }
          }
        }
      }
    },
    "/portal-api/call/friends": {
      "post": {
        "operationId": "friends",
        "summary": "获取农场好友 OpenID",
        "description": "使用本人已绑定 QQ 查询指定 AppID 可返回的农场好友 OpenID，与原 /webui/account 的“农场好友”模式相同。不是登录 QQ 本人的 OpenID，不保证覆盖全部 QQ 好友；friendUins 与 openids 不是逐项对应关系。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  }
                },
                "required": [
                  "qq"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029"
              }
            }
          }
        }
      }
    },
    "/portal-api/call/friend-openid": {
      "post": {
        "operationId": "friend-openid",
        "summary": "批量查询好友 OpenID",
        "description": "最多 100 个好友 QQ，仅使用当前客户已绑定账号的授权。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  },
                  "targetUins": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "1-100 个好友 QQ",
                    "example": [
                      "234567890"
                    ]
                  }
                },
                "required": [
                  "qq",
                  "targetUins"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029",
                "targetUins": [
                  "234567890"
                ]
              }
            }
          }
        }
      }
    },
    "/portal-api/redeem": {
      "post": {
        "operationId": "redeem",
        "summary": "兑换卡密",
        "description": "卡密只能兑换一次。默认每卡增加 1 个 QQ 绑定名额；支持永久、从兑换开始计算有效天数、指定使用到期日期。user.grants 返回每批限时名额的到期时间。使用到期与最晚兑换日期不同，过期账号停止客户调用但保留登录态。",
        "tags": [
          "客户 API"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "ok=true 表示请求成功。扫码请查看 session.state，业务结果在 data 中。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "管理员发放的卡密",
                    "example": "HQ-YOUR-CARD"
                  }
                },
                "required": [
                  "code"
                ]
              },
              "example": {
                "code": "HQ-YOUR-CARD"
              }
            }
          }
        }
      }
    },
    "/api/QQLogin/CreateQRLoginSession": {
      "post": {
        "operationId": "admin-create",
        "summary": "协议 · 按 QQ 出码",
        "description": "源码客户端基础地址填 https://hq.cdd2d.xin/api，密钥填管理员 Token 或 hqr_ 出租密钥。出租密钥仅操作所属客户账号；传 targetUin 给已绑定 QQ 会重新授权，给未绑定 QQ 仅限定本次扫码目标，不清理其他账号。管理员 targetUin 会替换原登录态。新二维码可传 {}，取得 sessionId 后继续查询。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "targetUin": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "可选，指定扫码 QQ；已绑定 QQ 会重新授权",
                    "example": "123456789"
                  }
                },
                "required": []
              },
              "example": {
                "targetUin": "123456789"
              }
            }
          }
        }
      }
    },
    "/api/QQLogin/GetQRLoginSession": {
      "post": {
        "operationId": "admin-status",
        "summary": "管理员 · 查询扫码",
        "description": "sessionId 来自创建接口的 data.sessionId。二维码链接位于 data.qrcodeurl，客户端需要生成二维码图片。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sessionId": {
                    "type": "string",
                    "description": "管理员扫码会话 ID",
                    "example": "qr-SESSION-ID"
                  }
                },
                "required": [
                  "sessionId"
                ]
              },
              "example": {
                "sessionId": "qr-SESSION-ID"
              }
            }
          }
        }
      }
    },
    "/api/FarmCode/GetCode": {
      "post": {
        "operationId": "admin-code",
        "summary": "协议 · 获取 code",
        "description": "支持管理员 Token 和 hqr_ 出租密钥，出租密钥只允许本人账号。完整 URL 为 https://hq.cdd2d.xin/api/FarmCode/GetCode。必须同时检查 code=0 和 data.ok=true；一次性业务 code 位于 data.token，不是管理员密钥。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "协议已保存并授权的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  }
                },
                "required": [
                  "qq"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029"
              }
            }
          }
        }
      }
    },
    "/api/OpenId/GetByUin": {
      "post": {
        "operationId": "admin-openid",
        "summary": "管理员 · 获取本人 OpenID",
        "description": "查询登录 QQ 在指定 AppID 下的本人 OpenID。targetUin 必须与 qq 相同，结果位于 data.openids。此接口不是农场好友列表。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "协议已保存并授权的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  },
                  "targetUin": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "查询本人时与 qq 相同",
                    "example": "123456789"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "auto"
                    ],
                    "example": "auto"
                  }
                },
                "required": [
                  "qq",
                  "targetUin"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029",
                "targetUin": "123456789",
                "method": "auto"
              }
            }
          }
        }
      }
    },
    "/api/QQLogin/GetQRLoginRuntimeStatus": {
      "post": {
        "operationId": "admin-runtime",
        "summary": "管理员 · 预热与保活",
        "description": "返回预热就绪数、在线 Worker、已保存账号数和保活策略。无需填写 QQ。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "required": []
              },
              "example": {}
            }
          }
        }
      }
    },
    "/api/QQLogin/GetQuickLoginListNew": {
      "post": {
        "operationId": "protocol-accounts",
        "summary": "协议 · 已保存账号",
        "description": "管理员可查询全部已保存账号；出租密钥仅返回所属客户的账号。已保存不代表当前在线。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "required": []
              },
              "example": {}
            }
          }
        }
      }
    },
    "/api/QQLogin/CloseQRLoginSession": {
      "post": {
        "operationId": "protocol-close",
        "summary": "协议 · 关闭扫码会话",
        "description": "关闭未完成的扫码会话，释放扫码资源。出租密钥只能关闭本客户会话。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sessionId": {
                    "type": "string",
                    "description": "创建二维码返回的 data.sessionId",
                    "example": "qr-SESSION-ID"
                  }
                },
                "required": [
                  "sessionId"
                ]
              },
              "example": {
                "sessionId": "qr-SESSION-ID"
              }
            }
          }
        }
      }
    },
    "/api/OpenId/FarmFriends": {
      "post": {
        "operationId": "protocol-friends",
        "summary": "协议 · 农场好友 OpenID",
        "description": "与旧网页农场好友模式相同。支持管理员 Token 和出租密钥；出租密钥只能使用所属客户的 QQ。结果在 data.openids，不是当前 QQ 本人的 OpenID。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  }
                },
                "required": [
                  "qq"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029"
              }
            }
          }
        }
      }
    },
    "/api/OpenId/BatchByUin": {
      "post": {
        "operationId": "protocol-batch",
        "summary": "协议 · 按好友 QQ 查 OpenID",
        "description": "使用本人已授权 QQ 查询好友 OpenID，最多 100 个好友 QQ。不同 AppID 授权范围可能不同。",
        "tags": [
          "管理员协议"
        ],
        "security": [
          {
            "adminToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "code=0 且 data.ok 不为 false 表示成功。starting/waiting/authorizing 需继续轮询。"
          },
          "400": {
            "description": "参数无效"
          },
          "401": {
            "description": "密钥无效或缺失"
          },
          "403": {
            "description": "账号无权限或已停用"
          },
          "409": {
            "description": "名额不足、会话冲突或需要确认重新授权"
          },
          "429": {
            "description": "请求过快或并发名额已满"
          },
          "502": {
            "description": "上游暂不可用或账号授权失效"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "qq": {
                    "type": "string",
                    "pattern": "^[0-9]{5,15}$",
                    "description": "当前客户已绑定的 QQ",
                    "example": "123456789"
                  },
                  "appid": {
                    "type": "string",
                    "description": "目标小程序 AppID，默认 1112386029",
                    "example": "1112386029"
                  },
                  "targetUins": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "要查询的好友 QQ 列表",
                    "example": [
                      "234567890"
                    ]
                  }
                },
                "required": [
                  "qq",
                  "targetUins"
                ]
              },
              "example": {
                "qq": "123456789",
                "appid": "1112386029",
                "targetUins": [
                  "234567890"
                ]
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "账号中心创建的 hq_ 个人 API Key，或后台发放的 hqr_ 出租密钥（仅扫码、账号和业务接口）"
      },
      "adminToken": {
        "type": "apiKey",
        "in": "header",
        "name": "token",
        "description": "管理员 Token，或 hqr_ 出租密钥。出租密钥不能访问管理配置、运行状态或其他客户账号；不要向客户分发管理员 Token。"
      }
    }
  }
}