{
  "openapi": "3.0.3",
  "info": {
    "title": "niubigeo 服务与积分 API",
    "version": "1.0.0",
    "description": "1 积分 = ¥1；50 积分起充。仅人工联系与充值确认，无在线支付。平台 Key 与首页 OpenRouter Key 独立。",
    "contact": {
      "email": "support@niubigeo.ai"
    }
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "security": [
    {
      "platformKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "platformKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Niubigeo-Key"
      }
    },
    "schemas": {
      "HumanSpec": {
        "type": "object",
        "required": [
          "questions",
          "aiTypes"
        ],
        "properties": {
          "questions": {
            "oneOf": [
              {
                "type": "string",
                "description": "每行一个问题，空行忽略，重复问题保留"
              },
              {
                "type": "array",
                "minItems": 1,
                "maxItems": 500,
                "items": {
                  "type": "string",
                  "maxLength": 4000
                }
              }
            ]
          },
          "aiTypes": {
            "oneOf": [
              {
                "type": "string",
                "description": "每行一个 AI 类型，不可重复"
              },
              {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "maxLength": 120
                }
              }
            ]
          },
          "peoplePerQuestion": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "browserMode": {
            "type": "string",
            "enum": [
              "incognito",
              "normal",
              "not_applicable"
            ],
            "default": "incognito"
          },
          "region": {
            "type": "string",
            "maxLength": 200
          },
          "timeWindow": {
            "type": "string",
            "maxLength": 200,
            "description": "日期、时段与时区；人工确认可执行性"
          },
          "device": {
            "type": "string",
            "maxLength": 200
          },
          "questionStyle": {
            "type": "string",
            "maxLength": 500
          }
        },
        "description": "每个问题在每个 AI 上由指定人数各提交一次，5 积分/次；单笔最多 10,000 次。价格由服务端计算。"
      },
      "ContentSpec": {
        "type": "object",
        "required": [
          "package",
          "brief"
        ],
        "properties": {
          "package": {
            "type": "string",
            "enum": [
              "article",
              "articles30",
              "articles90"
            ]
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "brief": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          }
        }
      },
      "HumanOrder": {
        "type": "object",
        "required": [
          "questions",
          "aiTypes",
          "termsVersion"
        ],
        "properties": {
          "questions": {
            "oneOf": [
              {
                "type": "string",
                "description": "每行一个问题，空行忽略，重复问题保留"
              },
              {
                "type": "array",
                "minItems": 1,
                "maxItems": 500,
                "items": {
                  "type": "string",
                  "maxLength": 4000
                }
              }
            ]
          },
          "aiTypes": {
            "oneOf": [
              {
                "type": "string",
                "description": "每行一个 AI 类型，不可重复"
              },
              {
                "type": "array",
                "minItems": 1,
                "maxItems": 20,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "maxLength": 120
                }
              }
            ]
          },
          "peoplePerQuestion": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "browserMode": {
            "type": "string",
            "enum": [
              "incognito",
              "normal",
              "not_applicable"
            ],
            "default": "incognito"
          },
          "region": {
            "type": "string",
            "maxLength": 200
          },
          "timeWindow": {
            "type": "string",
            "maxLength": 200,
            "description": "日期、时段与时区；人工确认可执行性"
          },
          "device": {
            "type": "string",
            "maxLength": 200
          },
          "questionStyle": {
            "type": "string",
            "maxLength": 500
          },
          "termsVersion": {
            "type": "string",
            "enum": [
              "2026-09-09.3"
            ],
            "description": "阅读 /terms 与 /terms#credits 后，提交此版本表示接受；隐私说明见 /privacy。新订单与充值申请必填，重试不改变已有记录。"
          }
        },
        "description": "每个问题在每个 AI 上由指定人数各提交一次，5 积分/次；单笔最多 10,000 次。价格由服务端计算。"
      },
      "ContentOrder": {
        "type": "object",
        "required": [
          "package",
          "brief",
          "termsVersion"
        ],
        "properties": {
          "package": {
            "type": "string",
            "enum": [
              "article",
              "articles30",
              "articles90"
            ]
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          },
          "brief": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000
          },
          "termsVersion": {
            "type": "string",
            "enum": [
              "2026-09-09.3"
            ],
            "description": "阅读 /terms 与 /terms#credits 后，提交此版本表示接受；隐私说明见 /privacy。新订单与充值申请必填，重试不改变已有记录。"
          }
        }
      }
    }
  },
  "paths": {
    "/catalog": {
      "get": {
        "summary": "公开价格与套餐",
        "parameters": [],
        "security": [],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/quotes/human-tests": {
      "post": {
        "summary": "计算真人测试价格，不扣积分",
        "parameters": [],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HumanSpec"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/quotes/content": {
      "post": {
        "summary": "计算内容套餐价格，不扣积分",
        "parameters": [],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContentSpec"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/account": {
      "get": {
        "summary": "当前账户与余额",
        "parameters": [],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/ledger": {
      "get": {
        "summary": "积分流水",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 9999999,
              "default": 0
            },
            "description": "每页最多 50 条"
          }
        ],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/orders": {
      "get": {
        "summary": "当前账户订单",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 9999999,
              "default": 0
            },
            "description": "每页最多 50 条"
          }
        ],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/orders/human-tests": {
      "post": {
        "summary": "创建真人测试订单并扣积分，等待人工执行",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "description": "相同内容重试使用相同键；改变内容须换键，否则 409。"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HumanOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "幂等订单重试返回已有订单"
          },
          "201": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/orders/content": {
      "post": {
        "summary": "创建内容订单并扣积分，等待人工执行",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "description": "相同内容重试使用相同键；改变内容须换键，否则 409。"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContentOrder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "幂等订单重试返回已有订单"
          },
          "201": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/orders/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "订单与人工交付记录",
        "parameters": [],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/orders/{id}/cancel": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "summary": "取消待执行订单并退回积分，可安全重复调用",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    },
    "/topups": {
      "get": {
        "summary": "充值申请记录",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 9999999,
              "default": 0
            },
            "description": "每页最多 50 条"
          }
        ],
        "responses": {
          "200": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      },
      "post": {
        "summary": "申请人工充值；提交不会增加余额",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            },
            "description": "相同内容重试使用相同键；改变内容须换键，否则 409。"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "credits",
                  "termsVersion"
                ],
                "properties": {
                  "credits": {
                    "type": "integer",
                    "minimum": 50,
                    "maximum": 1000000
                  },
                  "termsVersion": {
                    "type": "string",
                    "enum": [
                      "2026-09-09.3"
                    ],
                    "description": "阅读 /terms 与 /terms#credits 后，提交此版本表示接受；隐私说明见 /privacy。新订单与充值申请必填，重试不改变已有记录。"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "幂等订单重试返回已有订单"
          },
          "201": {
            "description": "成功，返回对应资源"
          },
          "400": {
            "description": "JSON 格式无效"
          },
          "401": {
            "description": "平台 API Key 缺失或无效"
          },
          "402": {
            "description": "积分不足"
          },
          "404": {
            "description": "资源不存在或不属于此账户"
          },
          "409": {
            "description": "幂等冲突或订单状态不允许"
          },
          "413": {
            "description": "请求体过大（最多 256KB）"
          },
          "415": {
            "description": "须使用 application/json"
          },
          "422": {
            "description": "参数不符合要求"
          },
          "428": {
            "description": "缺少当前 termsVersion，需阅读并接受条款后提交"
          }
        }
      }
    }
  }
}