Files
lijiaoqiao/docs/supply_api_contract_openapi_draft_v1_2026-03-25.yaml

1105 lines
32 KiB
YAML
Raw Normal View History

openapi: 3.0.3
info:
title: Supply Console API Contract Draft
version: 1.0.0-draft
description: |
供应侧三大页面(账号挂载、套餐发布、收益结算)接口契约草案。
安全边界要求:
1) 仅接受平台鉴权头Authorization不接受 query key 鉴权。
2) 任何响应不得返回可复用上游凭证明文片段。
变更日志:
- 2026-03-27:新增幂等请求头组件与写操作挂载;补充 409/202 幂等语义示例。
- 2026-03-27:命名策略调整为 `/supply` 主路径;`/supplier` 保留为兼容 alias。
servers:
- url: https://api.example.com
description: Production
security:
- BearerAuth: []
tags:
- name: SupplyAccounts
- name: SupplyPackages
- name: SupplySettlements
- name: SupplyEarnings
- name: SupplierBilling
paths:
/api/v1/supply/accounts/verify:
post:
tags: [SupplyAccounts]
summary: 验证供应账号凭证可用性
operationId: verifySupplyAccount
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/VerifySupplyAccountRequest'
responses:
'200':
description: 验证成功
content:
application/json:
schema:
$ref: '#/components/schemas/VerifySupplyAccountResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'422':
$ref: '#/components/responses/BusinessError'
/api/v1/supply/accounts:
post:
tags: [SupplyAccounts]
summary: 创建供应账号
operationId: createSupplyAccount
parameters:
- $ref: '#/components/parameters/XRequestIdHeader'
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSupplyAccountRequest'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSupplyAccountResponse'
'202':
$ref: '#/components/responses/AcceptedInProgress'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'409':
$ref: '#/components/responses/Conflict'
'422':
$ref: '#/components/responses/BusinessError'
/api/v1/supply/accounts/{accountId}/activate:
post:
tags: [SupplyAccounts]
summary: 激活供应账号
operationId: activateSupplyAccount
parameters:
- $ref: '#/components/parameters/AccountIdParam'
responses:
'200':
description: 激活成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyAccountStatusResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/accounts/{accountId}/suspend:
post:
tags: [SupplyAccounts]
summary: 暂停供应账号
operationId: suspendSupplyAccount
parameters:
- $ref: '#/components/parameters/AccountIdParam'
responses:
'200':
description: 暂停成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyAccountStatusResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/accounts/{accountId}:
delete:
tags: [SupplyAccounts]
summary: 删除供应账号
operationId: deleteSupplyAccount
parameters:
- $ref: '#/components/parameters/AccountIdParam'
responses:
'204':
description: 删除成功
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/accounts/{accountId}/audit-logs:
get:
tags: [SupplyAccounts]
summary: 查询账号审计日志
operationId: listSupplyAccountAuditLogs
parameters:
- $ref: '#/components/parameters/AccountIdParam'
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/PageSizeParam'
responses:
'200':
description: 查询成功
content:
application/json:
schema:
$ref: '#/components/schemas/AuditLogListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
/api/v1/supply/packages/draft:
post:
tags: [SupplyPackages]
summary: 保存套餐草稿
operationId: saveSupplyPackageDraft
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SaveSupplyPackageDraftRequest'
responses:
'201':
description: 保存成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyPackageResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'422':
$ref: '#/components/responses/BusinessError'
/api/v1/supply/packages/{packageId}/publish:
post:
tags: [SupplyPackages]
summary: 发布套餐上架
operationId: publishSupplyPackage
parameters:
- $ref: '#/components/parameters/PackageIdParam'
- $ref: '#/components/parameters/XRequestIdHeader'
- $ref: '#/components/parameters/IdempotencyKeyHeader'
responses:
'200':
description: 发布成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyPackageStatusResponse'
'202':
$ref: '#/components/responses/AcceptedInProgress'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/packages/{packageId}/pause:
post:
tags: [SupplyPackages]
summary: 暂停售卖套餐
operationId: pauseSupplyPackage
parameters:
- $ref: '#/components/parameters/PackageIdParam'
responses:
'200':
description: 暂停成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyPackageStatusResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/packages/{packageId}/unlist:
post:
tags: [SupplyPackages]
summary: 下架套餐
operationId: unlistSupplyPackage
parameters:
- $ref: '#/components/parameters/PackageIdParam'
responses:
'200':
description: 下架成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyPackageStatusResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/packages/batch-price:
post:
tags: [SupplyPackages]
summary: 批量调价
operationId: batchUpdateSupplyPackagePrice
parameters:
- $ref: '#/components/parameters/XRequestIdHeader'
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BatchUpdateSupplyPackagePriceRequest'
responses:
'200':
description: 调价完成
content:
application/json:
schema:
$ref: '#/components/schemas/BatchUpdateSupplyPackagePriceResponse'
'202':
$ref: '#/components/responses/AcceptedInProgress'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/packages/{packageId}/clone:
post:
tags: [SupplyPackages]
summary: 复制套餐
operationId: cloneSupplyPackage
parameters:
- $ref: '#/components/parameters/PackageIdParam'
responses:
'201':
description: 复制成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyPackageResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
/api/v1/supply/billing:
get:
tags: [SupplierBilling]
summary: 查询供应方账单汇总canonical
operationId: getSupplyBilling
parameters:
- $ref: '#/components/parameters/StartDateParam'
- $ref: '#/components/parameters/EndDateParam'
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/PageSizeParam'
responses:
'200':
description: 查询成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplierBillingResponse'
'401':
$ref: '#/components/responses/Unauthorized'
/api/v1/supplier/billing:
get:
tags: [SupplierBilling]
summary: 查询供应方账单汇总alias兼容路径
description: |
Deprecated alias of `/api/v1/supply/billing`.
仅用于历史客户端兼容,不新增能力字段。
deprecated: true
operationId: getSupplierBillingAlias
parameters:
- $ref: '#/components/parameters/StartDateParam'
- $ref: '#/components/parameters/EndDateParam'
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/PageSizeParam'
responses:
'200':
description: 查询成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplierBillingResponse'
'401':
$ref: '#/components/responses/Unauthorized'
/api/v1/supply/settlements/withdraw:
post:
tags: [SupplySettlements]
summary: 发起提现申请
operationId: createSupplySettlementWithdraw
parameters:
- $ref: '#/components/parameters/XRequestIdHeader'
- $ref: '#/components/parameters/IdempotencyKeyHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWithdrawRequest'
responses:
'201':
description: 提现申请创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWithdrawResponse'
'202':
$ref: '#/components/responses/AcceptedInProgress'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/settlements/{settlementId}/cancel:
post:
tags: [SupplySettlements]
summary: 撤销提现申请
operationId: cancelSupplySettlementWithdraw
parameters:
- $ref: '#/components/parameters/SettlementIdParam'
- $ref: '#/components/parameters/XRequestIdHeader'
- $ref: '#/components/parameters/IdempotencyKeyHeader'
responses:
'200':
description: 撤销成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplySettlementStatusResponse'
'202':
$ref: '#/components/responses/AcceptedInProgress'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
/api/v1/supply/settlements/{settlementId}/statement:
get:
tags: [SupplySettlements]
summary: 下载对账单
operationId: downloadSupplySettlementStatement
parameters:
- $ref: '#/components/parameters/SettlementIdParam'
responses:
'200':
description: 下载地址
content:
application/json:
schema:
$ref: '#/components/schemas/SettlementStatementResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
/api/v1/supply/earnings/records:
get:
tags: [SupplyEarnings]
summary: 查询收益流水
operationId: listSupplyEarningRecords
parameters:
- $ref: '#/components/parameters/StartDateParam'
- $ref: '#/components/parameters/EndDateParam'
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/PageSizeParam'
responses:
'200':
description: 查询成功
content:
application/json:
schema:
$ref: '#/components/schemas/SupplyEarningRecordListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
AccountIdParam:
name: accountId
in: path
required: true
schema:
type: integer
format: int64
PackageIdParam:
name: packageId
in: path
required: true
schema:
type: integer
format: int64
SettlementIdParam:
name: settlementId
in: path
required: true
schema:
type: integer
format: int64
StartDateParam:
name: start_date
in: query
schema:
type: string
format: date
EndDateParam:
name: end_date
in: query
schema:
type: string
format: date
PageParam:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
PageSizeParam:
name: page_size
in: query
schema:
type: integer
minimum: 1
maximum: 200
default: 20
XRequestIdHeader:
name: X-Request-Id
in: header
required: true
description: 客户端请求幂等追踪ID全链路唯一
schema:
type: string
minLength: 8
maxLength: 128
IdempotencyKeyHeader:
name: Idempotency-Key
in: header
required: true
description: 写操作幂等键(同资源同动作语义唯一)
schema:
type: string
minLength: 8
maxLength: 128
responses:
BadRequest:
description: 参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Unauthorized:
description: 未认证或认证失效
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: 资源不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Conflict:
description: 状态冲突
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
idempotencyPayloadMismatch:
summary: 幂等键命中但请求体不一致
value:
request_id: req_20260327_001
error:
code: IDEMPOTENCY_PAYLOAD_MISMATCH
message: idempotency key replay with different payload
details:
retryable: false
expected_action: reuse_same_payload_or_new_idempotency_key
AcceptedInProgress:
description: 首次请求仍在处理,请按建议间隔重试
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
idempotencyInProgress:
summary: 幂等处理中重放
value:
request_id: req_20260327_002
error:
code: IDEMPOTENCY_IN_PROGRESS
message: request is processing
details:
retry_after_ms: 2000
retryable: true
BusinessError:
description: 业务校验失败
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
VerifySupplyAccountRequest:
type: object
required: [provider, account_type, credential_input]
properties:
provider:
type: string
enum: [openai, anthropic, gemini, baidu, xfyun, tencent]
account_type:
type: string
enum: [api_key, oauth]
credential_input:
type: string
minLength: 8
maxLength: 4096
writeOnly: true
min_quota_threshold:
type: number
format: double
minimum: 0
VerifySupplyAccountResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [verify_status, risk_score]
properties:
verify_status:
type: string
enum: [pass, review_required, reject]
available_quota:
type: number
format: double
risk_score:
type: integer
minimum: 0
maximum: 100
check_items:
type: array
items:
type: object
properties:
item:
type: string
result:
type: string
enum: [pass, fail, warn]
message:
type: string
CreateSupplyAccountRequest:
allOf:
- $ref: '#/components/schemas/VerifySupplyAccountRequest'
- type: object
required: [risk_ack]
properties:
account_alias:
type: string
minLength: 1
maxLength: 100
risk_ack:
type: boolean
enum: [true]
CreateSupplyAccountResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
$ref: '#/components/schemas/SupplyAccount'
SupplyAccountStatusResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [account_id, status, updated_at]
properties:
account_id:
type: integer
format: int64
status:
type: string
enum: [pending, active, suspended, disabled]
updated_at:
type: string
format: date-time
SupplyAccount:
type: object
required: [account_id, provider, account_type, status, created_at]
properties:
account_id:
type: integer
format: int64
provider:
type: string
enum: [openai, anthropic, gemini, baidu, xfyun, tencent]
account_type:
type: string
enum: [api_key, oauth]
account_alias:
type: string
status:
type: string
enum: [pending, active, suspended, disabled]
available_quota:
type: number
format: double
risk_score:
type: integer
created_at:
type: string
format: date-time
SaveSupplyPackageDraftRequest:
type: object
required:
- supply_account_id
- model
- total_quota
- price_per_1m_input
- price_per_1m_output
- valid_days
properties:
supply_account_id:
type: integer
format: int64
model:
type: string
minLength: 1
maxLength: 100
total_quota:
type: number
format: double
exclusiveMinimum: true
minimum: 0
price_per_1m_input:
type: number
format: double
minimum: 0
price_per_1m_output:
type: number
format: double
minimum: 0
valid_days:
type: integer
minimum: 1
maximum: 365
max_concurrent:
type: integer
minimum: 1
maximum: 1000
default: 10
rate_limit_rpm:
type: integer
minimum: 1
maximum: 100000
default: 60
SupplyPackageResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
$ref: '#/components/schemas/SupplyPackage'
SupplyPackage:
type: object
required:
- package_id
- supply_account_id
- model
- status
- total_quota
- available_quota
- created_at
properties:
package_id:
type: integer
format: int64
supply_account_id:
type: integer
format: int64
model:
type: string
total_quota:
type: number
format: double
available_quota:
type: number
format: double
price_per_1m_input:
type: number
format: double
price_per_1m_output:
type: number
format: double
valid_days:
type: integer
status:
type: string
enum: [draft, active, paused, sold_out, expired]
created_at:
type: string
format: date-time
SupplyPackageStatusResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [package_id, status, updated_at]
properties:
package_id:
type: integer
format: int64
status:
type: string
enum: [draft, active, paused, sold_out, expired]
updated_at:
type: string
format: date-time
BatchUpdateSupplyPackagePriceRequest:
type: object
required: [items]
properties:
items:
type: array
minItems: 1
maxItems: 200
items:
type: object
required: [package_id, price_per_1m_input, price_per_1m_output]
properties:
package_id:
type: integer
format: int64
price_per_1m_input:
type: number
format: double
minimum: 0
price_per_1m_output:
type: number
format: double
minimum: 0
BatchUpdateSupplyPackagePriceResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [total, success_count, failed_count]
properties:
total:
type: integer
success_count:
type: integer
failed_count:
type: integer
failures:
type: array
items:
type: object
properties:
package_id:
type: integer
format: int64
error_code:
type: string
message:
type: string
SupplierBillingResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [period, summary]
properties:
period:
type: object
properties:
start:
type: string
format: date
end:
type: string
format: date
summary:
type: object
properties:
total_revenue:
type: number
format: double
total_orders:
type: integer
total_usage:
type: integer
format: int64
total_requests:
type: integer
format: int64
avg_success_rate:
type: number
format: double
platform_fee:
type: number
format: double
net_earnings:
type: number
format: double
by_platform:
type: array
items:
type: object
properties:
platform:
type: string
revenue:
type: number
format: double
orders:
type: integer
tokens:
type: integer
format: int64
success_rate:
type: number
format: double
CreateWithdrawRequest:
type: object
required: [withdraw_amount, payment_method, payment_account, sms_code]
properties:
withdraw_amount:
type: number
format: double
exclusiveMinimum: true
minimum: 0
payment_method:
type: string
enum: [bank, alipay, wechat]
payment_account:
type: string
minLength: 2
maxLength: 100
sms_code:
type: string
minLength: 4
maxLength: 10
CreateWithdrawResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
$ref: '#/components/schemas/SupplySettlement'
SupplySettlementStatusResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [settlement_id, status, updated_at]
properties:
settlement_id:
type: integer
format: int64
status:
type: string
enum: [pending, processing, completed, failed]
updated_at:
type: string
format: date-time
SupplySettlement:
type: object
required: [settlement_id, settlement_no, status, total_amount, net_amount, created_at]
properties:
settlement_id:
type: integer
format: int64
settlement_no:
type: string
status:
type: string
enum: [pending, processing, completed, failed]
total_amount:
type: number
format: double
fee_amount:
type: number
format: double
net_amount:
type: number
format: double
payment_method:
type: string
enum: [bank, alipay, wechat]
created_at:
type: string
format: date-time
SettlementStatementResponse:
type: object
required: [request_id, data]
properties:
request_id:
type: string
data:
type: object
required: [settlement_id, file_name, download_url, expires_at]
properties:
settlement_id:
type: integer
format: int64
file_name:
type: string
download_url:
type: string
format: uri
expires_at:
type: string
format: date-time
SupplyEarningRecordListResponse:
type: object
required: [request_id, data, pagination]
properties:
request_id:
type: string
data:
type: array
items:
type: object
required: [record_id, user_id, earnings_type, amount, status, earned_at]
properties:
record_id:
type: integer
format: int64
user_id:
type: integer
format: int64
settlement_id:
type: integer
format: int64
earnings_type:
type: string
enum: [usage, bonus, refund]
amount:
type: number
format: double
status:
type: string
enum: [pending, available, withdrawn, frozen]
description:
type: string
earned_at:
type: string
format: date-time
pagination:
$ref: '#/components/schemas/Pagination'
AuditLogListResponse:
type: object
required: [request_id, data, pagination]
properties:
request_id:
type: string
data:
type: array
items:
type: object
required:
[event_id, operator_id, tenant_id, object_type, object_id, request_id, created_at]
properties:
event_id:
type: string
operator_id:
type: integer
format: int64
tenant_id:
type: integer
format: int64
object_type:
type: string
object_id:
type: string
action:
type: string
before_state:
type: object
additionalProperties: true
after_state:
type: object
additionalProperties: true
request_id:
type: string
created_at:
type: string
format: date-time
pagination:
$ref: '#/components/schemas/Pagination'
Pagination:
type: object
required: [page, page_size, total]
properties:
page:
type: integer
page_size:
type: integer
total:
type: integer
ErrorResponse:
type: object
required: [request_id, error]
properties:
request_id:
type: string
error:
type: object
required: [code, message]
properties:
code:
type: string
example: SUP_ACC_4001
message:
type: string
details:
type: object
additionalProperties: true