{"openapi": "3.1.0", "info": {"title": "副脑中转站 Gateway API", "version": "2026-09-03", "description": "Gateway-only self-service and business API contract. OneAuth identity is shared by immutable subject; Gateway projects, credits, orders, usage, ledgers, and business keys are isolated from every other product. Current recharge and providers are local validation surfaces; production payment, SMS delivery, and deployment are NOT_RUN."}, "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", "servers": [{"url": "https://api.funaokeji.com", "description": "Canonical Gateway origin"}], "tags": [{"name": "Identity", "description": "OneAuth-aligned phone verification and Gateway sessions"}, {"name": "Account", "description": "Current Gateway account/project only"}, {"name": "Billing", "description": "Gateway-local custom recharge and isolated credit ledger"}, {"name": "Keys", "description": "Project-owned business API keys"}, {"name": "Business operations", "description": "Fixed-credit idempotent operations"}, {"name": "Documentation", "description": "Canonical machine-readable contracts"}], "paths": {"/v1/auth/send-code": {"post": {"operationId": "requestGatewaySmsCode", "summary": "请求 Gateway 短信验证码", "tags": ["Identity"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SendCodeRequest"}, "example": {"phone": "13800000000"}}}}, "responses": {"202": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VerificationChallenge"}, "example": {"challengeId": "gvc_example", "expiresInSeconds": 300, "resendAfterSeconds": 60}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, PHONE_INVALID：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；手机号或 JSON 字段无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "手机号或 JSON 字段无效。", "retry": "修正后重试。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}]}, "429": {"description": "RATE_LIMITED：请求方或手机号仍在限流/重发冷却窗口。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "请求方或手机号仍在限流/重发冷却窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "请求方或手机号仍在限流/重发冷却窗口。", "retry": "等待窗口后再请求。"}]}, "503": {"description": "SMS_DELIVERY_UNAVAILABLE：短信适配器未启用或投递失败，challenge 已失效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "SMS_DELIVERY_UNAVAILABLE", "message": "短信适配器未启用或投递失败，challenge 已失效。"}}}}, "x-error-codes": [{"status": 503, "code": "SMS_DELIVERY_UNAVAILABLE", "meaning": "短信适配器未启用或投递失败，challenge 已失效。", "retry": "稍后重新申请新 challenge。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "description": "为大陆手机号创建一次性 6 位验证 challenge；响应绝不回显验证码。\n\n何时使用：注册前或重新验证手机号时调用；先保存 challengeId，再等待用户持有的短信码。\n\n认证：无需登录；浏览器必须满足精确同源校验。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；重发会使旧 challenge 失效。\n\n重试：只有明确投递失败或超时后才申请新 challenge；旧 challenge 可能已失效。\n\n运行边界：真实短信送达与生产 OneAuth 为 NOT_RUN；本地 fake SMS 仅验收 seam。", "x-purpose": "为大陆手机号创建一次性 6 位验证 challenge；响应绝不回显验证码。", "x-when-to-use": "注册前或重新验证手机号时调用；先保存 challengeId，再等待用户持有的短信码。", "x-authentication": "无需登录；浏览器必须满足精确同源校验。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；重发会使旧 challenge 失效。", "x-retry-policy": "只有明确投递失败或超时后才申请新 challenge；旧 challenge 可能已失效。", "x-runtime-boundary": "真实短信送达与生产 OneAuth 为 NOT_RUN；本地 fake SMS 仅验收 seam。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "手机号或 JSON 字段无效。", "retry": "修正后重试。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "请求方或手机号仍在限流/重发冷却窗口。", "retry": "等待窗口后再请求。"}, {"status": 503, "code": "SMS_DELIVERY_UNAVAILABLE", "meaning": "短信适配器未启用或投递失败，challenge 已失效。", "retry": "稍后重新申请新 challenge。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "请求 Gateway 短信验证码", "purpose": "为大陆手机号创建一次性 6 位验证 challenge；响应绝不回显验证码。", "whenToUse": "注册前或重新验证手机号时调用；先保存 challengeId，再等待用户持有的短信码。", "authentication": "无需登录；浏览器必须满足精确同源校验。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"phone": "13800000000"}, "success": {"status": 202, "example": {"challengeId": "gvc_example", "expiresInSeconds": 300, "resendAfterSeconds": 60}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "手机号或 JSON 字段无效。", "retry": "修正后重试。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "请求方或手机号仍在限流/重发冷却窗口。", "retry": "等待窗口后再请求。"}, {"status": 503, "code": "SMS_DELIVERY_UNAVAILABLE", "meaning": "短信适配器未启用或投递失败，challenge 已失效。", "retry": "稍后重新申请新 challenge。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "只有明确投递失败或超时后才申请新 challenge；旧 challenge 可能已失效。", "idempotency": "不使用 Idempotency-Key；重发会使旧 challenge 失效。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": "真实短信送达与生产 OneAuth 为 NOT_RUN；本地 fake SMS 仅验收 seam。"}, "parameters": [{"$ref": "#/components/parameters/OriginHeader"}]}}, "/v1/auth/register": {"post": {"operationId": "registerGatewayAccount", "summary": "验证短信并创建 Gateway 账户", "tags": ["Identity"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RegisterRequest"}, "example": {"phone": "13800000000", "verificationCode": "<6位短信验证码>", "challengeId": "gvc_example", "recoveryEmail": "person@example.invalid", "password": "<12-128-character-password>", "next": "/console"}}}}, "responses": {"201": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AuthResponse"}, "example": {"account": {"accountId": "acct_example", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example"}, "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>", "redirectTo": "/console"}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, VERIFICATION_FAILED, PHONE_INVALID, EMAIL_INVALID, PASSWORD_INVALID, NEXT_PATH_INVALID：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；challenge、验证码、手机号、邮箱、密码或 next 无效。；phone 不是有效的中国大陆手机号。；recoveryEmail 格式无效。；password 长度不在 12 到 128 个字符。；next 不在 Gateway 页面白名单。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "VERIFICATION_FAILED", "meaning": "challenge、验证码、手机号、邮箱、密码或 next 无效。", "retry": "重新核对；challenge 失效时先申请新码。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "phone 不是有效的中国大陆手机号。", "retry": "修正手机号后申请或使用对应 challenge。"}, {"status": 400, "code": "EMAIL_INVALID", "meaning": "recoveryEmail 格式无效。", "retry": "提供有效邮箱格式；该邮箱仍需另行验证。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "设置符合长度要求的新密码。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}]}, "409": {"description": "ACCOUNT_ALREADY_EXISTS, ACCOUNT_UNAVAILABLE, VERIFICATION_CONFLICT：该已验证身份已存在 Gateway 账户。；账户创建与唯一约束发生冲突。；challenge 在原子消费时发生并发状态变化。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ACCOUNT_ALREADY_EXISTS", "message": "该已验证身份已存在 Gateway 账户。"}}}}, "x-error-codes": [{"status": 409, "code": "ACCOUNT_ALREADY_EXISTS", "meaning": "该已验证身份已存在 Gateway 账户。", "retry": "改走登录或官方恢复。"}, {"status": 409, "code": "ACCOUNT_UNAVAILABLE", "meaning": "账户创建与唯一约束发生冲突。", "retry": "先尝试登录确认状态，再走官方恢复。"}, {"status": 409, "code": "VERIFICATION_CONFLICT", "meaning": "challenge 在原子消费时发生并发状态变化。", "retry": "先尝试登录确认结果；不要重复消费同一验证码。"}]}, "429": {"description": "RATE_LIMITED：注册尝试超过固定窗口。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "注册尝试超过固定窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "注册尝试超过固定窗口。", "retry": "等待窗口后再试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "description": "原子消费 challenge，创建 OneAuth 映射、Gateway account、personal project 与登录会话。\n\n何时使用：用户已收到短信码并同意创建 Gateway 独立项目时调用；恢复邮箱初始保持待验证。\n\n认证：无需登录；浏览器必须满足精确同源校验。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；challenge 只能成功消费一次。\n\n重试：不要盲目重复验证码消费；收到不确定网络错误时先尝试登录确认状态。\n\n运行边界：生产 OneAuth、真实短信与正式账户迁移为 NOT_RUN。", "x-purpose": "原子消费 challenge，创建 OneAuth 映射、Gateway account、personal project 与登录会话。", "x-when-to-use": "用户已收到短信码并同意创建 Gateway 独立项目时调用；恢复邮箱初始保持待验证。", "x-authentication": "无需登录；浏览器必须满足精确同源校验。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；challenge 只能成功消费一次。", "x-retry-policy": "不要盲目重复验证码消费；收到不确定网络错误时先尝试登录确认状态。", "x-runtime-boundary": "生产 OneAuth、真实短信与正式账户迁移为 NOT_RUN。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "VERIFICATION_FAILED", "meaning": "challenge、验证码、手机号、邮箱、密码或 next 无效。", "retry": "重新核对；challenge 失效时先申请新码。"}, {"status": 409, "code": "ACCOUNT_ALREADY_EXISTS", "meaning": "该已验证身份已存在 Gateway 账户。", "retry": "改走登录或官方恢复。"}, {"status": 409, "code": "ACCOUNT_UNAVAILABLE", "meaning": "账户创建与唯一约束发生冲突。", "retry": "先尝试登录确认状态，再走官方恢复。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "注册尝试超过固定窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "phone 不是有效的中国大陆手机号。", "retry": "修正手机号后申请或使用对应 challenge。"}, {"status": 400, "code": "EMAIL_INVALID", "meaning": "recoveryEmail 格式无效。", "retry": "提供有效邮箱格式；该邮箱仍需另行验证。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "设置符合长度要求的新密码。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}, {"status": 409, "code": "VERIFICATION_CONFLICT", "meaning": "challenge 在原子消费时发生并发状态变化。", "retry": "先尝试登录确认结果；不要重复消费同一验证码。"}], "x-doc-detail": {"summary": "验证短信并创建 Gateway 账户", "purpose": "原子消费 challenge，创建 OneAuth 映射、Gateway account、personal project 与登录会话。", "whenToUse": "用户已收到短信码并同意创建 Gateway 独立项目时调用；恢复邮箱初始保持待验证。", "authentication": "无需登录；浏览器必须满足精确同源校验。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"phone": "13800000000", "verificationCode": "<6位短信验证码>", "challengeId": "gvc_example", "recoveryEmail": "person@example.invalid", "password": "<12-128-character-password>", "next": "/console"}, "success": {"status": 201, "example": {"account": {"accountId": "acct_example", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example"}, "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>", "redirectTo": "/console"}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "VERIFICATION_FAILED", "meaning": "challenge、验证码、手机号、邮箱、密码或 next 无效。", "retry": "重新核对；challenge 失效时先申请新码。"}, {"status": 409, "code": "ACCOUNT_ALREADY_EXISTS", "meaning": "该已验证身份已存在 Gateway 账户。", "retry": "改走登录或官方恢复。"}, {"status": 409, "code": "ACCOUNT_UNAVAILABLE", "meaning": "账户创建与唯一约束发生冲突。", "retry": "先尝试登录确认状态，再走官方恢复。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "注册尝试超过固定窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}, {"status": 400, "code": "PHONE_INVALID", "meaning": "phone 不是有效的中国大陆手机号。", "retry": "修正手机号后申请或使用对应 challenge。"}, {"status": 400, "code": "EMAIL_INVALID", "meaning": "recoveryEmail 格式无效。", "retry": "提供有效邮箱格式；该邮箱仍需另行验证。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "设置符合长度要求的新密码。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}, {"status": 409, "code": "VERIFICATION_CONFLICT", "meaning": "challenge 在原子消费时发生并发状态变化。", "retry": "先尝试登录确认结果；不要重复消费同一验证码。"}], "retry": "不要盲目重复验证码消费；收到不确定网络错误时先尝试登录确认状态。", "idempotency": "不使用 Idempotency-Key；challenge 只能成功消费一次。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": "生产 OneAuth、真实短信与正式账户迁移为 NOT_RUN。"}, "parameters": [{"$ref": "#/components/parameters/OriginHeader"}]}}, "/v1/auth/login": {"post": {"operationId": "loginGatewayAccount", "summary": "登录 Gateway 并轮换会话", "tags": ["Identity"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoginRequest"}, "example": {"identifier": "13800000000", "password": "<12-128-character-password>", "next": "/console"}}}}, "responses": {"200": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AuthResponse"}, "example": {"account": {"accountId": "acct_example", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example"}, "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>", "redirectTo": "/console"}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDENTIFIER_INVALID, PASSWORD_INVALID, NEXT_PATH_INVALID：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；identifier、密码格式、next 或字段合同无效。；password 长度不在 12 到 128 个字符。；next 不在 Gateway 页面白名单。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDENTIFIER_INVALID", "meaning": "identifier、密码格式、next 或字段合同无效。", "retry": "修正格式后重试。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "修正密码格式后重试。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}]}, "500": {"description": "INTERNAL_ERROR, PASSWORD_STATE_INVALID：服务端未能完成公开写请求。；账户密码摘要参数或存储状态无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 500, "code": "PASSWORD_STATE_INVALID", "meaning": "账户密码摘要参数或存储状态无效。", "retry": "停止重试并由运维修复账户状态。"}]}, "403": {"description": "ORIGIN_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}]}, "401": {"description": "AUTHENTICATION_FAILED：未知/待验证身份与错误密码统一失败。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "AUTHENTICATION_FAILED", "message": "未知/待验证身份与错误密码统一失败。"}}}}, "x-error-codes": [{"status": 401, "code": "AUTHENTICATION_FAILED", "meaning": "未知/待验证身份与错误密码统一失败。", "retry": "使用官方恢复；不要枚举账户。"}]}, "429": {"description": "RATE_LIMITED：登录尝试超过固定窗口。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "登录尝试超过固定窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "登录尝试超过固定窗口。", "retry": "等待窗口后再试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "description": "使用已验证手机号或已单独验证的恢复邮箱登录，并签发新 HttpOnly 会话。\n\n何时使用：已有 Gateway 账户且需要进入控制台或刷新失效会话时调用。\n\n认证：无需登录；浏览器必须满足精确同源校验。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；成功登录会轮换会话。\n\n重试：401 不区分身份是否存在；只在用户明确操作后重试。\n\n运行边界：正式生产身份系统为 NOT_RUN。", "x-purpose": "使用已验证手机号或已单独验证的恢复邮箱登录，并签发新 HttpOnly 会话。", "x-when-to-use": "已有 Gateway 账户且需要进入控制台或刷新失效会话时调用。", "x-authentication": "无需登录；浏览器必须满足精确同源校验。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；成功登录会轮换会话。", "x-retry-policy": "401 不区分身份是否存在；只在用户明确操作后重试。", "x-runtime-boundary": "正式生产身份系统为 NOT_RUN。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "IDENTIFIER_INVALID", "meaning": "identifier、密码格式、next 或字段合同无效。", "retry": "修正格式后重试。"}, {"status": 401, "code": "AUTHENTICATION_FAILED", "meaning": "未知/待验证身份与错误密码统一失败。", "retry": "使用官方恢复；不要枚举账户。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "登录尝试超过固定窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "修正密码格式后重试。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}, {"status": 500, "code": "PASSWORD_STATE_INVALID", "meaning": "账户密码摘要参数或存储状态无效。", "retry": "停止重试并由运维修复账户状态。"}], "x-doc-detail": {"summary": "登录 Gateway 并轮换会话", "purpose": "使用已验证手机号或已单独验证的恢复邮箱登录，并签发新 HttpOnly 会话。", "whenToUse": "已有 Gateway 账户且需要进入控制台或刷新失效会话时调用。", "authentication": "无需登录；浏览器必须满足精确同源校验。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"identifier": "13800000000", "password": "<12-128-character-password>", "next": "/console"}, "success": {"status": 200, "example": {"account": {"accountId": "acct_example", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example"}, "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>", "redirectTo": "/console"}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "IDENTIFIER_INVALID", "meaning": "identifier、密码格式、next 或字段合同无效。", "retry": "修正格式后重试。"}, {"status": 401, "code": "AUTHENTICATION_FAILED", "meaning": "未知/待验证身份与错误密码统一失败。", "retry": "使用官方恢复；不要枚举账户。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "登录尝试超过固定窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}, {"status": 400, "code": "PASSWORD_INVALID", "meaning": "password 长度不在 12 到 128 个字符。", "retry": "修正密码格式后重试。"}, {"status": 400, "code": "NEXT_PATH_INVALID", "meaning": "next 不在 Gateway 页面白名单。", "retry": "省略 next 或使用公开允许的站内路径。"}, {"status": 500, "code": "PASSWORD_STATE_INVALID", "meaning": "账户密码摘要参数或存储状态无效。", "retry": "停止重试并由运维修复账户状态。"}], "retry": "401 不区分身份是否存在；只在用户明确操作后重试。", "idempotency": "不使用 Idempotency-Key；成功登录会轮换会话。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": "正式生产身份系统为 NOT_RUN。"}, "parameters": [{"$ref": "#/components/parameters/OriginHeader"}]}}, "/v1/auth/logout": {"post": {"operationId": "logoutGatewayAccount", "summary": "撤销当前 Gateway 会话", "tags": ["Identity"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmptyObject"}, "example": {}}}}, "responses": {"200": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LogoutResponse"}, "example": {"state": "logged_out"}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID, CSRF_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。；Origin 或 CSRF 不匹配当前会话。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配当前会话。", "retry": "刷新会话上下文后重试一次。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话缺失或已失效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话缺失或已失效。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失或已失效。", "retry": "视为已退出；无需循环重试。"}]}, "429": {"description": "RATE_LIMITED：会话写操作限流。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "会话写操作限流。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "会话写操作限流。", "retry": "等待窗口后重试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "parameters": [{"$ref": "#/components/parameters/CsrfToken"}, {"$ref": "#/components/parameters/OriginHeader"}], "security": [{"GatewaySession": [], "CsrfHeader": []}], "description": "使当前服务端会话失效并清理浏览器 Cookie。\n\n何时使用：用户主动退出或怀疑会话泄露时调用。\n\n认证：需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：必需，且必须绑定当前 Cookie 会话。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；重复登出可能返回 401，但不会扣费。\n\n重试：成功或明确 401 后客户端都应丢弃本地会话界面状态。", "x-purpose": "使当前服务端会话失效并清理浏览器 Cookie。", "x-when-to-use": "用户主动退出或怀疑会话泄露时调用。", "x-authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "必需，且必须绑定当前 Cookie 会话。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；重复登出可能返回 401，但不会扣费。", "x-retry-policy": "成功或明确 401 后客户端都应丢弃本地会话界面状态。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失或已失效。", "retry": "视为已退出；无需循环重试。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配当前会话。", "retry": "刷新会话上下文后重试一次。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "会话写操作限流。", "retry": "等待窗口后重试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "撤销当前 Gateway 会话", "purpose": "使当前服务端会话失效并清理浏览器 Cookie。", "whenToUse": "用户主动退出或怀疑会话泄露时调用。", "authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "必需，且必须绑定当前 Cookie 会话。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "requestExample": {}, "success": {"status": 200, "example": {"state": "logged_out"}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失或已失效。", "retry": "视为已退出；无需循环重试。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配当前会话。", "retry": "刷新会话上下文后重试一次。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "会话写操作限流。", "retry": "等待窗口后重试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "成功或明确 401 后客户端都应丢弃本地会话界面状态。", "idempotency": "不使用 Idempotency-Key；重复登出可能返回 401，但不会扣费。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/pricing": {"get": {"operationId": "getGatewayPricing", "summary": "读取 Gateway canonical 价格", "tags": ["Billing"], "responses": {"200": {"description": "Canonical pricing", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PricingResponse"}, "example": {"currency": "CNY", "amountUnit": "fen", "minAmountFen": 100, "maxAmountFen": 1000000, "stepAmountFen": 100, "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "paymentMode": "local-simulated", "productionPayment": "NOT_RUN", "operations": [{"operation": "agent.run", "path": "/v1/agent/run", "scope": "agent:run", "credits": 5, "cnyFen": 50, "cnyYuan": "0.50"}, {"operation": "model.chat", "path": "/v1/models/chat", "scope": "models:invoke", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "shopping.search", "path": "/v1/shopping/search", "scope": "shopping:search", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.compare", "path": "/v1/zhentiao/compare", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.filter", "path": "/v1/zhentiao/filter", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.links", "path": "/v1/zhentiao/links", "scope": "zhentiao:link", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.prepurchase_review", "path": "/v1/zhentiao/prepurchase-review", "scope": "zhentiao:read", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.recommend", "path": "/v1/zhentiao/recommend", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.search", "path": "/v1/zhentiao/search", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}], "chargePolicy": {"reserve": "Before forwarding, the fixed operation credits are reserved from the current Gateway project.", "settle": "A confirmed provider result settles the reservation exactly once.", "release": "A confirmed pre-forward or adapter failure releases the reservation.", "manualReview": "An uncertain forwarding outcome stays reserved for manual review; automatic retry is disabled.", "idempotentReplay": "The same Idempotency-Key and request fingerprint replays the stored result without a second charge.", "idempotencyConflict": "Reusing an Idempotency-Key for a different request returns HTTP 409.", "insufficientCredits": "Insufficient available credits returns HTTP 402 before provider forwarding."}}}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "返回自定义充值范围、¥1=10 credits、9 类业务操作固定价格与扣费策略。\n\n何时使用：生成客户端价格展示或调用前预算时读取；不要硬编码另一份价格表。\n\n认证：无需登录；仅公开读取。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可指数退避重试。", "x-purpose": "返回自定义充值范围、¥1=10 credits、9 类业务操作固定价格与扣费策略。", "x-when-to-use": "生成客户端价格展示或调用前预算时读取；不要硬编码另一份价格表。", "x-authentication": "无需登录；仅公开读取。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可指数退避重试。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "读取 Gateway canonical 价格", "purpose": "返回自定义充值范围、¥1=10 credits、9 类业务操作固定价格与扣费策略。", "whenToUse": "生成客户端价格展示或调用前预算时读取；不要硬编码另一份价格表。", "authentication": "无需登录；仅公开读取。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "requestExample": null, "success": {"status": 200, "example": {"currency": "CNY", "amountUnit": "fen", "minAmountFen": 100, "maxAmountFen": 1000000, "stepAmountFen": 100, "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "paymentMode": "local-simulated", "productionPayment": "NOT_RUN", "operations": [{"operation": "agent.run", "path": "/v1/agent/run", "scope": "agent:run", "credits": 5, "cnyFen": 50, "cnyYuan": "0.50"}, {"operation": "model.chat", "path": "/v1/models/chat", "scope": "models:invoke", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "shopping.search", "path": "/v1/shopping/search", "scope": "shopping:search", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.compare", "path": "/v1/zhentiao/compare", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.filter", "path": "/v1/zhentiao/filter", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.links", "path": "/v1/zhentiao/links", "scope": "zhentiao:link", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.prepurchase_review", "path": "/v1/zhentiao/prepurchase-review", "scope": "zhentiao:read", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.recommend", "path": "/v1/zhentiao/recommend", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.search", "path": "/v1/zhentiao/search", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}], "chargePolicy": {"reserve": "Before forwarding, the fixed operation credits are reserved from the current Gateway project.", "settle": "A confirmed provider result settles the reservation exactly once.", "release": "A confirmed pre-forward or adapter failure releases the reservation.", "manualReview": "An uncertain forwarding outcome stays reserved for manual review; automatic retry is disabled.", "idempotentReplay": "The same Idempotency-Key and request fingerprint replays the stored result without a second charge.", "idempotencyConflict": "Reusing an Idempotency-Key for a different request returns HTTP 409.", "insufficientCredits": "Insufficient available credits returns HTTP 402 before provider forwarding."}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可指数退避重试。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/plans": {"get": {"operationId": "getDeprecatedGatewayPlansAlias", "summary": "读取已弃用价格兼容别名", "deprecated": true, "tags": ["Billing"], "responses": {"200": {"description": "Deprecated alias", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeprecatedPlansResponse"}, "example": {"deprecated": true, "canonical": "/v1/pricing", "pricing": {"currency": "CNY", "amountUnit": "fen", "minAmountFen": 100, "maxAmountFen": 1000000, "stepAmountFen": 100, "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "paymentMode": "local-simulated", "productionPayment": "NOT_RUN", "operations": [{"operation": "agent.run", "path": "/v1/agent/run", "scope": "agent:run", "credits": 5, "cnyFen": 50, "cnyYuan": "0.50"}, {"operation": "model.chat", "path": "/v1/models/chat", "scope": "models:invoke", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "shopping.search", "path": "/v1/shopping/search", "scope": "shopping:search", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.compare", "path": "/v1/zhentiao/compare", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.filter", "path": "/v1/zhentiao/filter", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.links", "path": "/v1/zhentiao/links", "scope": "zhentiao:link", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.prepurchase_review", "path": "/v1/zhentiao/prepurchase-review", "scope": "zhentiao:read", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.recommend", "path": "/v1/zhentiao/recommend", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.search", "path": "/v1/zhentiao/search", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}], "chargePolicy": {"reserve": "Before forwarding, the fixed operation credits are reserved from the current Gateway project.", "settle": "A confirmed provider result settles the reservation exactly once.", "release": "A confirmed pre-forward or adapter failure releases the reservation.", "manualReview": "An uncertain forwarding outcome stays reserved for manual review; automatic retry is disabled.", "idempotentReplay": "The same Idempotency-Key and request fingerprint replays the stored result without a second charge.", "idempotencyConflict": "Reusing an Idempotency-Key for a different request returns HTTP 409.", "insufficientCredits": "Insufficient available credits returns HTTP 402 before provider forwarding."}}}}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "为旧客户端返回 deprecated 标记与 canonical /v1/pricing 内容；不存在固定套餐。\n\n何时使用：仅迁移旧客户端时使用；新实现直接调用 /v1/pricing。\n\n认证：无需登录；仅公开读取。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可重试，但应尽快迁移 canonical 路径。", "x-purpose": "为旧客户端返回 deprecated 标记与 canonical /v1/pricing 内容；不存在固定套餐。", "x-when-to-use": "仅迁移旧客户端时使用；新实现直接调用 /v1/pricing。", "x-authentication": "无需登录；仅公开读取。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可重试，但应尽快迁移 canonical 路径。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "读取已弃用价格兼容别名", "purpose": "为旧客户端返回 deprecated 标记与 canonical /v1/pricing 内容；不存在固定套餐。", "whenToUse": "仅迁移旧客户端时使用；新实现直接调用 /v1/pricing。", "authentication": "无需登录；仅公开读取。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "requestExample": null, "success": {"status": 200, "example": {"deprecated": true, "canonical": "/v1/pricing", "pricing": {"currency": "CNY", "amountUnit": "fen", "minAmountFen": 100, "maxAmountFen": 1000000, "stepAmountFen": 100, "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "paymentMode": "local-simulated", "productionPayment": "NOT_RUN", "operations": [{"operation": "agent.run", "path": "/v1/agent/run", "scope": "agent:run", "credits": 5, "cnyFen": 50, "cnyYuan": "0.50"}, {"operation": "model.chat", "path": "/v1/models/chat", "scope": "models:invoke", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "shopping.search", "path": "/v1/shopping/search", "scope": "shopping:search", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.compare", "path": "/v1/zhentiao/compare", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.filter", "path": "/v1/zhentiao/filter", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.links", "path": "/v1/zhentiao/links", "scope": "zhentiao:link", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.prepurchase_review", "path": "/v1/zhentiao/prepurchase-review", "scope": "zhentiao:read", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.recommend", "path": "/v1/zhentiao/recommend", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.search", "path": "/v1/zhentiao/search", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}], "chargePolicy": {"reserve": "Before forwarding, the fixed operation credits are reserved from the current Gateway project.", "settle": "A confirmed provider result settles the reservation exactly once.", "release": "A confirmed pre-forward or adapter failure releases the reservation.", "manualReview": "An uncertain forwarding outcome stays reserved for manual review; automatic retry is disabled.", "idempotentReplay": "The same Idempotency-Key and request fingerprint replays the stored result without a second charge.", "idempotencyConflict": "Reusing an Idempotency-Key for a different request returns HTTP 409.", "insufficientCredits": "Insufficient available credits returns HTTP 402 before provider forwarding."}}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可重试，但应尽快迁移 canonical 路径。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/me": {"get": {"operationId": "getGatewayAccount", "summary": "读取当前 Gateway 项目摘要", "tags": ["Account"], "security": [{"GatewaySession": []}], "responses": {"200": {"description": "Current account", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountSummary"}, "example": {"account": {"accountId": "acct_example", "name": "个人 Gateway 账户", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example", "name": "个人项目"}, "credits": {"available": 230, "reserved": 0}, "latestOrder": null, "recentOrders": [], "apiKeys": [], "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>"}}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话缺失、失效、过期或已撤销。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话缺失、失效、过期或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "返回 masked identity、当前 personal project、credits、订单、Key 元数据、会话与新 CSRF。\n\n何时使用：控制台启动、刷新余额或取得当前 CSRF 时调用。\n\n认证：需要有效 Gateway HttpOnly 会话 Cookie。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可在重新登录后重试；每次成功响应都应替换旧 CSRF。", "x-purpose": "返回 masked identity、当前 personal project、credits、订单、Key 元数据、会话与新 CSRF。", "x-when-to-use": "控制台启动、刷新余额或取得当前 CSRF 时调用。", "x-authentication": "需要有效 Gateway HttpOnly 会话 Cookie。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可在重新登录后重试；每次成功响应都应替换旧 CSRF。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "读取当前 Gateway 项目摘要", "purpose": "返回 masked identity、当前 personal project、credits、订单、Key 元数据、会话与新 CSRF。", "whenToUse": "控制台启动、刷新余额或取得当前 CSRF 时调用。", "authentication": "需要有效 Gateway HttpOnly 会话 Cookie。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}], "requestExample": null, "success": {"status": 200, "example": {"account": {"accountId": "acct_example", "name": "个人 Gateway 账户", "oneAuthSubject": "oneauth_subject_example", "phoneMasked": "138****0000", "recoveryEmailMasked": "p***@example.invalid", "recoveryEmailState": "pending_verification"}, "project": {"projectId": "proj_example", "name": "个人项目"}, "credits": {"available": 230, "reserved": 0}, "latestOrder": null, "recentOrders": [], "apiKeys": [], "session": {"expiresAt": "2026-09-03T12:00:00+00:00"}, "csrfToken": "<session-bound-csrf-token>"}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可在重新登录后重试；每次成功响应都应替换旧 CSRF。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/keys": {"get": {"operationId": "listGatewayBusinessKeys", "summary": "列出当前项目业务 Key 元数据", "tags": ["Keys"], "security": [{"GatewaySession": []}], "responses": {"200": {"description": "Key metadata", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KeyList"}, "example": {"items": []}}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话缺失、失效、过期或已撤销。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话缺失、失效、过期或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "只返回 keyId、前缀、scope 与生命周期；永不返回历史明文 Key。\n\n何时使用：审计、撤销或展示当前项目 Key 时调用。\n\n认证：需要有效 Gateway HttpOnly 会话 Cookie。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可在重新登录后重试。", "x-purpose": "只返回 keyId、前缀、scope 与生命周期；永不返回历史明文 Key。", "x-when-to-use": "审计、撤销或展示当前项目 Key 时调用。", "x-authentication": "需要有效 Gateway HttpOnly 会话 Cookie。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可在重新登录后重试。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "列出当前项目业务 Key 元数据", "purpose": "只返回 keyId、前缀、scope 与生命周期；永不返回历史明文 Key。", "whenToUse": "审计、撤销或展示当前项目 Key 时调用。", "authentication": "需要有效 Gateway HttpOnly 会话 Cookie。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}], "requestExample": null, "success": {"status": 200, "example": {"items": []}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话缺失、失效、过期或已撤销。", "retry": "重新登录后再读。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可在重新登录后重试。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}, "post": {"operationId": "createGatewayBusinessKey", "summary": "创建项目级业务 Key", "tags": ["Keys"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateKeyRequest"}, "example": {"scopes": ["models:invoke"]}}}}, "responses": {"201": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateKeyResponse"}, "example": {"keyId": "key_example", "apiKey": "<shown-once-business-key>", "displayPrefix": "fk_example...0000", "scopes": ["models:invoke"], "state": "active", "expiresAt": null, "rotatedFromKeyId": null, "shownOnce": true}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, INVALID_SCOPE：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；scope 列表为空、重复、类型错误或不在允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "INVALID_SCOPE", "meaning": "scope 列表为空、重复、类型错误或不在允许列表。", "retry": "选择最小有效 scope 后重试。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID, CSRF_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。；Origin 或 CSRF 不匹配。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话无效。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}]}, "429": {"description": "RATE_LIMITED：Key 创建进入限流窗口。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "Key 创建进入限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "Key 创建进入限流窗口。", "retry": "等待窗口后再试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "parameters": [{"$ref": "#/components/parameters/CsrfToken"}, {"$ref": "#/components/parameters/OriginHeader"}], "security": [{"GatewaySession": [], "CsrfHeader": []}], "description": "按最小 scope 创建 Key；明文仅在本次成功响应显示一次。\n\n何时使用：需要新集成凭证或轮换旧 Key 时调用；调用方必须立即安全接收一次性明文。\n\n认证：需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：必需，且必须绑定当前 Cookie 会话。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；每次成功会创建新 Key。\n\n重试：若一次性明文未被安全接收，撤销该 Key 并创建新 Key；不要请求回显。", "x-purpose": "按最小 scope 创建 Key；明文仅在本次成功响应显示一次。", "x-when-to-use": "需要新集成凭证或轮换旧 Key 时调用；调用方必须立即安全接收一次性明文。", "x-authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "必需，且必须绑定当前 Cookie 会话。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；每次成功会创建新 Key。", "x-retry-policy": "若一次性明文未被安全接收，撤销该 Key 并创建新 Key；不要请求回显。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "INVALID_SCOPE", "meaning": "scope 列表为空、重复、类型错误或不在允许列表。", "retry": "选择最小有效 scope 后重试。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "Key 创建进入限流窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "创建项目级业务 Key", "purpose": "按最小 scope 创建 Key；明文仅在本次成功响应显示一次。", "whenToUse": "需要新集成凭证或轮换旧 Key 时调用；调用方必须立即安全接收一次性明文。", "authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "必需，且必须绑定当前 Cookie 会话。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "requestExample": {"scopes": ["models:invoke"]}, "success": {"status": 201, "example": {"keyId": "key_example", "apiKey": "<shown-once-business-key>", "displayPrefix": "fk_example...0000", "scopes": ["models:invoke"], "state": "active", "expiresAt": null, "rotatedFromKeyId": null, "shownOnce": true}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "INVALID_SCOPE", "meaning": "scope 列表为空、重复、类型错误或不在允许列表。", "retry": "选择最小有效 scope 后重试。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "Key 创建进入限流窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "若一次性明文未被安全接收，撤销该 Key 并创建新 Key；不要请求回显。", "idempotency": "不使用 Idempotency-Key；每次成功会创建新 Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/keys/{keyId}/revoke": {"post": {"operationId": "revokeGatewayBusinessKey", "summary": "撤销当前项目业务 Key", "tags": ["Keys"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmptyObject"}, "example": {}}}}, "responses": {"200": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KeyStateResponse"}, "example": {"keyId": "key_example", "state": "revoked"}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID, CSRF_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。；Origin 或 CSRF 不匹配。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话无效。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}]}, "404": {"description": "KEY_NOT_FOUND：Key 不存在或不属于当前项目。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "KEY_NOT_FOUND", "message": "Key 不存在或不属于当前项目。"}}}}, "x-error-codes": [{"status": 404, "code": "KEY_NOT_FOUND", "meaning": "Key 不存在或不属于当前项目。", "retry": "核对当前项目 Key 列表；不要跨 owner 探测。"}]}, "429": {"description": "RATE_LIMITED：Key 撤销进入限流窗口。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "Key 撤销进入限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "Key 撤销进入限流窗口。", "retry": "等待窗口后再试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "parameters": [{"$ref": "#/components/parameters/KeyId"}, {"$ref": "#/components/parameters/CsrfToken"}, {"$ref": "#/components/parameters/OriginHeader"}], "security": [{"GatewaySession": [], "CsrfHeader": []}], "description": "使指定 keyId 立即不可用于业务调用；跨项目资源统一不可见。\n\n何时使用：凭证轮换、泄露处置或集成下线时调用。\n\n认证：需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：必需，且必须绑定当前 Cookie 会话。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用 Idempotency-Key；已撤销资源不会恢复。\n\n重试：若网络结果不明，先重新列出 Key 状态；不要假设撤销失败。", "x-purpose": "使指定 keyId 立即不可用于业务调用；跨项目资源统一不可见。", "x-when-to-use": "凭证轮换、泄露处置或集成下线时调用。", "x-authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "必需，且必须绑定当前 Cookie 会话。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用 Idempotency-Key；已撤销资源不会恢复。", "x-retry-policy": "若网络结果不明，先重新列出 Key 状态；不要假设撤销失败。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "KEY_NOT_FOUND", "meaning": "Key 不存在或不属于当前项目。", "retry": "核对当前项目 Key 列表；不要跨 owner 探测。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "Key 撤销进入限流窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "撤销当前项目业务 Key", "purpose": "使指定 keyId 立即不可用于业务调用；跨项目资源统一不可见。", "whenToUse": "凭证轮换、泄露处置或集成下线时调用。", "authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "必需，且必须绑定当前 Cookie 会话。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "requestExample": {}, "success": {"status": 200, "example": {"keyId": "key_example", "state": "revoked"}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "KEY_NOT_FOUND", "meaning": "Key 不存在或不属于当前项目。", "retry": "核对当前项目 Key 列表；不要跨 owner 探测。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "Key 撤销进入限流窗口。", "retry": "等待窗口后再试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "若网络结果不明，先重新列出 Key 状态；不要假设撤销失败。", "idempotency": "不使用 Idempotency-Key；已撤销资源不会恢复。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/orders": {"post": {"operationId": "createGatewayRechargeOrder", "summary": "创建自定义充值订单", "tags": ["Billing"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrderRequest"}, "example": {"amountFen": 2300}}}}, "responses": {"201": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrderResponse"}, "example": {"orderId": "ord_example", "amountFen": 2300, "creditAmount": 230, "currency": "CNY", "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "state": "pending", "paymentMode": "local-simulated", "createdAt": "2026-09-03T04:00:00+00:00", "simulatedPaidAt": null, "creditedAt": null, "idempotentReplay": false}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, RECHARGE_AMOUNT_INVALID, IDEMPOTENCY_KEY_REQUIRED：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；amountFen 不是 100..1000000 范围内的 100 倍数，或幂等键缺失。；Idempotency-Key 缺失、为空或超过 128 字符。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "RECHARGE_AMOUNT_INVALID", "meaning": "amountFen 不是 100..1000000 范围内的 100 倍数，或幂等键缺失。", "retry": "修正金额并使用新键。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID, CSRF_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。；Origin 或 CSRF 不匹配。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话无效。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}]}, "404": {"description": "SIMULATED_PAYMENT_DISABLED：当前运行态未显式开放本地模拟充值。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "SIMULATED_PAYMENT_DISABLED", "message": "当前运行态未显式开放本地模拟充值。"}}}}, "x-error-codes": [{"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT：同 project 幂等键已绑定另一金额。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "同 project 幂等键已绑定另一金额。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "同 project 幂等键已绑定另一金额。", "retry": "使用新键创建不同金额订单。"}]}, "429": {"description": "RATE_LIMITED：订单创建限流。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "订单创建限流。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "订单创建限流。", "retry": "等待窗口后重试。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "parameters": [{"$ref": "#/components/parameters/CsrfToken"}, {"$ref": "#/components/parameters/IdempotencyKey"}, {"$ref": "#/components/parameters/OriginHeader"}], "security": [{"GatewaySession": [], "CsrfHeader": []}], "description": "按整数分金额固化 CNY、credits 汇率、价格版本与项目 owner 快照。\n\n何时使用：用户确认充值金额后、进入显式模拟确认前调用。\n\n认证：需要有效会话 Cookie、精确 Origin、CSRF 与 Idempotency-Key。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：必需，且必须绑定当前 Cookie 会话。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：project + Idempotency-Key + 规范金额绑定；相同请求重放同一订单，不重复创建。\n\n重试：相同键与相同金额可安全重放；不要在不确定时换键。\n\n运行边界：真实支付、退款、发票与生产账务为 NOT_RUN；当前仅 local-simulated。", "x-purpose": "按整数分金额固化 CNY、credits 汇率、价格版本与项目 owner 快照。", "x-when-to-use": "用户确认充值金额后、进入显式模拟确认前调用。", "x-authentication": "需要有效会话 Cookie、精确 Origin、CSRF 与 Idempotency-Key。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "必需，且必须绑定当前 Cookie 会话。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "project + Idempotency-Key + 规范金额绑定；相同请求重放同一订单，不重复创建。", "x-retry-policy": "相同键与相同金额可安全重放；不要在不确定时换键。", "x-runtime-boundary": "真实支付、退款、发票与生产账务为 NOT_RUN；当前仅 local-simulated。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "RECHARGE_AMOUNT_INVALID", "meaning": "amountFen 不是 100..1000000 范围内的 100 倍数，或幂等键缺失。", "retry": "修正金额并使用新键。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "同 project 幂等键已绑定另一金额。", "retry": "使用新键创建不同金额订单。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "订单创建限流。", "retry": "等待窗口后重试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "创建自定义充值订单", "purpose": "按整数分金额固化 CNY、credits 汇率、价格版本与项目 owner 快照。", "whenToUse": "用户确认充值金额后、进入显式模拟确认前调用。", "authentication": "需要有效会话 Cookie、精确 Origin、CSRF 与 Idempotency-Key。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "必需，且必须绑定当前 Cookie 会话。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}], "requestExample": {"amountFen": 2300}, "success": {"status": 201, "example": {"orderId": "ord_example", "amountFen": 2300, "creditAmount": 230, "currency": "CNY", "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "state": "pending", "paymentMode": "local-simulated", "createdAt": "2026-09-03T04:00:00+00:00", "simulatedPaidAt": null, "creditedAt": null, "idempotentReplay": false}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 400, "code": "RECHARGE_AMOUNT_INVALID", "meaning": "amountFen 不是 100..1000000 范围内的 100 倍数，或幂等键缺失。", "retry": "修正金额并使用新键。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "同 project 幂等键已绑定另一金额。", "retry": "使用新键创建不同金额订单。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "订单创建限流。", "retry": "等待窗口后重试。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "相同键与相同金额可安全重放；不要在不确定时换键。", "idempotency": "project + Idempotency-Key + 规范金额绑定；相同请求重放同一订单，不重复创建。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": "真实支付、退款、发票与生产账务为 NOT_RUN；当前仅 local-simulated。"}}}, "/v1/orders/{orderId}/confirm": {"post": {"operationId": "confirmGatewayRechargeOrder", "summary": "显式确认本地模拟充值", "tags": ["Billing"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmptyObject"}, "example": {}}}}, "responses": {"200": {"description": "Success", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ConfirmOrderResponse"}, "example": {"orderId": "ord_example", "amountFen": 2300, "creditAmount": 230, "currency": "CNY", "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "state": "credited", "paymentMode": "local-simulated", "createdAt": "2026-09-03T04:00:00+00:00", "simulatedPaidAt": "2026-09-03T04:01:00+00:00", "creditedAt": "2026-09-03T04:01:00+00:00", "creditLotId": "lot_example", "creditedAmount": 230, "creditKind": "simulated_prepaid", "idempotentReplay": false}}}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "403": {"description": "ORIGIN_INVALID, CSRF_INVALID：浏览器 Origin 不是当前 Gateway 精确 Origin。；Origin 或 CSRF 不匹配。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORIGIN_INVALID", "message": "浏览器 Origin 不是当前 Gateway 精确 Origin。"}}}}, "x-error-codes": [{"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}]}, "401": {"description": "GATEWAY_AUTH_REQUIRED：会话无效。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "GATEWAY_AUTH_REQUIRED", "message": "会话无效。"}}}}, "x-error-codes": [{"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}]}, "404": {"description": "SIMULATED_PAYMENT_DISABLED, ORDER_NOT_FOUND：当前运行态未显式开放本地模拟充值。；订单不存在或不属于当前项目。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "SIMULATED_PAYMENT_DISABLED", "message": "当前运行态未显式开放本地模拟充值。"}}}}, "x-error-codes": [{"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}, {"status": 404, "code": "ORDER_NOT_FOUND", "meaning": "订单不存在或不属于当前项目。", "retry": "核对当前项目 recentOrders。"}]}, "409": {"description": "ORDER_NOT_PAYABLE, ORDER_CONFIRM_CONFLICT, ORDER_CREDIT_CONFLICT：订单当前状态不允许确认。；并发确认未取得唯一状态转换。；入账状态转换发生并发冲突。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "ORDER_NOT_PAYABLE", "message": "订单当前状态不允许确认。"}}}}, "x-error-codes": [{"status": 409, "code": "ORDER_NOT_PAYABLE", "meaning": "订单当前状态不允许确认。", "retry": "重新读取订单状态，不要盲目重复。"}, {"status": 409, "code": "ORDER_CONFIRM_CONFLICT", "meaning": "并发确认未取得唯一状态转换。", "retry": "重新读取订单状态并核对 credits。"}, {"status": 409, "code": "ORDER_CREDIT_CONFLICT", "meaning": "入账状态转换发生并发冲突。", "retry": "先读取 /v1/me 对账，禁止再次模拟付款。"}]}, "429": {"description": "RATE_LIMITED：确认操作限流。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "RATE_LIMITED", "message": "确认操作限流。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "确认操作限流。", "retry": "等待窗口后再查状态。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体未在截止时间内读完。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体未在截止时间内读完。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体超过服务端上限。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体超过服务端上限。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}]}}, "parameters": [{"$ref": "#/components/parameters/OrderId"}, {"$ref": "#/components/parameters/CsrfToken"}, {"$ref": "#/components/parameters/OriginHeader"}], "security": [{"GatewaySession": [], "CsrfHeader": []}], "description": "对当前项目订单执行 exactly-once simulated credit，写入 entitlement、credit lot 与 ledger。\n\n何时使用：仅本地验收时，在用户明确确认模拟付款后调用；不能作为真实付款证据。\n\n认证：需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。\n\nOrigin：浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。\n\nCSRF：必需，且必须绑定当前 Cookie 会话。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不使用客户端 Idempotency-Key；orderId 自身是 exactly-once 幂等边界。\n\n重试：结果不明时先读取 /v1/me；同一订单并发确认也只入账一次。\n\n运行边界：仅 local-simulated；真实支付确认与生产对账为 NOT_RUN。", "x-purpose": "对当前项目订单执行 exactly-once simulated credit，写入 entitlement、credit lot 与 ledger。", "x-when-to-use": "仅本地验收时，在用户明确确认模拟付款后调用；不能作为真实付款证据。", "x-authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "x-origin-policy": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "x-csrf-policy": "必需，且必须绑定当前 Cookie 会话。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不使用客户端 Idempotency-Key；orderId 自身是 exactly-once 幂等边界。", "x-retry-policy": "结果不明时先读取 /v1/me；同一订单并发确认也只入账一次。", "x-runtime-boundary": "仅 local-simulated；真实支付确认与生产对账为 NOT_RUN。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}, {"status": 404, "code": "ORDER_NOT_FOUND", "meaning": "订单不存在或不属于当前项目。", "retry": "核对当前项目 recentOrders。"}, {"status": 409, "code": "ORDER_NOT_PAYABLE", "meaning": "订单当前状态不允许确认。", "retry": "重新读取订单状态，不要盲目重复。"}, {"status": 409, "code": "ORDER_CONFIRM_CONFLICT", "meaning": "并发确认未取得唯一状态转换。", "retry": "重新读取订单状态并核对 credits。"}, {"status": 409, "code": "ORDER_CREDIT_CONFLICT", "meaning": "入账状态转换发生并发冲突。", "retry": "先读取 /v1/me 对账，禁止再次模拟付款。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "确认操作限流。", "retry": "等待窗口后再查状态。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "x-doc-detail": {"summary": "显式确认本地模拟充值", "purpose": "对当前项目订单执行 exactly-once simulated credit，写入 entitlement、credit lot 与 ledger。", "whenToUse": "仅本地验收时，在用户明确确认模拟付款后调用；不能作为真实付款证据。", "authentication": "需要有效会话 Cookie、精确 Origin 与 session-bound CSRF。", "origin": "浏览器写请求只接受当前 Gateway 精确 Origin；不得跨域调用。", "csrf": "必需，且必须绑定当前 Cookie 会话。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Origin", "required": true, "example": "https://api.funaokeji.com", "meaning": "必须与当前 Gateway origin 精确一致。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}, {"name": "Cookie", "required": true, "example": "funao_gateway_session=<session-cookie>", "meaning": "HttpOnly Gateway 会话 Cookie；不要写入日志或脚本存储。"}, {"name": "X-CSRF-Token", "required": true, "example": "<session-bound-csrf-token>", "meaning": "从当前会话响应取得并与 Cookie 会话绑定。"}], "requestExample": {}, "success": {"status": 200, "example": {"orderId": "ord_example", "amountFen": 2300, "creditAmount": 230, "currency": "CNY", "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "state": "credited", "paymentMode": "local-simulated", "createdAt": "2026-09-03T04:00:00+00:00", "simulatedPaidAt": "2026-09-03T04:01:00+00:00", "creditedAt": "2026-09-03T04:01:00+00:00", "creditLotId": "lot_example", "creditedAmount": 230, "creditKind": "simulated_prepaid", "idempotentReplay": false}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 403, "code": "ORIGIN_INVALID", "meaning": "浏览器 Origin 不是当前 Gateway 精确 Origin。", "retry": "回到 canonical Gateway 页面重新发起。"}, {"status": 401, "code": "GATEWAY_AUTH_REQUIRED", "meaning": "会话无效。", "retry": "重新登录。"}, {"status": 403, "code": "CSRF_INVALID", "meaning": "Origin 或 CSRF 不匹配。", "retry": "刷新 /v1/me 后重试。"}, {"status": 404, "code": "SIMULATED_PAYMENT_DISABLED", "meaning": "当前运行态未显式开放本地模拟充值。", "retry": "不要重试；等待正式支付或本地授权配置。"}, {"status": 404, "code": "ORDER_NOT_FOUND", "meaning": "订单不存在或不属于当前项目。", "retry": "核对当前项目 recentOrders。"}, {"status": 409, "code": "ORDER_NOT_PAYABLE", "meaning": "订单当前状态不允许确认。", "retry": "重新读取订单状态，不要盲目重复。"}, {"status": 409, "code": "ORDER_CONFIRM_CONFLICT", "meaning": "并发确认未取得唯一状态转换。", "retry": "重新读取订单状态并核对 credits。"}, {"status": 409, "code": "ORDER_CREDIT_CONFLICT", "meaning": "入账状态转换发生并发冲突。", "retry": "先读取 /v1/me 对账，禁止再次模拟付款。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "确认操作限流。", "retry": "等待窗口后再查状态。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体未在截止时间内读完。", "retry": "可在确认服务可达后使用新请求重试。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体超过服务端上限。", "retry": "缩小请求体后再发；原样重试无效。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host；不要自动跟随未知跳转。"}], "retry": "结果不明时先读取 /v1/me；同一订单并发确认也只入账一次。", "idempotency": "不使用客户端 Idempotency-Key；orderId 自身是 exactly-once 幂等边界。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": "仅 local-simulated；真实支付确认与生产对账为 NOT_RUN。"}}}, "/openapi.json": {"get": {"operationId": "getGatewayOpenApi", "summary": "下载 OpenAPI 3.1 契约", "tags": ["Documentation"], "responses": {"200": {"description": "OpenAPI document", "content": {"application/json": {"schema": {"type": "object"}, "example": {"openapi": "3.1.0", "info": {"title": "副脑中转站 Gateway API", "version": "2026-09-03"}}}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "返回 24 个公开操作、schema、示例、逐操作错误、认证与扣费扩展。\n\n何时使用：生成 SDK、静态校验或核对客户端实现时使用。\n\n认证：无需登录；仅公开读取。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可重试。", "x-purpose": "返回 24 个公开操作、schema、示例、逐操作错误、认证与扣费扩展。", "x-when-to-use": "生成 SDK、静态校验或核对客户端实现时使用。", "x-authentication": "无需登录；仅公开读取。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可重试。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "下载 OpenAPI 3.1 契约", "purpose": "返回 24 个公开操作、schema、示例、逐操作错误、认证与扣费扩展。", "whenToUse": "生成 SDK、静态校验或核对客户端实现时使用。", "authentication": "无需登录；仅公开读取。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "requestExample": null, "success": {"status": 200, "example": {"openapi": "3.1.0", "info": {"title": "副脑中转站 Gateway API", "version": "2026-09-03"}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可重试。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/llms.txt": {"get": {"operationId": "getGatewayLlmsText", "summary": "读取 AI 客户端契约摘要", "tags": ["Documentation"], "responses": {"200": {"description": "Plain-text contract", "content": {"text/plain": {"schema": {"type": "string"}, "example": "# 副脑中转站 Gateway API\n..."}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "按 24 个操作给出用途、认证、字段、示例、响应、错误、重试、幂等与价格。\n\n何时使用：让 AI 编码客户端在不解析 HTML 时取得足够合同上下文。\n\n认证：无需登录；仅公开读取。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可重试。", "x-purpose": "按 24 个操作给出用途、认证、字段、示例、响应、错误、重试、幂等与价格。", "x-when-to-use": "让 AI 编码客户端在不解析 HTML 时取得足够合同上下文。", "x-authentication": "无需登录；仅公开读取。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可重试。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "读取 AI 客户端契约摘要", "purpose": "按 24 个操作给出用途、认证、字段、示例、响应、错误、重试、幂等与价格。", "whenToUse": "让 AI 编码客户端在不解析 HTML 时取得足够合同上下文。", "authentication": "无需登录；仅公开读取。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "requestExample": null, "success": {"status": 200, "example": "# 副脑中转站 Gateway API\n..."}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可重试。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/docs": {"get": {"operationId": "getGatewayHtmlDocs", "summary": "阅读人类版 Gateway API 文档", "tags": ["Documentation"], "responses": {"200": {"description": "HTML documentation", "content": {"text/html": {"schema": {"type": "string"}, "example": "<!doctype html><html lang=\"zh-CN\">...</html>"}}}, "400": {"description": "REQUEST_TARGET_INVALID：HTTP request-target 不是安全的 origin-form 路径。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能生成公开响应。", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能生成公开响应。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}]}}, "description": "渲染与 OpenAPI 同源的逐操作用途、字段、示例、错误和扣费信息。\n\n何时使用：人工接入、排障和评审契约时使用。\n\n认证：无需登录；仅公开读取。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：不扣费；本操作不预留或结算 Gateway credits。\n\n幂等：不需要 Idempotency-Key。\n\n重试：安全 GET 可重试。", "x-purpose": "渲染与 OpenAPI 同源的逐操作用途、字段、示例、错误和扣费信息。", "x-when-to-use": "人工接入、排障和评审契约时使用。", "x-authentication": "无需登录；仅公开读取。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "x-billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "x-idempotency": "不需要 Idempotency-Key。", "x-retry-policy": "安全 GET 可重试。", "x-runtime-boundary": "", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "x-doc-detail": {"summary": "阅读人类版 Gateway API 文档", "purpose": "渲染与 OpenAPI 同源的逐操作用途、字段、示例、错误和扣费信息。", "whenToUse": "人工接入、排障和评审契约时使用。", "authentication": "无需登录；仅公开读取。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}], "requestExample": null, "success": {"status": 200, "example": "<!doctype html><html lang=\"zh-CN\">...</html>"}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能生成公开响应。", "retry": "指数退避；不要携带或记录秘密。"}], "retry": "安全 GET 可重试。", "idempotency": "不需要 Idempotency-Key。", "billing": {"billable": false, "summary": "不扣费；本操作不预留或结算 Gateway credits。"}, "runtimeBoundary": ""}}}, "/v1/models/chat": {"post": {"operationId": "invokeModelChat", "summary": "调用模型对话", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelChatRequest"}, "example": {"provider": "deepseek", "model": "mock-default", "prompt": "你好，请概括这段文本。"}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ModelChatSettledResponse"}, "example": {"status": "settled", "operation": "model.chat", "chargedCredits": 3, "data": {"provider": "deepseek", "model": "mock-default", "output": "本地模拟输出"}, "usage": {"inputUnits": 12, "outputUnits": 8, "totalUnits": 20}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, PROVIDER_NOT_ALLOWED, INVALID_MODEL, INVALID_PROMPT, MODEL_NOT_ALLOWED：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；provider 不在当前模型适配器集合。；model 必须是字符串。；prompt 缺失、不是字符串或去空白后为空。；model 不在已配置 provider 的别名白名单。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 不在当前模型适配器集合。", "retry": "改用已发布 provider。"}, {"status": 400, "code": "INVALID_MODEL", "meaning": "model 必须是字符串。", "retry": "传字符串 model 或省略以使用默认值。"}, {"status": 400, "code": "INVALID_PROMPT", "meaning": "prompt 缺失、不是字符串或去空白后为空。", "retry": "提供非空 prompt。"}, {"status": 400, "code": "MODEL_NOT_ALLOWED", "meaning": "model 不在已配置 provider 的别名白名单。", "retry": "改用该 provider 已发布的 model 名称。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT：幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE, PROMPT_TOO_LARGE：请求体过大，供应商未转发。；prompt 超过已配置 provider 的字符上限。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 413, "code": "PROMPT_TOO_LARGE", "meaning": "prompt 超过已配置 provider 的字符上限。", "retry": "缩短 prompt 后使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID, PROVIDER_REQUEST_REJECTED：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。；模型 provider 明确拒绝请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "模型 provider 明确拒绝请求。", "retry": "修正 provider 可接受的请求后使用新幂等键。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE, PROVIDER_DISABLED, PROVIDER_AUTH_REQUIRED, PROVIDER_CIRCUIT_OPEN, PROVIDER_RATE_LIMITED, PROVIDER_CAPACITY_EXHAUSTED：真实 provider 未启用、凭据缺失、限流或暂时不可用。；真实模型 provider 在当前配置中关闭。；模型 provider 凭据在调用时不可用。；模型 provider 的进程内熔断器仍在冷却。；模型 provider 返回限流。；模型 provider 传输并发容量暂时用尽，尚未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实模型 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "模型 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_CIRCUIT_OPEN", "meaning": "模型 provider 的进程内熔断器仍在冷却。", "retry": "等待冷却窗口后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "模型 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "模型 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 3, "x-cny-at-current-local-rate": "0.30", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "向固定模型 provider 提交 prompt，返回本地候选或已配置 provider 的公开输出。\n\n何时使用：需要单轮文本生成且已准备 models:invoke Key 时使用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "向固定模型 provider 提交 prompt，返回本地候选或已配置 provider 的公开输出。", "x-when-to-use": "需要单轮文本生成且已准备 models:invoke Key 时使用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 不在当前模型适配器集合。", "retry": "改用已发布 provider。"}, {"status": 400, "code": "INVALID_MODEL", "meaning": "model 必须是字符串。", "retry": "传字符串 model 或省略以使用默认值。"}, {"status": 400, "code": "INVALID_PROMPT", "meaning": "prompt 缺失、不是字符串或去空白后为空。", "retry": "提供非空 prompt。"}, {"status": 400, "code": "MODEL_NOT_ALLOWED", "meaning": "model 不在已配置 provider 的别名白名单。", "retry": "改用该 provider 已发布的 model 名称。"}, {"status": 413, "code": "PROMPT_TOO_LARGE", "meaning": "prompt 超过已配置 provider 的字符上限。", "retry": "缩短 prompt 后使用新幂等键。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实模型 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "模型 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_CIRCUIT_OPEN", "meaning": "模型 provider 的进程内熔断器仍在冷却。", "retry": "等待冷却窗口后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "模型 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "模型 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "模型 provider 明确拒绝请求。", "retry": "修正 provider 可接受的请求后使用新幂等键。"}], "x-doc-detail": {"summary": "调用模型对话", "purpose": "向固定模型 provider 提交 prompt，返回本地候选或已配置 provider 的公开输出。", "whenToUse": "需要单轮文本生成且已准备 models:invoke Key 时使用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"provider": "deepseek", "model": "mock-default", "prompt": "你好，请概括这段文本。"}, "success": {"status": 200, "example": {"status": "settled", "operation": "model.chat", "chargedCredits": 3, "data": {"provider": "deepseek", "model": "mock-default", "output": "本地模拟输出"}, "usage": {"inputUnits": 12, "outputUnits": 8, "totalUnits": 20}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 不在当前模型适配器集合。", "retry": "改用已发布 provider。"}, {"status": 400, "code": "INVALID_MODEL", "meaning": "model 必须是字符串。", "retry": "传字符串 model 或省略以使用默认值。"}, {"status": 400, "code": "INVALID_PROMPT", "meaning": "prompt 缺失、不是字符串或去空白后为空。", "retry": "提供非空 prompt。"}, {"status": 400, "code": "MODEL_NOT_ALLOWED", "meaning": "model 不在已配置 provider 的别名白名单。", "retry": "改用该 provider 已发布的 model 名称。"}, {"status": 413, "code": "PROMPT_TOO_LARGE", "meaning": "prompt 超过已配置 provider 的字符上限。", "retry": "缩短 prompt 后使用新幂等键。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实模型 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "模型 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_CIRCUIT_OPEN", "meaning": "模型 provider 的进程内熔断器仍在冷却。", "retry": "等待冷却窗口后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "模型 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "模型 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "模型 provider 明确拒绝请求。", "retry": "修正 provider 可接受的请求后使用新幂等键。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/shopping/search": {"post": {"operationId": "searchShopping", "summary": "搜索购物候选", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SearchRequest"}, "example": {"query": "预算 300 元的耳机", "providers": ["jd"], "sort": "relevance", "limit": 1}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShoppingSearchSettledResponse"}, "example": {"status": "settled", "operation": "shopping.search", "chargedCredits": 2, "data": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_QUERY, PROVIDER_NOT_ALLOWED, INVALID_LIMIT, INVALID_SORT, INVALID_FILTERS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；query 必须是非空字符串。；provider 或 providers 不在固定真挑 registry。；limit 必须是 1 到 3 的整数。；sort 不在 price_asc、relevance 白名单。；filters 只允许非负整数 maxPriceCents。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT：幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID, PROVIDER_REQUEST_REJECTED, PROVIDER_REDIRECT_FORBIDDEN：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。；真挑 provider 明确拒绝请求。；真挑 provider 返回不允许跟随的重定向。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE, PROVIDER_DISABLED, PROVIDER_AUTH_REQUIRED, PROVIDER_RATE_LIMITED, PROVIDER_CAPACITY_EXHAUSTED：真实 provider 未启用、凭据缺失、限流或暂时不可用。；真实真挑 provider 在当前配置中关闭。；真挑 provider 凭据在调用时不可用。；真挑 provider 返回限流。；真挑 provider 传输并发容量暂时用尽，尚未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 2, "x-cny-at-current-local-rate": "0.20", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "通过真挑 facade 搜索当前项目的购物候选；项目衍生理由只写入该项目缓存。\n\n何时使用：使用 shopping:search scope 做兼容搜索时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "通过真挑 facade 搜索当前项目的购物候选；项目衍生理由只写入该项目缓存。", "x-when-to-use": "使用 shopping:search scope 做兼容搜索时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "x-doc-detail": {"summary": "搜索购物候选", "purpose": "通过真挑 facade 搜索当前项目的购物候选；项目衍生理由只写入该项目缓存。", "whenToUse": "使用 shopping:search scope 做兼容搜索时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"query": "预算 300 元的耳机", "providers": ["jd"], "sort": "relevance", "limit": 1}, "success": {"status": 200, "example": {"status": "settled", "operation": "shopping.search", "chargedCredits": 2, "data": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/search": {"post": {"operationId": "searchZhentiao", "summary": "搜索真挑候选", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SearchRequest"}, "example": {"query": "预算 300 元的耳机", "providers": ["jd"], "filters": {"maxPriceCents": 30000}, "sort": "relevance", "limit": 1}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoSearchSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.search", "chargedCredits": 2, "data": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_QUERY, PROVIDER_NOT_ALLOWED, INVALID_LIMIT, INVALID_SORT, INVALID_FILTERS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；query 必须是非空字符串。；provider 或 providers 不在固定真挑 registry。；limit 必须是 1 到 3 的整数。；sort 不在 price_asc、relevance 白名单。；filters 只允许非负整数 maxPriceCents。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT：幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID, PROVIDER_REQUEST_REJECTED, PROVIDER_REDIRECT_FORBIDDEN：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。；真挑 provider 明确拒绝请求。；真挑 provider 返回不允许跟随的重定向。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE, PROVIDER_DISABLED, PROVIDER_AUTH_REQUIRED, PROVIDER_RATE_LIMITED, PROVIDER_CAPACITY_EXHAUSTED：真实 provider 未启用、凭据缺失、限流或暂时不可用。；真实真挑 provider 在当前配置中关闭。；真挑 provider 凭据在调用时不可用。；真挑 provider 返回限流。；真挑 provider 传输并发容量暂时用尽，尚未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 2, "x-cny-at-current-local-rate": "0.20", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "按 query、provider、筛选与排序生成当前项目隔离的候选集合。\n\n何时使用：需要先获得 itemRef 供后续筛选、比较或推荐时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "按 query、provider、筛选与排序生成当前项目隔离的候选集合。", "x-when-to-use": "需要先获得 itemRef 供后续筛选、比较或推荐时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "x-doc-detail": {"summary": "搜索真挑候选", "purpose": "按 query、provider、筛选与排序生成当前项目隔离的候选集合。", "whenToUse": "需要先获得 itemRef 供后续筛选、比较或推荐时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"query": "预算 300 元的耳机", "providers": ["jd"], "filters": {"maxPriceCents": 30000}, "sort": "relevance", "limit": 1}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.search", "chargedCredits": 2, "data": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "sort 不在 price_asc、relevance 白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 只允许非负整数 maxPriceCents。", "retry": "修正或移除 filters。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/filter": {"post": {"operationId": "filterZhentiaoItems", "summary": "筛选已搜索候选", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FilterRequest"}, "example": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}], "criteria": {"maxPriceCents": 30000}}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoFilterSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.filter", "chargedCredits": 2, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "criteria": {"maxPriceCents": 30000}, "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ITEM_REFS, INVALID_ITEM_REF, INVALID_FILTERS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；itemRefs 必须包含 1 到 3 项。；itemRef 必须只含有效 provider 与非空 productId。；criteria 只允许非负整数 maxPriceCents。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "criteria 只允许非负整数 maxPriceCents。", "retry": "修正或移除 criteria。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT, PROVIDER_CAPABILITY_UNSUPPORTED：幂等键已绑定不同 operation、请求指纹或旧隔离版本。；真实真挑详情只能读取当前项目已有的已验证搜索快照。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE：真实 provider 未启用、凭据缺失、限流或暂时不可用。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 2, "x-cny-at-current-local-rate": "0.20", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "只读取当前项目此前验证的 itemRef，并按最高价格条件筛选。\n\n何时使用：已经通过同项目搜索取得 itemRef，需要缩小候选时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "只读取当前项目此前验证的 itemRef，并按最高价格条件筛选。", "x-when-to-use": "已经通过同项目搜索取得 itemRef，需要缩小候选时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "criteria 只允许非负整数 maxPriceCents。", "retry": "修正或移除 criteria。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "x-doc-detail": {"summary": "筛选已搜索候选", "purpose": "只读取当前项目此前验证的 itemRef，并按最高价格条件筛选。", "whenToUse": "已经通过同项目搜索取得 itemRef，需要缩小候选时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}], "criteria": {"maxPriceCents": 30000}}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.filter", "chargedCredits": 2, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "criteria": {"maxPriceCents": 30000}, "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "criteria 只允许非负整数 maxPriceCents。", "retry": "修正或移除 criteria。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 2, "cnyFen": 20, "cnyYuan": "0.20", "summary": "固定 2 credits（按当前本地规则折合 ¥0.20）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/compare": {"post": {"operationId": "compareZhentiaoItems", "summary": "比较已搜索候选", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CompareRequest"}, "example": {"itemRefs": [{"provider": "jd", "productId": "sku-a"}, {"provider": "douyin", "productId": "sku-b"}]}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoCompareSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.compare", "chargedCredits": 3, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-a"}, "title": "候选商品 A", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}, {"itemRef": {"provider": "douyin", "productId": "sku-b"}, "title": "候选商品 B", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "dimensions": ["priceCents", "availability", "highlights"], "mode": "local-mock"}, "usage": {"providerCalls": 2, "resultCount": 2}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ITEM_REFS, INVALID_ITEM_REF：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；itemRefs 必须包含 2 到 3 项。；itemRef 必须只含有效 provider 与非空 productId。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 2 到 3 项。", "retry": "传入 2 到 3 个当前项目 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT, PROVIDER_CAPABILITY_UNSUPPORTED：幂等键已绑定不同 operation、请求指纹或旧隔离版本。；真实真挑详情只能读取当前项目已有的已验证搜索快照。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE：真实 provider 未启用、凭据缺失、限流或暂时不可用。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 3, "x-cny-at-current-local-rate": "0.30", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "读取当前项目 2–3 个 itemRef，并返回价格、可用性与 highlights 比较维度。\n\n何时使用：同项目已有多个候选并需要并排比较时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "读取当前项目 2–3 个 itemRef，并返回价格、可用性与 highlights 比较维度。", "x-when-to-use": "同项目已有多个候选并需要并排比较时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 2 到 3 项。", "retry": "传入 2 到 3 个当前项目 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "x-doc-detail": {"summary": "比较已搜索候选", "purpose": "读取当前项目 2–3 个 itemRef，并返回价格、可用性与 highlights 比较维度。", "whenToUse": "同项目已有多个候选并需要并排比较时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"itemRefs": [{"provider": "jd", "productId": "sku-a"}, {"provider": "douyin", "productId": "sku-b"}]}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.compare", "chargedCredits": 3, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-a"}, "title": "候选商品 A", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}, {"itemRef": {"provider": "douyin", "productId": "sku-b"}, "title": "候选商品 B", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "dimensions": ["priceCents", "availability", "highlights"], "mode": "local-mock"}, "usage": {"providerCalls": 2, "resultCount": 2}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 2 到 3 项。", "retry": "传入 2 到 3 个当前项目 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/recommend": {"post": {"operationId": "recommendZhentiaoItems", "summary": "排序推荐已搜索候选", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecommendRequest"}, "example": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}], "preferences": {"priority": "balanced"}}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoRecommendSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.recommend", "chargedCredits": 3, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "preferences": {"priority": "balanced"}, "method": "deterministic-local-rule", "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ITEM_REFS, INVALID_ITEM_REF, INVALID_PREFERENCES：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；itemRefs 必须包含 1 到 3 项。；itemRef 必须只含有效 provider 与非空 productId。；preferences 只允许 price 或 balanced priority。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "preferences 只允许 price 或 balanced priority。", "retry": "修正或移除 preferences。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT, PROVIDER_CAPABILITY_UNSUPPORTED：幂等键已绑定不同 operation、请求指纹或旧隔离版本。；真实真挑详情只能读取当前项目已有的已验证搜索快照。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE：真实 provider 未启用、凭据缺失、限流或暂时不可用。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 3, "x-cny-at-current-local-rate": "0.30", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "只基于当前项目可读候选与 allowlisted preferences 生成确定性排序。\n\n何时使用：同项目已有 itemRef，需按 price 或 balanced 偏好排序时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "只基于当前项目可读候选与 allowlisted preferences 生成确定性排序。", "x-when-to-use": "同项目已有 itemRef，需按 price 或 balanced 偏好排序时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "preferences 只允许 price 或 balanced priority。", "retry": "修正或移除 preferences。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "x-doc-detail": {"summary": "排序推荐已搜索候选", "purpose": "只基于当前项目可读候选与 allowlisted preferences 生成确定性排序。", "whenToUse": "同项目已有 itemRef，需按 price 或 balanced 偏好排序时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}], "preferences": {"priority": "balanced"}}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.recommend", "chargedCredits": 3, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "preferences": {"priority": "balanced"}, "method": "deterministic-local-rule", "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "preferences 只允许 price 或 balanced priority。", "retry": "修正或移除 preferences。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 3, "cnyFen": 30, "cnyYuan": "0.30", "summary": "固定 3 credits（按当前本地规则折合 ¥0.30）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/prepurchase-review": {"post": {"operationId": "reviewZhentiaoPurchase", "summary": "生成购买前复核清单", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PrepurchaseReviewRequest"}, "example": {"itemRef": {"provider": "jd", "productId": "sku-example"}, "requirements": ["支持七天无理由"]}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoPrepurchaseReviewSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.prepurchase_review", "chargedCredits": 1, "data": {"itemRef": {"provider": "jd", "productId": "sku-example"}, "summary": "可作为候选，真实库存、到手价和售后仍待核对", "checks": [{"code": "price", "status": "known", "message": "本地样例价 1990 分"}], "limitations": ["仅本地合同样例"], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ITEM_REF, INVALID_REQUIREMENTS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；itemRef 必须只含有效 provider 与非空 productId。；requirements 必须是最多 5 项的字符串数组。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "requirements 必须是最多 5 项的字符串数组。", "retry": "修正或移除 requirements。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT, PROVIDER_CAPABILITY_UNSUPPORTED：幂等键已绑定不同 operation、请求指纹或旧隔离版本。；真实真挑详情只能读取当前项目已有的已验证搜索快照。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE：真实 provider 未启用、凭据缺失、限流或暂时不可用。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 1, "x-cny-at-current-local-rate": "0.10", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "读取当前项目候选快照，给出价格已知项、库存/到手价未知项与能力限制。\n\n何时使用：准备跳转购买前，需要提醒用户再次核对实时信息时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "读取当前项目候选快照，给出价格已知项、库存/到手价未知项与能力限制。", "x-when-to-use": "准备跳转购买前，需要提醒用户再次核对实时信息时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 1, "cnyFen": 10, "cnyYuan": "0.10", "summary": "固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "requirements 必须是最多 5 项的字符串数组。", "retry": "修正或移除 requirements。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "x-doc-detail": {"summary": "生成购买前复核清单", "purpose": "读取当前项目候选快照，给出价格已知项、库存/到手价未知项与能力限制。", "whenToUse": "准备跳转购买前，需要提醒用户再次核对实时信息时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"itemRef": {"provider": "jd", "productId": "sku-example"}, "requirements": ["支持七天无理由"]}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.prepurchase_review", "chargedCredits": 1, "data": {"itemRef": {"provider": "jd", "productId": "sku-example"}, "summary": "可作为候选，真实库存、到手价和售后仍待核对", "checks": [{"code": "price", "status": "known", "message": "本地样例价 1990 分"}], "limitations": ["仅本地合同样例"], "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "requirements 必须是最多 5 项的字符串数组。", "retry": "修正或移除 requirements。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 1, "cnyFen": 10, "cnyYuan": "0.10", "summary": "固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/zhentiao/links": {"post": {"operationId": "generateZhentiaoLinks", "summary": "生成已校验商品链接", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LinksRequest"}, "example": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}]}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ZhentiaoLinksSettledResponse"}, "example": {"status": "settled", "operation": "zhentiao.links", "chargedCredits": 1, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "productUrl": "https://u.jd.example/p/example"}], "disclosure": "部分链接可能为推广链接", "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ITEM_REFS, INVALID_ITEM_REF：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；itemRefs 必须包含 1 到 3 项。；itemRef 必须只含有效 provider 与非空 productId。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN：Key 不具备本操作所需 scope。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT：幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID, PROVIDER_LINK_FORBIDDEN, PROVIDER_REQUEST_REJECTED, PROVIDER_REDIRECT_FORBIDDEN：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。；provider 返回的商品链接不满足 HTTPS 与 host 白名单。；真挑 provider 明确拒绝请求。；真挑 provider 返回不允许跟随的重定向。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 502, "code": "PROVIDER_LINK_FORBIDDEN", "meaning": "provider 返回的商品链接不满足 HTTPS 与 host 白名单。", "retry": "不要打开链接；由运维核对 provider。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE, PROVIDER_DISABLED, PROVIDER_AUTH_REQUIRED, PROVIDER_RATE_LIMITED, PROVIDER_CAPACITY_EXHAUSTED：真实 provider 未启用、凭据缺失、限流或暂时不可用。；真实真挑 provider 在当前配置中关闭。；真挑 provider 凭据在调用时不可用。；真挑 provider 返回限流。；真挑 provider 传输并发容量暂时用尽，尚未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 1, "x-cny-at-current-local-rate": "0.10", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "为 1–3 个 itemRef 请求 allowlisted HTTPS 商品/推广链接，并附推广披露。\n\n何时使用：用户明确准备打开商品页且 Key 具备 zhentiao:link scope 时调用。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "为 1–3 个 itemRef 请求 allowlisted HTTPS 商品/推广链接，并附推广披露。", "x-when-to-use": "用户明确准备打开商品页且 Key 具备 zhentiao:link scope 时调用。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 1, "cnyFen": 10, "cnyYuan": "0.10", "summary": "固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 502, "code": "PROVIDER_LINK_FORBIDDEN", "meaning": "provider 返回的商品链接不满足 HTTPS 与 host 白名单。", "retry": "不要打开链接；由运维核对 provider。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "x-doc-detail": {"summary": "生成已校验商品链接", "purpose": "为 1–3 个 itemRef 请求 allowlisted HTTPS 商品/推广链接，并附推广披露。", "whenToUse": "用户明确准备打开商品页且 Key 具备 zhentiao:link scope 时调用。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"itemRefs": [{"provider": "jd", "productId": "sku-example"}]}, "success": {"status": 200, "example": {"status": "settled", "operation": "zhentiao.links", "chargedCredits": 1, "data": {"items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "productUrl": "https://u.jd.example/p/example"}], "disclosure": "部分链接可能为推广链接", "mode": "local-mock"}, "usage": {"providerCalls": 1, "resultCount": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 必须包含 1 到 3 项。", "retry": "传入当前项目搜索返回的 itemRef。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 必须只含有效 provider 与非空 productId。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 502, "code": "PROVIDER_LINK_FORBIDDEN", "meaning": "provider 返回的商品链接不满足 HTTPS 与 host 白名单。", "retry": "不要打开链接；由运维核对 provider。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 1, "cnyFen": 10, "cnyYuan": "0.10", "summary": "固定 1 credits（按当前本地规则折合 ¥0.10）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}, "/v1/agent/run": {"post": {"operationId": "runControlledAgent", "summary": "运行受控真挑 Agent 工具", "tags": ["Business operations"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentRunRequest"}, "example": {"tool": "zhentiao.assist", "arguments": {"operation": "search", "payload": {"query": "预算 300 元的耳机", "providers": ["jd"], "limit": 1}}}}}}, "responses": {"200": {"description": "Provider result confirmed and credits settled", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentRunSettledResponse"}, "example": {"status": "settled", "operation": "agent.run", "chargedCredits": 5, "data": {"tool": "zhentiao.assist", "result": {"operation": "search", "result": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}}}, "usage": {"toolCalls": 1}}}}}, "202": {"description": "Forwarding outcome uncertain and hold retained for manual review", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ManualReviewBusinessResponse"}}}, "x-manual-review": {"retryAllowed": false, "charging": "hold remains reserved pending operator review"}}, "400": {"description": "REQUEST_TARGET_INVALID, TRANSFER_ENCODING_UNSUPPORTED, CONTENT_LENGTH_INVALID, REQUEST_BODY_INCOMPLETE, INVALID_JSON, UNKNOWN_FIELDS, IDEMPOTENCY_KEY_REQUIRED, INVALID_ARGUMENTS, INVALID_QUERY, PROVIDER_NOT_ALLOWED, INVALID_LIMIT, INVALID_SORT, INVALID_FILTERS, INVALID_ITEM_REFS, INVALID_ITEM_REF, INVALID_PREFERENCES, INVALID_REQUIREMENTS：HTTP request-target 不是安全的 origin-form 路径。；服务不接受 Transfer-Encoding 请求体。；Content-Length 重复、格式错误或超出允许位数。；实际收到的请求体短于 Content-Length。；请求体不是 UTF-8 JSON 对象。；请求包含本操作合同以外的字段。；Idempotency-Key 缺失、为空或超过 128 字符。；arguments 必须是对象。；search query 必须是非空字符串。；provider 或 providers 不在固定真挑 registry。；search limit 必须是 1 到 3 的整数。；search sort 不在白名单。；filters 或 criteria 不符合公开结构。；itemRefs 数量不符合所选子操作。；itemRef 结构或内容无效。；recommend preferences 不在白名单。；prepurchase_review requirements 结构无效。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TARGET_INVALID", "message": "HTTP request-target 不是安全的 origin-form 路径。"}}}}, "x-error-codes": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 400, "code": "INVALID_ARGUMENTS", "meaning": "arguments 必须是对象。", "retry": "提供 operation 与 payload 对象。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "search query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "search limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "search sort 不在白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 或 criteria 不符合公开结构。", "retry": "修正筛选条件。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 数量不符合所选子操作。", "retry": "使用该子操作要求的 itemRef 数量。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 结构或内容无效。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "recommend preferences 不在白名单。", "retry": "改用 price 或 balanced。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "prepurchase_review requirements 结构无效。", "retry": "传最多 5 项字符串数组。"}]}, "500": {"description": "INTERNAL_ERROR：服务端未能完成公开写请求。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INTERNAL_ERROR", "message": "服务端未能完成公开写请求。"}}}}, "x-error-codes": [{"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}]}, "401": {"description": "UNAUTHORIZED, KEY_EXPIRED：Bearer Key 缺失、无效或已撤销。；Bearer Key 已过期。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "UNAUTHORIZED", "message": "Bearer Key 缺失、无效或已撤销。"}}}}, "x-error-codes": [{"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}]}, "402": {"description": "INSUFFICIENT_PAID_CREDITS：当前项目可用 credits 不足，未转发供应商。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "INSUFFICIENT_PAID_CREDITS", "message": "当前项目可用 credits 不足，未转发供应商。"}}}}, "x-error-codes": [{"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}]}, "403": {"description": "FORBIDDEN, TOOL_NOT_ALLOWED, TOOL_OPERATION_NOT_ALLOWED：Key 不具备本操作所需 scope。；tool 不是唯一允许的 zhentiao.assist。；Agent 子操作不在固定白名单。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "FORBIDDEN", "message": "Key 不具备本操作所需 scope。"}}}}, "x-error-codes": [{"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 403, "code": "TOOL_NOT_ALLOWED", "meaning": "tool 不是唯一允许的 zhentiao.assist。", "retry": "改用公开允许的 tool。"}, {"status": 403, "code": "TOOL_OPERATION_NOT_ALLOWED", "meaning": "Agent 子操作不在固定白名单。", "retry": "改用公开允许的子操作。"}]}, "408": {"description": "REQUEST_TIMEOUT：请求体读取超时，供应商未确认转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "REQUEST_TIMEOUT", "message": "请求体读取超时，供应商未确认转发。"}}}}, "x-error-codes": [{"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}]}, "409": {"description": "IDEMPOTENCY_CONFLICT, PROVIDER_CAPABILITY_UNSUPPORTED：幂等键已绑定不同 operation、请求指纹或旧隔离版本。；真实真挑详情只能读取当前项目已有的已验证搜索快照。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "IDEMPOTENCY_CONFLICT", "message": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。"}}}}, "x-error-codes": [{"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}]}, "413": {"description": "PAYLOAD_TOO_LARGE：请求体过大，供应商未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PAYLOAD_TOO_LARGE", "message": "请求体过大，供应商未转发。"}}}}, "x-error-codes": [{"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}]}, "421": {"description": "HOST_NOT_ALLOWED：Host 不属于 Gateway 精确允许列表。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "HOST_NOT_ALLOWED", "message": "Host 不属于 Gateway 精确允许列表。"}}}}, "x-error-codes": [{"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}]}, "429": {"description": "RATE_LIMITED：当前项目或凭证进入固定限流窗口。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "RATE_LIMITED", "message": "当前项目或凭证进入固定限流窗口。"}}}}, "x-error-codes": [{"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}]}, "502": {"description": "ADAPTER_FAILURE, PROVIDER_CONTRACT_INVALID, PROVIDER_REQUEST_REJECTED, PROVIDER_REDIRECT_FORBIDDEN：适配器在确认成功前失败，已释放预留 credits。；供应商拒绝请求或成功响应不符合公开合同。；真挑 provider 明确拒绝请求。；真挑 provider 返回不允许跟随的重定向。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "ADAPTER_FAILURE", "message": "适配器在确认成功前失败，已释放预留 credits。"}}}}, "x-error-codes": [{"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}]}, "503": {"description": "PROVIDER_UNAVAILABLE, PROVIDER_DISABLED, PROVIDER_AUTH_REQUIRED, PROVIDER_RATE_LIMITED, PROVIDER_CAPACITY_EXHAUSTED：真实 provider 未启用、凭据缺失、限流或暂时不可用。；真实真挑 provider 在当前配置中关闭。；真挑 provider 凭据在调用时不可用。；真挑 provider 返回限流。；真挑 provider 传输并发容量暂时用尽，尚未转发。", "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/ErrorResponse"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse"}]}, "example": {"error": {"code": "PROVIDER_UNAVAILABLE", "message": "真实 provider 未启用、凭据缺失、限流或暂时不可用。"}}}}, "x-error-codes": [{"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}]}}, "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "security": [{"BusinessApiKey": []}], "x-credits": 5, "x-cny-at-current-local-rate": "0.50", "x-charge-policy": "reserve-settle-release-or-manual-review", "x-idempotent-replay": "no-second-charge", "x-uncertain-outcome": "manual_review; do-not-blindly-retry", "description": "只允许 zhentiao.assist 与固定 search/filter/compare/recommend/prepurchase_review 子操作。\n\n何时使用：需要统一 Agent 包装且已准备 agent:run scope 时调用；不能生成链接。\n\n认证：需要具备本操作 scope 的 project-scoped Bearer 业务 Key。\n\nOrigin：使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。\n\nCSRF：不需要；不要发送或复制其他会话的 CSRF 值。\n\n扣费：固定 5 credits（按当前本地规则折合 ¥0.50）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。\n\n幂等：Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。\n\n重试：同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。\n\n运行边界：真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-purpose": "只允许 zhentiao.assist 与固定 search/filter/compare/recommend/prepurchase_review 子操作。", "x-when-to-use": "需要统一 Agent 包装且已准备 agent:run scope 时调用；不能生成链接。", "x-authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "x-origin-policy": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "x-csrf-policy": "不需要；不要发送或复制其他会话的 CSRF 值。", "x-required-headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "x-billing": {"billable": true, "credits": 5, "cnyFen": 50, "cnyYuan": "0.50", "summary": "固定 5 credits（按当前本地规则折合 ¥0.50）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "x-idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "x-retry-policy": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "x-runtime-boundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。", "x-errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 403, "code": "TOOL_NOT_ALLOWED", "meaning": "tool 不是唯一允许的 zhentiao.assist。", "retry": "改用公开允许的 tool。"}, {"status": 400, "code": "INVALID_ARGUMENTS", "meaning": "arguments 必须是对象。", "retry": "提供 operation 与 payload 对象。"}, {"status": 403, "code": "TOOL_OPERATION_NOT_ALLOWED", "meaning": "Agent 子操作不在固定白名单。", "retry": "改用公开允许的子操作。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "search query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "search limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "search sort 不在白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 或 criteria 不符合公开结构。", "retry": "修正筛选条件。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 数量不符合所选子操作。", "retry": "使用该子操作要求的 itemRef 数量。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 结构或内容无效。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "recommend preferences 不在白名单。", "retry": "改用 price 或 balanced。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "prepurchase_review requirements 结构无效。", "retry": "传最多 5 项字符串数组。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "x-doc-detail": {"summary": "运行受控真挑 Agent 工具", "purpose": "只允许 zhentiao.assist 与固定 search/filter/compare/recommend/prepurchase_review 子操作。", "whenToUse": "需要统一 Agent 包装且已准备 agent:run scope 时调用；不能生成链接。", "authentication": "需要具备本操作 scope 的 project-scoped Bearer 业务 Key。", "origin": "使用 https://api.funaokeji.com canonical origin；loopback 前缀仅用于本地验收。", "csrf": "不需要；不要发送或复制其他会话的 CSRF 值。", "headers": [{"name": "Host", "required": true, "example": "api.funaokeji.com", "meaning": "必须是 Gateway canonical 主机；其他 Host fail closed。"}, {"name": "Accept", "required": false, "example": "application/json", "meaning": "JSON 接口建议声明 application/json；文档端点按其媒体类型返回。"}, {"name": "Idempotency-Key", "required": true, "example": "request-unique-id", "meaning": "同 project 内绑定 operation 与规范化请求；同键改请求返回 409。"}, {"name": "Authorization", "required": true, "example": "Bearer <gateway-business-key>", "meaning": "项目所属、具备所需 scope 的 Gateway 业务 Key。"}, {"name": "Content-Type", "required": true, "example": "application/json", "meaning": "请求体必须是 JSON 对象。"}], "requestExample": {"tool": "zhentiao.assist", "arguments": {"operation": "search", "payload": {"query": "预算 300 元的耳机", "providers": ["jd"], "limit": 1}}}, "success": {"status": 200, "example": {"status": "settled", "operation": "agent.run", "chargedCredits": 5, "data": {"tool": "zhentiao.assist", "result": {"operation": "search", "result": {"query": "预算 300 元的耳机", "items": [{"itemRef": {"provider": "jd", "productId": "sku-example"}, "title": "候选商品", "priceCents": 1990, "currency": "CNY", "availability": "unknown", "highlights": ["公开属性示例"], "reason": "基于当前项目请求生成的候选理由", "testOnly": true}], "mode": "local-mock"}}}, "usage": {"toolCalls": 1}}}, "errors": [{"status": 400, "code": "REQUEST_TARGET_INVALID", "meaning": "HTTP request-target 不是安全的 origin-form 路径。", "retry": "改用以单个 / 开头且不含 authority、反斜杠、控制字符或编码分隔符的路径。"}, {"status": 400, "code": "TRANSFER_ENCODING_UNSUPPORTED", "meaning": "服务不接受 Transfer-Encoding 请求体。", "retry": "移除 Transfer-Encoding 并发送唯一、正确的 Content-Length。"}, {"status": 400, "code": "CONTENT_LENGTH_INVALID", "meaning": "Content-Length 重复、格式错误或超出允许位数。", "retry": "发送唯一的非负十进制 Content-Length。"}, {"status": 400, "code": "REQUEST_BODY_INCOMPLETE", "meaning": "实际收到的请求体短于 Content-Length。", "retry": "确认客户端完整发送请求体后发起新请求。"}, {"status": 400, "code": "INVALID_JSON", "meaning": "请求体不是 UTF-8 JSON 对象。", "retry": "修正 JSON 编码与对象结构后重试。"}, {"status": 400, "code": "UNKNOWN_FIELDS", "meaning": "请求包含本操作合同以外的字段。", "retry": "删除未知字段后重试。"}, {"status": 500, "code": "INTERNAL_ERROR", "meaning": "服务端未能完成公开写请求。", "retry": "指数退避；幂等操作保留原键，非幂等操作先核对状态。"}, {"status": 400, "code": "IDEMPOTENCY_KEY_REQUIRED", "meaning": "Idempotency-Key 缺失、为空或超过 128 字符。", "retry": "提供有效的新幂等键。"}, {"status": 401, "code": "UNAUTHORIZED", "meaning": "Bearer Key 缺失、无效或已撤销。", "retry": "换用当前项目有效 Key。"}, {"status": 401, "code": "KEY_EXPIRED", "meaning": "Bearer Key 已过期。", "retry": "创建具备最小 scope 的新 Key。"}, {"status": 402, "code": "INSUFFICIENT_PAID_CREDITS", "meaning": "当前项目可用 credits 不足，未转发供应商。", "retry": "充值后可用同一业务意图重新请求。"}, {"status": 403, "code": "FORBIDDEN", "meaning": "Key 不具备本操作所需 scope。", "retry": "创建最小所需 scope 的新 Key。"}, {"status": 408, "code": "REQUEST_TIMEOUT", "meaning": "请求体读取超时，供应商未确认转发。", "retry": "使用新幂等键重试。"}, {"status": 409, "code": "IDEMPOTENCY_CONFLICT", "meaning": "幂等键已绑定不同 operation、请求指纹或旧隔离版本。", "retry": "生成新幂等键；不要覆盖旧键。"}, {"status": 413, "code": "PAYLOAD_TOO_LARGE", "meaning": "请求体过大，供应商未转发。", "retry": "缩小请求体并使用新幂等键。"}, {"status": 421, "code": "HOST_NOT_ALLOWED", "meaning": "Host 不属于 Gateway 精确允许列表。", "retry": "改用 canonical Host。"}, {"status": 429, "code": "RATE_LIMITED", "meaning": "当前项目或凭证进入固定限流窗口。", "retry": "等待响应窗口后再试。"}, {"status": 502, "code": "ADAPTER_FAILURE", "meaning": "适配器在确认成功前失败，已释放预留 credits。", "retry": "修复适配器或请求后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_CONTRACT_INVALID", "meaning": "供应商拒绝请求或成功响应不符合公开合同。", "retry": "若返回 released 可修正后重试；否则按 manual_review 处理。"}, {"status": 503, "code": "PROVIDER_UNAVAILABLE", "meaning": "真实 provider 未启用、凭据缺失、限流或暂时不可用。", "retry": "指数退避；先确认不是 manual_review。"}, {"status": 403, "code": "TOOL_NOT_ALLOWED", "meaning": "tool 不是唯一允许的 zhentiao.assist。", "retry": "改用公开允许的 tool。"}, {"status": 400, "code": "INVALID_ARGUMENTS", "meaning": "arguments 必须是对象。", "retry": "提供 operation 与 payload 对象。"}, {"status": 403, "code": "TOOL_OPERATION_NOT_ALLOWED", "meaning": "Agent 子操作不在固定白名单。", "retry": "改用公开允许的子操作。"}, {"status": 400, "code": "INVALID_QUERY", "meaning": "search query 必须是非空字符串。", "retry": "提供非空 query。"}, {"status": 400, "code": "PROVIDER_NOT_ALLOWED", "meaning": "provider 或 providers 不在固定真挑 registry。", "retry": "改用公开允许的 provider。"}, {"status": 400, "code": "INVALID_LIMIT", "meaning": "search limit 必须是 1 到 3 的整数。", "retry": "修正 limit。"}, {"status": 400, "code": "INVALID_SORT", "meaning": "search sort 不在白名单。", "retry": "改用公开 sort。"}, {"status": 400, "code": "INVALID_FILTERS", "meaning": "filters 或 criteria 不符合公开结构。", "retry": "修正筛选条件。"}, {"status": 400, "code": "INVALID_ITEM_REFS", "meaning": "itemRefs 数量不符合所选子操作。", "retry": "使用该子操作要求的 itemRef 数量。"}, {"status": 400, "code": "INVALID_ITEM_REF", "meaning": "itemRef 结构或内容无效。", "retry": "使用未改写的搜索结果 itemRef。"}, {"status": 400, "code": "INVALID_PREFERENCES", "meaning": "recommend preferences 不在白名单。", "retry": "改用 price 或 balanced。"}, {"status": 400, "code": "INVALID_REQUIREMENTS", "meaning": "prepurchase_review requirements 结构无效。", "retry": "传最多 5 项字符串数组。"}, {"status": 409, "code": "PROVIDER_CAPABILITY_UNSUPPORTED", "meaning": "真实真挑详情只能读取当前项目已有的已验证搜索快照。", "retry": "先在同一项目搜索并使用返回的 itemRef。"}, {"status": 503, "code": "PROVIDER_DISABLED", "meaning": "真实真挑 provider 在当前配置中关闭。", "retry": "不要重试；等待运行配置显式启用。"}, {"status": 503, "code": "PROVIDER_AUTH_REQUIRED", "meaning": "真挑 provider 凭据在调用时不可用。", "retry": "由运维恢复凭据后再试。"}, {"status": 503, "code": "PROVIDER_RATE_LIMITED", "meaning": "真挑 provider 返回限流。", "retry": "按 provider 窗口退避后使用新请求。"}, {"status": 503, "code": "PROVIDER_CAPACITY_EXHAUSTED", "meaning": "真挑 provider 传输并发容量暂时用尽，尚未转发。", "retry": "等待短暂退避后使用新请求。"}, {"status": 502, "code": "PROVIDER_REQUEST_REJECTED", "meaning": "真挑 provider 明确拒绝请求。", "retry": "修正请求或 provider 配置后使用新幂等键。"}, {"status": 502, "code": "PROVIDER_REDIRECT_FORBIDDEN", "meaning": "真挑 provider 返回不允许跟随的重定向。", "retry": "不要跟随；由运维修正固定 endpoint。"}], "retry": "同键同规范请求可安全重放且不二次扣费；202 manual_review 时禁止自动重试。", "idempotency": "Idempotency-Key 按 project + operation + 规范请求指纹绑定；改请求返回 409。", "billing": {"billable": true, "credits": 5, "cnyFen": 50, "cnyYuan": "0.50", "summary": "固定 5 credits（按当前本地规则折合 ¥0.50）：转发前 reserve，成功 settle，确定失败 release，不确定结果 manual_review。"}, "runtimeBoundary": "真实 provider 与生产流量为 NOT_RUN；默认 provider-disabled 或 local-mock。"}}}}, "components": {"securitySchemes": {"GatewaySession": {"type": "apiKey", "in": "cookie", "name": "funao_gateway_session", "description": "Gateway HttpOnly、SameSite=Strict、host-only 会话；不得写入客户端持久存储或日志。"}, "CsrfHeader": {"type": "apiKey", "in": "header", "name": "X-CSRF-Token", "description": "由当前会话响应签发且只对该 Cookie 会话有效。"}, "BusinessApiKey": {"type": "http", "scheme": "bearer", "bearerFormat": "Gateway business key", "description": "项目级业务 Key；必须具备操作声明的最小 scope，明文仅创建时显示一次。"}}, "parameters": {"OriginHeader": {"name": "Origin", "in": "header", "required": true, "description": "浏览器写请求必须精确等于当前 Gateway origin；canonical 为 https://api.funaokeji.com。", "schema": {"type": "string", "format": "uri", "const": "https://api.funaokeji.com"}}, "CsrfToken": {"name": "X-CSRF-Token", "in": "header", "required": true, "description": "当前 Gateway 会话绑定的 CSRF token；从登录/注册或最新 /v1/me 响应取得。", "schema": {"type": "string", "minLength": 10}}, "IdempotencyKey": {"name": "Idempotency-Key", "in": "header", "required": true, "description": "调用方生成的 project-scoped 唯一键；同键同规范请求重放不二次扣费，同键改请求返回 409。", "schema": {"type": "string", "minLength": 1, "maxLength": 128}}, "OrderId": {"name": "orderId", "in": "path", "required": true, "description": "当前 Gateway project 所属的充值订单标识；跨 owner 与不存在统一 404。", "schema": {"type": "string", "pattern": "^ord_[A-Za-z0-9]+$"}}, "KeyId": {"name": "keyId", "in": "path", "required": true, "description": "当前 Gateway project 所属业务 Key 标识；不是明文凭证。", "schema": {"type": "string", "pattern": "^key_[A-Za-z0-9]+$"}}}, "responses": {"Error400": {"description": "HTTP 400 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error401": {"description": "HTTP 401 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error402": {"description": "HTTP 402 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error403": {"description": "HTTP 403 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error404": {"description": "HTTP 404 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error408": {"description": "HTTP 408 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error409": {"description": "HTTP 409 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error413": {"description": "HTTP 413 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error421": {"description": "HTTP 421 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error429": {"description": "HTTP 429 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error500": {"description": "HTTP 500 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error502": {"description": "HTTP 502 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}, "Error503": {"description": "HTTP 503 error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "example": {"error": {"code": "REQUEST_REJECTED", "message": "request was rejected"}}}}}}, "schemas": {"EmptyObject": {"type": "object", "properties": {}, "additionalProperties": false, "description": "EmptyObject 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ErrorDetail": {"type": "object", "properties": {"code": {"type": "string", "description": "稳定机器错误码或复核项代码。"}, "message": {"type": "string", "description": "面向调用者的安全说明，不应被用于推断重试策略。"}}, "additionalProperties": false, "required": ["code", "message"], "description": "ErrorDetail 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ErrorResponse": {"type": "object", "properties": {"error": {"$ref": "#/components/schemas/ErrorDetail", "description": "稳定机器错误结构。"}}, "additionalProperties": false, "required": ["error"], "description": "ErrorResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "SendCodeRequest": {"type": "object", "properties": {"phone": {"type": "string", "pattern": "^1[3-9][0-9]{9}$", "example": "13800000000", "description": "中国大陆手机号，格式为 1[3-9] 后接 9 位数字。"}}, "additionalProperties": false, "required": ["phone"], "description": "SendCodeRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "VerificationChallenge": {"type": "object", "properties": {"challengeId": {"type": "string", "pattern": "^gvc_[A-Za-z0-9]+$", "description": "短信验证 challenge 标识，绑定手机号、过期时间与单次消费状态。"}, "expiresInSeconds": {"type": "integer", "const": 300, "description": "challenge 自创建起的有效秒数。"}, "resendAfterSeconds": {"type": "integer", "const": 60, "description": "再次申请短信 challenge 前的最短等待秒数。"}}, "additionalProperties": false, "required": ["challengeId", "expiresInSeconds", "resendAfterSeconds"], "description": "VerificationChallenge 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "RegisterRequest": {"type": "object", "properties": {"phone": {"type": "string", "pattern": "^1[3-9][0-9]{9}$", "example": "13800000000", "description": "中国大陆手机号，格式为 1[3-9] 后接 9 位数字。"}, "verificationCode": {"type": "string", "pattern": "^[0-9]{6}$", "description": "用户持有的 6 位短信验证码；不得记录或回显。"}, "challengeId": {"type": "string", "pattern": "^gvc_[A-Za-z0-9]+$", "description": "短信验证 challenge 标识，绑定手机号、过期时间与单次消费状态。"}, "recoveryEmail": {"type": "string", "format": "email", "maxLength": 254, "example": "person@example.invalid", "description": "Stored as pending and cannot authenticate or reserve the address until separately verified."}, "password": {"type": "string", "minLength": 12, "maxLength": 128, "format": "password", "description": "用户持有的 12–128 字符密码；服务端只保存 scrypt 摘要。"}, "next": {"type": "string", "enum": ["/console"], "description": "成功认证后的 allowlisted Gateway 控制台路径。"}}, "additionalProperties": false, "required": ["phone", "verificationCode", "challengeId", "recoveryEmail", "password"], "description": "RegisterRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "LoginRequest": {"type": "object", "properties": {"identifier": {"type": "string", "description": "Verified mainland-China phone or verified recovery email"}, "password": {"type": "string", "minLength": 12, "maxLength": 128, "format": "password", "description": "用户持有的 12–128 字符密码；服务端只保存 scrypt 摘要。"}, "next": {"type": "string", "enum": ["/console"], "description": "成功认证后的 allowlisted Gateway 控制台路径。"}}, "additionalProperties": false, "required": ["identifier", "password"], "description": "LoginRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AuthResponse": {"type": "object", "properties": {"account": {"type": "object", "properties": {"accountId": {"type": "string", "description": "服务端生成的 Gateway 账户标识。"}, "oneAuthSubject": {"type": "string", "description": "已验证身份对应的不可变 OneAuth subject。"}, "phoneMasked": {"type": "string", "description": "脱敏手机号；不可用于认证。"}, "recoveryEmailMasked": {"type": "string", "description": "脱敏恢复邮箱；不可用于认证。"}, "recoveryEmailState": {"type": "string", "enum": ["pending_verification", "verified"], "description": "恢复邮箱处于 pending_verification 或 verified。"}}, "additionalProperties": false, "required": ["accountId", "oneAuthSubject", "phoneMasked", "recoveryEmailMasked", "recoveryEmailState"], "description": "当前 Gateway 账户；只包含脱敏身份和公开账户字段。"}, "project": {"type": "object", "properties": {"projectId": {"type": "string", "description": "服务端从认证主体取得的项目标识；不得由业务请求体覆盖。"}}, "additionalProperties": false, "required": ["projectId"], "description": "当前 Gateway personal project；credits、订单、Key 与缓存均按此隔离。"}, "session": {"type": "object", "properties": {"expiresAt": {"type": "string", "format": "date-time", "description": "资源或会话过期时间；永久资源可为 null。"}}, "additionalProperties": false, "required": ["expiresAt"], "description": "当前 Gateway 会话公开元数据，不含 Cookie 明文。"}, "csrfToken": {"type": "string", "description": "当前 Cookie 会话绑定的 CSRF token；只用于同源写请求。"}, "redirectTo": {"type": "string", "enum": ["/console", "/gateway/console"], "description": "服务端确认的认证后 Gateway 控制台路径。"}}, "additionalProperties": false, "required": ["account", "project", "session", "csrfToken", "redirectTo"], "description": "AuthResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "LogoutResponse": {"type": "object", "properties": {"state": {"type": "string", "const": "logged_out", "description": "资源、订单、Key 或业务扣费当前状态。"}}, "additionalProperties": false, "required": ["state"], "description": "LogoutResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "OperationPrice": {"type": "object", "properties": {"operation": {"type": "string", "description": "固定业务操作标识。"}, "path": {"type": "string", "description": "公开 canonical API 路径。"}, "scope": {"type": "string", "description": "调用业务操作所需的最小 Key scope。"}, "credits": {"type": "integer", "enum": [1, 2, 3, 5], "description": "业务操作扣费数量，或账户可用/预留 credits 结构。"}, "cnyFen": {"type": "integer", "enum": [10, 20, 30, 50], "description": "cnyFen 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "cnyYuan": {"type": "string", "enum": ["0.10", "0.20", "0.30", "0.50"], "description": "cnyYuan 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "path", "scope", "credits", "cnyFen", "cnyYuan"], "description": "OperationPrice 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "PricingResponse": {"type": "object", "properties": {"currency": {"type": "string", "const": "CNY", "description": "价格币种；当前固定为 CNY。"}, "amountUnit": {"type": "string", "const": "fen", "description": "amountUnit 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "minAmountFen": {"type": "integer", "const": 100, "description": "允许创建订单的最小人民币分金额。"}, "maxAmountFen": {"type": "integer", "const": 1000000, "description": "允许创建订单的最大人民币分金额。"}, "stepAmountFen": {"type": "integer", "const": 100, "description": "充值金额允许的人民币分步长。"}, "creditsPerYuan": {"type": "integer", "const": 10, "description": "服务端价格版本规定的每人民币元 credits 数。"}, "yuanPerCredit": {"type": "string", "const": "0.10", "description": "按当前本地价格规则折算的每 credit 人民币元字符串。"}, "pricingVersion": {"type": "string", "const": "gateway-custom-cny-10credits-v1", "description": "服务端订单价格快照版本。"}, "paymentMode": {"type": "string", "enum": ["disabled", "local-simulated"], "description": "当前充值能力模式；local-simulated 不是真实支付。"}, "productionPayment": {"type": "string", "const": "NOT_RUN", "description": "真实支付运行状态；当前明确为 NOT_RUN。"}, "operations": {"type": "array", "minItems": 9, "maxItems": 9, "items": {"$ref": "#/components/schemas/OperationPrice", "description": "operationsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "9 个可计费业务操作及固定价格列表。"}, "chargePolicy": {"type": "object", "additionalProperties": {"type": "string", "description": "chargePolicyValue 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "reserve、settle、release、manual_review 与幂等重放规则。"}}, "additionalProperties": false, "required": ["currency", "amountUnit", "minAmountFen", "maxAmountFen", "stepAmountFen", "creditsPerYuan", "yuanPerCredit", "pricingVersion", "paymentMode", "productionPayment", "operations", "chargePolicy"], "description": "PricingResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "DeprecatedPlansResponse": {"type": "object", "properties": {"deprecated": {"type": "boolean", "const": true, "description": "是否为只保留兼容性的旧入口。"}, "canonical": {"type": "string", "enum": ["/v1/pricing", "/gateway/api/pricing"], "description": "canonical 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "pricing": {"$ref": "#/components/schemas/PricingResponse", "description": "canonical Gateway 价格合同。"}}, "additionalProperties": false, "required": ["deprecated", "canonical", "pricing"], "description": "DeprecatedPlansResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CreateOrderRequest": {"type": "object", "properties": {"amountFen": {"type": "integer", "minimum": 100, "maximum": 1000000, "multipleOf": 100, "example": 2300, "description": "充值金额，单位为人民币分；必须是整数元范围内的 100 倍数。"}}, "additionalProperties": false, "required": ["amountFen"], "description": "CreateOrderRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "OrderResponse": {"type": "object", "properties": {"orderId": {"type": "string", "description": "当前项目所属充值订单标识。"}, "amountFen": {"type": "integer", "minimum": 100, "maximum": 1000000, "description": "充值金额，单位为人民币分；必须是整数元范围内的 100 倍数。"}, "creditAmount": {"type": "integer", "minimum": 10, "maximum": 100000, "description": "按服务端价格快照计算的 credits 数量。"}, "currency": {"type": "string", "const": "CNY", "description": "价格币种；当前固定为 CNY。"}, "creditsPerYuan": {"type": "integer", "const": 10, "description": "服务端价格版本规定的每人民币元 credits 数。"}, "yuanPerCredit": {"type": "string", "const": "0.10", "description": "按当前本地价格规则折算的每 credit 人民币元字符串。"}, "pricingVersion": {"type": "string", "const": "gateway-custom-cny-10credits-v1", "description": "服务端订单价格快照版本。"}, "state": {"type": "string", "enum": ["pending", "simulated_paid", "credited"], "description": "资源、订单、Key 或业务扣费当前状态。"}, "paymentMode": {"type": "string", "const": "local-simulated", "description": "当前充值能力模式；local-simulated 不是真实支付。"}, "createdAt": {"type": "string", "format": "date-time", "description": "服务端创建时间，含时区的 ISO-8601 时间。"}, "simulatedPaidAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "simulatedPaidAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "simulatedPaidAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "本地模拟确认发生时间；未确认时为 null。"}, "creditedAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "creditedAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "creditedAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "credits 实际入账时间；未入账时为 null。"}}, "additionalProperties": false, "required": ["orderId", "amountFen", "creditAmount", "currency", "creditsPerYuan", "yuanPerCredit", "pricingVersion", "state", "paymentMode", "createdAt", "simulatedPaidAt", "creditedAt"], "description": "OrderResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CreateOrderResponse": {"type": "object", "properties": {"orderId": {"type": "string", "description": "当前项目所属充值订单标识。"}, "amountFen": {"type": "integer", "minimum": 100, "maximum": 1000000, "description": "充值金额，单位为人民币分；必须是整数元范围内的 100 倍数。"}, "creditAmount": {"type": "integer", "minimum": 10, "maximum": 100000, "description": "按服务端价格快照计算的 credits 数量。"}, "currency": {"type": "string", "const": "CNY", "description": "价格币种；当前固定为 CNY。"}, "creditsPerYuan": {"type": "integer", "const": 10, "description": "服务端价格版本规定的每人民币元 credits 数。"}, "yuanPerCredit": {"type": "string", "const": "0.10", "description": "按当前本地价格规则折算的每 credit 人民币元字符串。"}, "pricingVersion": {"type": "string", "const": "gateway-custom-cny-10credits-v1", "description": "服务端订单价格快照版本。"}, "state": {"type": "string", "enum": ["pending", "simulated_paid", "credited"], "description": "资源、订单、Key 或业务扣费当前状态。"}, "paymentMode": {"type": "string", "const": "local-simulated", "description": "当前充值能力模式；local-simulated 不是真实支付。"}, "createdAt": {"type": "string", "format": "date-time", "description": "服务端创建时间，含时区的 ISO-8601 时间。"}, "simulatedPaidAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "simulatedPaidAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "simulatedPaidAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "本地模拟确认发生时间；未确认时为 null。"}, "creditedAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "creditedAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "creditedAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "credits 实际入账时间；未入账时为 null。"}, "idempotentReplay": {"type": "boolean", "description": "是否为相同 owner、键与请求指纹的存储结果重放。"}}, "additionalProperties": false, "required": ["orderId", "amountFen", "creditAmount", "currency", "creditsPerYuan", "yuanPerCredit", "pricingVersion", "state", "paymentMode", "createdAt", "simulatedPaidAt", "creditedAt", "idempotentReplay"], "description": "CreateOrderResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ConfirmOrderResponse": {"type": "object", "properties": {"orderId": {"type": "string", "description": "当前项目所属充值订单标识。"}, "amountFen": {"type": "integer", "minimum": 100, "maximum": 1000000, "description": "充值金额，单位为人民币分；必须是整数元范围内的 100 倍数。"}, "creditAmount": {"type": "integer", "minimum": 10, "maximum": 100000, "description": "按服务端价格快照计算的 credits 数量。"}, "currency": {"type": "string", "const": "CNY", "description": "价格币种；当前固定为 CNY。"}, "creditsPerYuan": {"type": "integer", "const": 10, "description": "服务端价格版本规定的每人民币元 credits 数。"}, "yuanPerCredit": {"type": "string", "const": "0.10", "description": "按当前本地价格规则折算的每 credit 人民币元字符串。"}, "pricingVersion": {"type": "string", "const": "gateway-custom-cny-10credits-v1", "description": "服务端订单价格快照版本。"}, "state": {"type": "string", "enum": ["pending", "simulated_paid", "credited"], "description": "资源、订单、Key 或业务扣费当前状态。"}, "paymentMode": {"type": "string", "const": "local-simulated", "description": "当前充值能力模式；local-simulated 不是真实支付。"}, "createdAt": {"type": "string", "format": "date-time", "description": "服务端创建时间，含时区的 ISO-8601 时间。"}, "simulatedPaidAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "simulatedPaidAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "simulatedPaidAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "本地模拟确认发生时间；未确认时为 null。"}, "creditedAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "creditedAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "creditedAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "credits 实际入账时间；未入账时为 null。"}, "creditLotId": {"anyOf": [{"type": "string", "description": "creditLotIdanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "creditLotIdanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "入账后生成的项目级 credit lot 标识；未生成时为 null。"}, "creditedAmount": {"type": "integer", "minimum": 1, "description": "本次 exactly-once 入账的 credits 数量。"}, "creditKind": {"type": "string", "const": "simulated_prepaid", "description": "credit lot 来源类型；local-simulated 固定为 simulated_prepaid。"}, "idempotentReplay": {"type": "boolean", "description": "是否为相同 owner、键与请求指纹的存储结果重放。"}}, "additionalProperties": false, "required": ["orderId", "amountFen", "creditAmount", "currency", "creditsPerYuan", "yuanPerCredit", "pricingVersion", "state", "paymentMode", "createdAt", "simulatedPaidAt", "creditedAt", "creditLotId", "creditedAmount", "creditKind", "idempotentReplay"], "description": "ConfirmOrderResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CreateKeyRequest": {"type": "object", "properties": {"scopes": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "enum": ["models:invoke", "shopping:search", "zhentiao:read", "zhentiao:link", "agent:run"], "description": "scopesItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "业务 Key 被授予的固定 scope 集合。"}}, "additionalProperties": false, "required": ["scopes"], "description": "CreateKeyRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CreateKeyResponse": {"type": "object", "properties": {"keyId": {"type": "string", "description": "项目级业务 Key 元数据标识，不是明文 Key。"}, "apiKey": {"type": "string", "description": "新创建业务 Key 的一次性明文；响应后无法再次读取。"}, "displayPrefix": {"type": "string", "description": "业务 Key 的安全展示前缀与尾部摘要，不是可用凭证。"}, "scopes": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "enum": ["models:invoke", "shopping:search", "zhentiao:read", "zhentiao:link", "agent:run"], "description": "scopesItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "业务 Key 被授予的固定 scope 集合。"}, "state": {"type": "string", "const": "active", "description": "资源、订单、Key 或业务扣费当前状态。"}, "expiresAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "expiresAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "expiresAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "资源或会话过期时间；永久资源可为 null。"}, "rotatedFromKeyId": {"anyOf": [{"type": "string", "description": "rotatedFromKeyIdanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "rotatedFromKeyIdanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "轮换来源 Key 标识；非轮换创建时为 null。"}, "shownOnce": {"type": "boolean", "const": true, "description": "业务 Key 明文是否仅在当前响应显示一次；固定为 true。"}}, "additionalProperties": false, "required": ["keyId", "apiKey", "displayPrefix", "scopes", "state", "expiresAt", "rotatedFromKeyId", "shownOnce"], "description": "CreateKeyResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "KeyMetadata": {"type": "object", "properties": {"keyId": {"type": "string", "description": "项目级业务 Key 元数据标识，不是明文 Key。"}, "displayPrefix": {"type": "string", "description": "业务 Key 的安全展示前缀与尾部摘要，不是可用凭证。"}, "scopes": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "enum": ["models:invoke", "shopping:search", "zhentiao:read", "zhentiao:link", "agent:run"], "description": "scopesItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "业务 Key 被授予的固定 scope 集合。"}, "state": {"type": "string", "enum": ["active", "revoked", "expired"], "description": "资源、订单、Key 或业务扣费当前状态。"}, "createdAt": {"type": "string", "format": "date-time", "description": "服务端创建时间，含时区的 ISO-8601 时间。"}, "revokedAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "revokedAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "revokedAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "业务 Key 撤销时间；仍有效时为 null。"}, "expiresAt": {"anyOf": [{"type": "string", "format": "date-time", "description": "expiresAtanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "expiresAtanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "资源或会话过期时间；永久资源可为 null。"}, "rotatedFromKeyId": {"anyOf": [{"type": "string", "description": "rotatedFromKeyIdanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "rotatedFromKeyIdanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "轮换来源 Key 标识；非轮换创建时为 null。"}}, "additionalProperties": false, "required": ["keyId", "displayPrefix", "scopes", "state", "createdAt", "revokedAt", "expiresAt", "rotatedFromKeyId"], "description": "KeyMetadata 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "KeyStateResponse": {"type": "object", "properties": {"keyId": {"type": "string", "description": "项目级业务 Key 元数据标识，不是明文 Key。"}, "state": {"type": "string", "const": "revoked", "description": "资源、订单、Key 或业务扣费当前状态。"}}, "additionalProperties": false, "required": ["keyId", "state"], "description": "KeyStateResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "KeyList": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/KeyMetadata", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}}, "additionalProperties": false, "required": ["items"], "description": "KeyList 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AccountSummaryAccount": {"type": "object", "properties": {"accountId": {"type": "string", "description": "服务端生成的 Gateway 账户标识。"}, "name": {"type": "string", "description": "当前 Gateway 账户或项目的显示名称。"}, "oneAuthSubject": {"type": "string", "description": "已验证身份对应的不可变 OneAuth subject。"}, "phoneMasked": {"type": "string", "description": "脱敏手机号；不可用于认证。"}, "recoveryEmailMasked": {"type": "string", "description": "脱敏恢复邮箱；不可用于认证。"}, "recoveryEmailState": {"type": "string", "enum": ["pending_verification", "verified"], "description": "恢复邮箱处于 pending_verification 或 verified。"}}, "additionalProperties": false, "required": ["accountId", "name", "oneAuthSubject", "phoneMasked", "recoveryEmailMasked", "recoveryEmailState"], "description": "AccountSummaryAccount 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "GatewayProject": {"type": "object", "properties": {"projectId": {"type": "string", "description": "服务端从认证主体取得的项目标识；不得由业务请求体覆盖。"}, "name": {"type": "string", "description": "当前 Gateway 账户或项目的显示名称。"}}, "additionalProperties": false, "required": ["projectId", "name"], "description": "GatewayProject 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "GatewaySession": {"type": "object", "properties": {"expiresAt": {"type": "string", "format": "date-time", "description": "资源或会话过期时间；永久资源可为 null。"}}, "additionalProperties": false, "required": ["expiresAt"], "description": "GatewaySession 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AccountSummary": {"type": "object", "properties": {"account": {"$ref": "#/components/schemas/AccountSummaryAccount", "description": "当前 Gateway 账户；只包含脱敏身份和公开账户字段。"}, "project": {"$ref": "#/components/schemas/GatewayProject", "description": "当前 Gateway personal project；credits、订单、Key 与缓存均按此隔离。"}, "credits": {"type": "object", "properties": {"available": {"type": "integer", "minimum": 0, "description": "available 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "reserved": {"type": "integer", "minimum": 0, "description": "reserved 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["available", "reserved"], "description": "业务操作扣费数量，或账户可用/预留 credits 结构。"}, "latestOrder": {"anyOf": [{"$ref": "#/components/schemas/OrderResponse", "description": "latestOrderanyOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"type": "null", "description": "latestOrderanyOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "当前项目最近订单；没有订单时为 null。"}, "recentOrders": {"type": "array", "items": {"$ref": "#/components/schemas/OrderResponse", "description": "recentOrdersItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前项目最近订单列表。"}, "apiKeys": {"type": "array", "items": {"$ref": "#/components/schemas/KeyMetadata", "description": "apiKeysItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前项目业务 Key 的元数据列表，不含明文 Key。"}, "session": {"$ref": "#/components/schemas/GatewaySession", "description": "当前 Gateway 会话公开元数据，不含 Cookie 明文。"}, "csrfToken": {"type": "string", "description": "当前 Cookie 会话绑定的 CSRF token；只用于同源写请求。"}}, "additionalProperties": false, "required": ["account", "project", "credits", "latestOrder", "recentOrders", "apiKeys", "session", "csrfToken"], "description": "AccountSummary 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ItemRef": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ShoppingItem": {"type": "object", "properties": {"itemRef": {"$ref": "#/components/schemas/ItemRef", "description": "固定 provider 与其 canonical productId 组成的商品引用。"}, "title": {"type": "string", "minLength": 1, "maxLength": 500, "description": "经过公开 allowlist 与长度校验的商品标题。"}, "priceCents": {"type": "integer", "minimum": 0, "description": "商品候选价格，单位为人民币分。"}, "currency": {"type": "string", "minLength": 1, "maxLength": 8, "description": "价格币种；当前固定为 CNY。"}, "availability": {"type": "string", "enum": ["available", "unavailable", "unknown"], "description": "候选可用性；unknown 表示仍需购买前复核。"}, "highlights": {"type": "array", "maxItems": 3, "items": {"type": "string", "minLength": 1, "maxLength": 200, "description": "highlightsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前项目候选的公开亮点，最多返回经过 allowlist 的短文本。"}, "reason": {"type": "string", "minLength": 1, "maxLength": 500, "description": "由当前项目查询衍生的候选理由；只允许所属项目读取。"}, "testOnly": {"type": "boolean", "description": "结果是否来自本地合同 fixture；true 表示不能当作真实平台结果。"}}, "additionalProperties": false, "required": ["itemRef", "title", "priceCents", "currency", "availability", "highlights", "reason", "testOnly"], "description": "ShoppingItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ModelChatRequest": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["alibaba-cloud", "deepseek", "doubao"], "description": "固定 allowlist 中的 provider 名称。"}, "model": {"type": "string", "description": "固定 provider 下的模型名；省略时使用服务端默认。"}, "prompt": {"type": "string", "minLength": 1, "description": "要交给固定模型适配器的非空文本。"}}, "additionalProperties": false, "required": ["prompt"], "description": "ModelChatRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "SearchRequest": {"type": "object", "properties": {"query": {"type": "string", "minLength": 1, "description": "当前项目本次搜索意图；可能影响 reason，不能跨项目共享。"}, "provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "providers": {"type": "array", "minItems": 1, "maxItems": 3, "uniqueItems": true, "items": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "providersItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "搜索时使用的 1–3 个去重 provider。"}, "filters": {"type": "object", "properties": {"maxPriceCents": {"type": "integer", "minimum": 0, "description": "允许的最高商品价格，单位为人民币分。"}}, "additionalProperties": false, "description": "搜索前允许的公开筛选条件。"}, "sort": {"type": "string", "enum": ["price_asc", "relevance"], "description": "候选排序方式：price_asc 或 relevance。"}, "limit": {"type": "integer", "minimum": 1, "maximum": 3, "description": "搜索最多返回的候选数，范围 1–3。"}}, "additionalProperties": false, "required": ["query"], "description": "SearchRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "FilterRequest": {"type": "object", "properties": {"itemRefs": {"type": "array", "minItems": 1, "maxItems": 3, "items": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "1–3 个商品引用；比较操作至少需要 2 个。"}, "criteria": {"type": "object", "properties": {"maxPriceCents": {"type": "integer", "minimum": 0, "description": "允许的最高商品价格，单位为人民币分。"}}, "additionalProperties": false, "description": "筛选结果实际采用的 allowlisted 条件。"}}, "additionalProperties": false, "required": ["itemRefs"], "description": "FilterRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CompareRequest": {"type": "object", "properties": {"itemRefs": {"type": "array", "minItems": 2, "maxItems": 3, "items": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "1–3 个商品引用；比较操作至少需要 2 个。"}}, "additionalProperties": false, "required": ["itemRefs"], "description": "CompareRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "RecommendRequest": {"type": "object", "properties": {"itemRefs": {"type": "array", "minItems": 1, "maxItems": 3, "items": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "1–3 个商品引用；比较操作至少需要 2 个。"}, "preferences": {"type": "object", "properties": {"priority": {"type": "string", "enum": ["price", "balanced"], "description": "推荐优先级；price 或 balanced。"}}, "additionalProperties": false, "description": "推荐允许的偏好对象；当前仅 priority。"}}, "additionalProperties": false, "required": ["itemRefs"], "description": "RecommendRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "PrepurchaseReviewRequest": {"type": "object", "properties": {"itemRef": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "requirements": {"type": "array", "maxItems": 5, "items": {"type": "string", "description": "requirementsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "购买前复核的可选短文本要求，最多 5 项。"}}, "additionalProperties": false, "required": ["itemRef"], "description": "PrepurchaseReviewRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "LinksRequest": {"type": "object", "properties": {"itemRefs": {"type": "array", "minItems": 1, "maxItems": 3, "items": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["douyin", "jd", "pinduoduo"], "description": "固定 allowlist 中的 provider 名称。"}, "productId": {"type": "string", "minLength": 1, "maxLength": 500, "description": "provider 内的 canonical 商品标识；区分大小写并在验证后去除边缘空白。"}}, "additionalProperties": false, "required": ["provider", "productId"], "description": "ItemRef 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "1–3 个商品引用；比较操作至少需要 2 个。"}}, "additionalProperties": false, "required": ["itemRefs"], "description": "LinksRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentArguments": {"oneOf": [{"type": "object", "properties": {"operation": {"type": "string", "const": "search", "description": "固定业务操作标识。"}, "payload": {"$ref": "#/components/schemas/SearchRequest", "description": "payload 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "payload"], "description": "agent.run 的 search 子操作与对应请求结构。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "filter", "description": "固定业务操作标识。"}, "payload": {"$ref": "#/components/schemas/FilterRequest", "description": "payload 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "payload"], "description": "agent.run 的 filter 子操作与对应请求结构。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "compare", "description": "固定业务操作标识。"}, "payload": {"$ref": "#/components/schemas/CompareRequest", "description": "payload 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "payload"], "description": "agent.run 的 compare 子操作与对应请求结构。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "recommend", "description": "固定业务操作标识。"}, "payload": {"$ref": "#/components/schemas/RecommendRequest", "description": "payload 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "payload"], "description": "agent.run 的 recommend 子操作与对应请求结构。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "prepurchase_review", "description": "固定业务操作标识。"}, "payload": {"$ref": "#/components/schemas/PrepurchaseReviewRequest", "description": "payload 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}, "additionalProperties": false, "required": ["operation", "payload"], "description": "agent.run 的 prepurchase_review 子操作与对应请求结构。"}], "description": "AgentArguments 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentRunRequest": {"type": "object", "properties": {"tool": {"type": "string", "const": "zhentiao.assist", "description": "受控 Agent 工具名；固定为 zhentiao.assist。"}, "arguments": {"$ref": "#/components/schemas/AgentArguments", "description": "受控 Agent 工具参数，只允许 operation 与 payload。"}}, "additionalProperties": false, "required": ["tool", "arguments"], "description": "AgentRunRequest 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ModelUsage": {"type": "object", "properties": {"inputUnits": {"type": "integer", "minimum": 0, "description": "模型适配器报告的输入计量单位；不得视作人民币金额。"}, "outputUnits": {"type": "integer", "minimum": 0, "description": "模型适配器报告的输出计量单位；不得视作人民币金额。"}, "totalUnits": {"type": "integer", "minimum": 0, "description": "provider 报告的总用量单位；本地适配器取 inputUnits 与 outputUnits 之和。", "example": 20}}, "additionalProperties": false, "required": ["inputUnits", "outputUnits", "totalUnits"], "description": "ModelUsage 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ProviderResultUsage": {"type": "object", "properties": {"providerCalls": {"type": "integer", "minimum": 0, "maximum": 3, "description": "本次操作实际触发或读取的 provider 调用计数。"}, "resultCount": {"type": "integer", "minimum": 0, "maximum": 3, "description": "本次操作返回的公开候选或结果数量。"}}, "additionalProperties": false, "required": ["providerCalls", "resultCount"], "description": "ProviderResultUsage 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentUsage": {"type": "object", "properties": {"toolCalls": {"type": "integer", "const": 1, "description": "受控 Agent 本次执行的工具调用次数；当前固定为 1。"}}, "additionalProperties": false, "required": ["toolCalls"], "description": "AgentUsage 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ModelChatData": {"type": "object", "properties": {"provider": {"type": "string", "enum": ["alibaba-cloud", "deepseek", "doubao"], "description": "固定 allowlist 中的 provider 名称。"}, "model": {"type": "string", "minLength": 1, "description": "固定 provider 下的模型名；省略时使用服务端默认。"}, "output": {"type": "string", "description": "模型适配器公开输出文本。"}}, "additionalProperties": false, "required": ["provider", "model", "output"], "description": "ModelChatData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "SearchData": {"type": "object", "properties": {"query": {"type": "string", "minLength": 1, "description": "当前项目本次搜索意图；可能影响 reason，不能跨项目共享。"}, "items": {"type": "array", "maxItems": 3, "items": {"$ref": "#/components/schemas/ShoppingItem", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["query", "items", "mode"], "description": "SearchData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "FilterData": {"type": "object", "properties": {"items": {"type": "array", "maxItems": 3, "items": {"$ref": "#/components/schemas/ShoppingItem", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}, "criteria": {"type": "object", "properties": {"maxPriceCents": {"type": "integer", "minimum": 0, "description": "允许的最高商品价格，单位为人民币分。"}}, "additionalProperties": false, "description": "筛选结果实际采用的 allowlisted 条件。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["items", "criteria", "mode"], "description": "FilterData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "CompareData": {"type": "object", "properties": {"items": {"type": "array", "minItems": 2, "maxItems": 3, "items": {"$ref": "#/components/schemas/ShoppingItem", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}, "dimensions": {"type": "array", "items": {"type": "string", "enum": ["priceCents", "availability", "highlights"], "description": "dimensionsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "比较响应实际使用的公开维度列表。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["items", "dimensions", "mode"], "description": "CompareData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "RecommendData": {"type": "object", "properties": {"items": {"type": "array", "maxItems": 3, "items": {"$ref": "#/components/schemas/ShoppingItem", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}, "preferences": {"type": "object", "properties": {"priority": {"type": "string", "enum": ["price", "balanced"], "description": "推荐优先级；price 或 balanced。"}}, "additionalProperties": false, "required": ["priority"], "description": "推荐允许的偏好对象；当前仅 priority。"}, "method": {"type": "string", "const": "deterministic-local-rule", "description": "推荐所用的公开、确定性方法标识。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["items", "preferences", "method", "mode"], "description": "RecommendData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ReviewCheck": {"type": "object", "properties": {"code": {"type": "string", "minLength": 1, "description": "稳定机器错误码或复核项代码。"}, "status": {"type": "string", "enum": ["known", "unknown"], "description": "业务结果、复核项或资源当前稳定状态。"}, "message": {"type": "string", "minLength": 1, "description": "面向调用者的安全说明，不应被用于推断重试策略。"}}, "additionalProperties": false, "required": ["code", "status", "message"], "description": "ReviewCheck 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "PrepurchaseReviewData": {"type": "object", "properties": {"itemRef": {"$ref": "#/components/schemas/ItemRef", "description": "固定 provider 与其 canonical productId 组成的商品引用。"}, "summary": {"type": "string", "minLength": 1, "description": "面向用户的购买前复核摘要。"}, "checks": {"type": "array", "items": {"$ref": "#/components/schemas/ReviewCheck", "description": "checksItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "购买前逐项复核结果。"}, "limitations": {"type": "array", "items": {"type": "string", "minLength": 1, "description": "limitationsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "购买前复核仍存在的能力或运行边界。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["itemRef", "summary", "checks", "limitations", "mode"], "description": "PrepurchaseReviewData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ProductLink": {"type": "object", "properties": {"itemRef": {"$ref": "#/components/schemas/ItemRef", "description": "固定 provider 与其 canonical productId 组成的商品引用。"}, "productUrl": {"type": "string", "format": "uri", "pattern": "^https://", "maxLength": 2048, "description": "经过 scheme、host 与端口 allowlist 验证的 HTTPS 商品链接。"}}, "additionalProperties": false, "required": ["itemRef", "productUrl"], "description": "ProductLink 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "LinksData": {"type": "object", "properties": {"items": {"type": "array", "minItems": 1, "maxItems": 3, "items": {"$ref": "#/components/schemas/ProductLink", "description": "itemsItem 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "description": "当前响应中的条目列表；其 owner 范围由当前 Gateway project 决定。"}, "disclosure": {"type": "string", "minLength": 1, "description": "商品链接的推广关系披露；展示链接时必须一并展示。"}, "mode": {"type": "string", "enum": ["local-mock", "truepick-http"], "description": "结果来源模式；local-mock 与 truepick-http 不会混用。"}}, "additionalProperties": false, "required": ["items", "disclosure", "mode"], "description": "LinksData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentToolResult": {"oneOf": [{"type": "object", "properties": {"operation": {"type": "string", "const": "search", "description": "固定业务操作标识。"}, "result": {"$ref": "#/components/schemas/SearchData", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["operation", "result"], "description": "agent.run 的 search 子操作成功结果。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "filter", "description": "固定业务操作标识。"}, "result": {"$ref": "#/components/schemas/FilterData", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["operation", "result"], "description": "agent.run 的 filter 子操作成功结果。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "compare", "description": "固定业务操作标识。"}, "result": {"$ref": "#/components/schemas/CompareData", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["operation", "result"], "description": "agent.run 的 compare 子操作成功结果。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "recommend", "description": "固定业务操作标识。"}, "result": {"$ref": "#/components/schemas/RecommendData", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["operation", "result"], "description": "agent.run 的 recommend 子操作成功结果。"}, {"type": "object", "properties": {"operation": {"type": "string", "const": "prepurchase_review", "description": "固定业务操作标识。"}, "result": {"$ref": "#/components/schemas/PrepurchaseReviewData", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["operation", "result"], "description": "agent.run 的 prepurchase_review 子操作成功结果。"}], "description": "AgentToolResult 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentRunData": {"type": "object", "properties": {"tool": {"type": "string", "const": "zhentiao.assist", "description": "受控 Agent 工具名；固定为 zhentiao.assist。"}, "result": {"$ref": "#/components/schemas/AgentToolResult", "description": "受控 Agent 子操作的公开结果，结构由 operation 精确决定。"}}, "additionalProperties": false, "required": ["tool", "result"], "description": "AgentRunData 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ModelChatSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "model.chat", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 3, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/ModelChatData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ModelUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ModelChatSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ShoppingSearchSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "shopping.search", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 2, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/SearchData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ShoppingSearchSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoSearchSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.search", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 2, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/SearchData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoSearchSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoFilterSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.filter", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 2, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/FilterData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoFilterSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoCompareSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.compare", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 3, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/CompareData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoCompareSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoRecommendSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.recommend", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 3, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/RecommendData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoRecommendSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoPrepurchaseReviewSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.prepurchase_review", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 1, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/PrepurchaseReviewData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoPrepurchaseReviewSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ZhentiaoLinksSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "zhentiao.links", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 1, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/LinksData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/ProviderResultUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "ZhentiaoLinksSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "AgentRunSettledResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "settled", "description": "业务结果、复核项或资源当前稳定状态。"}, "operation": {"type": "string", "const": "agent.run", "description": "固定业务操作标识。"}, "chargedCredits": {"type": "integer", "const": 5, "description": "chargedCredits 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "data": {"$ref": "#/components/schemas/AgentRunData", "description": "本次业务操作的公开结果对象；具体字段由 operation 决定。"}, "usage": {"$ref": "#/components/schemas/AgentUsage", "description": "本次业务操作的公开计量对象，不含内部成本或凭证。"}}, "additionalProperties": false, "required": ["status", "operation", "chargedCredits", "data", "usage"], "description": "AgentRunSettledResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "SettledBusinessResponse": {"oneOf": [{"$ref": "#/components/schemas/ModelChatSettledResponse", "description": "SettledBusinessResponseoneOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ShoppingSearchSettledResponse", "description": "SettledBusinessResponseoneOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoSearchSettledResponse", "description": "SettledBusinessResponseoneOf3 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoFilterSettledResponse", "description": "SettledBusinessResponseoneOf4 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoCompareSettledResponse", "description": "SettledBusinessResponseoneOf5 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoRecommendSettledResponse", "description": "SettledBusinessResponseoneOf6 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoPrepurchaseReviewSettledResponse", "description": "SettledBusinessResponseoneOf7 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ZhentiaoLinksSettledResponse", "description": "SettledBusinessResponseoneOf8 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/AgentRunSettledResponse", "description": "SettledBusinessResponseoneOf9 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "SettledBusinessResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ManualReviewBusinessResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "manual_review", "description": "业务结果、复核项或资源当前稳定状态。"}, "holdId": {"type": "string", "description": "不确定转发结果对应的项目级扣费 hold 标识。"}, "retryAllowed": {"type": "boolean", "const": false, "description": "是否允许客户端自动重试；manual_review 固定为 false。"}, "message": {"type": "string", "description": "面向调用者的安全说明，不应被用于推断重试策略。"}}, "additionalProperties": false, "required": ["status", "holdId", "retryAllowed", "message"], "description": "ManualReviewBusinessResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "ReleasedBusinessResponse": {"type": "object", "properties": {"status": {"type": "string", "const": "released", "description": "业务结果、复核项或资源当前稳定状态。"}, "error": {"$ref": "#/components/schemas/ErrorDetail", "description": "稳定机器错误结构。"}}, "additionalProperties": false, "required": ["status", "error"], "description": "ReleasedBusinessResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, "BusinessResponse": {"oneOf": [{"$ref": "#/components/schemas/SettledBusinessResponse", "description": "BusinessResponseoneOf1 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ManualReviewBusinessResponse", "description": "BusinessResponseoneOf2 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}, {"$ref": "#/components/schemas/ReleasedBusinessResponse", "description": "BusinessResponseoneOf3 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}], "description": "BusinessResponse 的公开合同字段；类型、必填性与取值限制以本 schema 为准。"}}}, "x-gateway-pricing": {"currency": "CNY", "amountUnit": "fen", "minAmountFen": 100, "maxAmountFen": 1000000, "stepAmountFen": 100, "creditsPerYuan": 10, "yuanPerCredit": "0.10", "pricingVersion": "gateway-custom-cny-10credits-v1", "paymentMode": "local-simulated", "productionPayment": "NOT_RUN", "operations": [{"operation": "agent.run", "path": "/v1/agent/run", "scope": "agent:run", "credits": 5, "cnyFen": 50, "cnyYuan": "0.50"}, {"operation": "model.chat", "path": "/v1/models/chat", "scope": "models:invoke", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "shopping.search", "path": "/v1/shopping/search", "scope": "shopping:search", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.compare", "path": "/v1/zhentiao/compare", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.filter", "path": "/v1/zhentiao/filter", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}, {"operation": "zhentiao.links", "path": "/v1/zhentiao/links", "scope": "zhentiao:link", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.prepurchase_review", "path": "/v1/zhentiao/prepurchase-review", "scope": "zhentiao:read", "credits": 1, "cnyFen": 10, "cnyYuan": "0.10"}, {"operation": "zhentiao.recommend", "path": "/v1/zhentiao/recommend", "scope": "zhentiao:read", "credits": 3, "cnyFen": 30, "cnyYuan": "0.30"}, {"operation": "zhentiao.search", "path": "/v1/zhentiao/search", "scope": "zhentiao:read", "credits": 2, "cnyFen": 20, "cnyYuan": "0.20"}], "chargePolicy": {"reserve": "Before forwarding, the fixed operation credits are reserved from the current Gateway project.", "settle": "A confirmed provider result settles the reservation exactly once.", "release": "A confirmed pre-forward or adapter failure releases the reservation.", "manualReview": "An uncertain forwarding outcome stays reserved for manual review; automatic retry is disabled.", "idempotentReplay": "The same Idempotency-Key and request fingerprint replays the stored result without a second charge.", "idempotencyConflict": "Reusing an Idempotency-Key for a different request returns HTTP 409.", "insufficientCredits": "Insufficient available credits returns HTTP 402 before provider forwarding."}}, "x-runtime-boundary": {"realSmsDelivery": "NOT_RUN", "productionOneAuth": "NOT_RUN", "realPayment": "NOT_RUN", "realProviders": "NOT_RUN", "productionDeployment": "NOT_RUN"}}