openapi: 3.0.0 info: title: Quyun Platform API description: API specification for Quyun (曲韵) Platform - A multi-tenant opera content delivery platform. version: 1.0.2 servers: - url: /v1 description: Production Server components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT schemas: # --- Common Models --- Error: type: object properties: code: type: integer message: type: string Pager: type: object properties: page: type: integer limit: type: integer total: type: integer items: type: array items: {} # Generic placeholder # --- User Models --- User: type: object properties: id: type: string phone: type: string nickname: type: string avatar: type: string gender: type: string enum: [male, female, secret] bio: type: string birthday: type: string format: date location: type: object properties: province: type: string city: type: string balance: type: number readOnly: true points: type: integer readOnly: true is_real_name_verified: type: boolean readOnly: true UserUpdate: type: object properties: nickname: type: string avatar: type: string gender: type: string enum: [male, female, secret] bio: type: string birthday: type: string format: date location: type: object properties: province: type: string city: type: string # --- Content Models --- ContentItem: type: object properties: id: type: string title: type: string cover: type: string genre: type: string type: type: string enum: [video, audio, article] price: type: number author_id: type: string author_name: type: string author_avatar: type: string views: type: integer likes: type: integer is_purchased: type: boolean description: User specific state ContentDetail: allOf: - $ref: '#/components/schemas/ContentItem' - type: object properties: description: type: string body: type: string # HTML/Markdown media_urls: type: array items: type: object properties: type: type: string url: type: string duration: type: integer meta: type: object properties: role: type: string key: type: string beat: type: string is_liked: type: boolean description: User specific state is_favorited: type: boolean description: User specific state Comment: type: object properties: id: type: string content: type: string user_id: type: string user_nickname: type: string user_avatar: type: string create_time: type: string likes: type: integer is_liked: type: boolean reply_to: type: string # Comment ID # --- Tenant/Creator Public Profile --- TenantProfile: type: object properties: id: type: string name: type: string avatar: type: string cover: type: string bio: type: string description: type: string cert_type: type: string enum: [personal, enterprise] stats: type: object properties: followers: type: integer contents: type: integer likes: type: integer is_following: type: boolean # --- Order Models --- Order: type: object properties: id: type: string create_time: type: string format: date-time pay_time: type: string format: date-time status: type: string enum: [unpaid, paid, completed, refunding, refunded, cancelled] amount: type: number quantity: type: integer items: type: array items: $ref: '#/components/schemas/ContentItem' tenant_id: type: string tenant_name: type: string is_virtual: type: boolean # --- Creator Dashboard Models --- CreatorStats: type: object properties: total_followers: type: object properties: value: type: integer trend: type: number description: Percentage change (e.g. 1.2 for +1.2%) total_revenue: type: object properties: value: type: number trend: type: number pending_refunds: type: integer new_messages: type: integer PayoutAccount: type: object properties: id: type: string type: type: string enum: [bank, alipay] name: type: string account: type: string realname: type: string UserCouponItem: type: object properties: id: type: string coupon_id: type: string title: type: string description: type: string type: type: string enum: [fix_amount, discount] value: type: integer min_order_amount: type: integer start_at: type: string end_at: type: string status: type: string enum: [unused, used, expired] # --- Upload --- UploadResult: type: object properties: id: type: string url: type: string filename: type: string size: type: integer mime_type: type: string security: - BearerAuth: [] paths: # ============================ # Public / Auth # ============================ /auth/otp: post: summary: Send OTP security: [] requestBody: required: true content: application/json: schema: type: object properties: phone: type: string responses: '200': description: OTP sent /auth/login: post: summary: Login or Register with OTP security: [] requestBody: required: true content: application/json: schema: type: object properties: phone: type: string otp: type: string responses: '200': description: Successful login content: application/json: schema: type: object properties: token: type: string user: $ref: '#/components/schemas/User' # ============================ # Public Content & Interaction # ============================ /contents: get: summary: List contents (Explore / Search) security: [] parameters: - name: keyword in: query schema: type: string description: Search keyword - name: genre in: query schema: type: string - name: tenant_id in: query schema: type: string description: Filter by creator - name: sort in: query schema: type: string enum: [latest, hot, price_asc] - name: page in: query schema: type: integer responses: '200': description: List of contents content: application/json: schema: allOf: - $ref: '#/components/schemas/Pager' - type: object properties: items: type: array items: $ref: '#/components/schemas/ContentItem' /contents/{id}: get: summary: Get content detail security: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Content detail content: application/json: schema: $ref: '#/components/schemas/ContentDetail' /contents/{id}/comments: get: summary: Get comments for a content security: [] parameters: - name: id in: path required: true schema: type: string - name: page in: query schema: type: integer responses: '200': content: application/json: schema: allOf: - $ref: '#/components/schemas/Pager' - type: object properties: items: type: array items: $ref: '#/components/schemas/Comment' post: summary: Post a comment requestBody: content: application/json: schema: type: object properties: content: type: string reply_to: type: string responses: '200': description: Comment created /comments/{id}/like: post: summary: Like a comment parameters: - name: id in: path required: true schema: type: string responses: '200': description: Liked /topics: get: summary: List curated topics security: [] responses: '200': description: List of topics content: application/json: schema: type: array items: type: object properties: id: type: string title: type: string cover: type: string tag: type: string count: type: integer # ============================ # Public Tenant Profile # ============================ /tenants/{id}: get: summary: Get tenant public profile security: [] parameters: - name: id in: path required: true schema: type: string responses: '200': content: application/json: schema: $ref: '#/components/schemas/TenantProfile' /tenants/{id}/follow: post: summary: Follow a tenant parameters: - name: id in: path required: true schema: type: string responses: '200': description: Followed delete: summary: Unfollow a tenant parameters: - name: id in: path required: true schema: type: string responses: '200': description: Unfollowed # ============================ # User Center # ============================ /me: get: summary: Get current user profile responses: '200': content: application/json: schema: $ref: '#/components/schemas/User' put: summary: Update user profile requestBody: content: application/json: schema: $ref: '#/components/schemas/UserUpdate' responses: '200': description: Updated /me/realname: post: summary: Submit real-name authentication requestBody: content: application/json: schema: type: object properties: realname: type: string id_card: type: string responses: '200': description: Submitted /me/wallet: get: summary: Get wallet balance and transactions responses: '200': content: application/json: schema: type: object properties: balance: type: number transactions: type: array items: type: object properties: id: type: string title: type: string amount: type: number type: type: string enum: [income, expense] date: type: string /me/wallet/recharge: post: summary: Recharge wallet requestBody: content: application/json: schema: type: object properties: amount: type: number method: type: string enum: [alipay] responses: '200': description: Recharge initiated content: application/json: schema: type: object properties: pay_params: type: string # QR code or SDK params order_id: type: string /me/orders: get: summary: List user orders parameters: - name: status in: query schema: type: string enum: [all, unpaid, completed, refund] responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/Order' /me/orders/{id}: get: summary: Get user order detail parameters: - name: id in: path required: true schema: type: string responses: '200': content: application/json: schema: $ref: '#/components/schemas/Order' /me/library: get: summary: Get purchased content responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/ContentItem' /me/favorites: get: summary: Get favorites responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/ContentItem' post: summary: Add to favorites parameters: - name: content_id in: query required: true schema: type: string responses: '200': description: Added /me/favorites/{content_id}: delete: summary: Remove from favorites parameters: - name: content_id in: path required: true schema: type: string responses: '200': description: Removed /me/likes: get: summary: Get liked contents responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/ContentItem' post: summary: Like content parameters: - name: content_id in: query required: true schema: type: string responses: '200': description: Liked /me/likes/{content_id}: delete: summary: Unlike content parameters: - name: content_id in: path required: true schema: type: string responses: '200': description: Unliked /me/notifications: get: summary: Get notifications parameters: - name: type in: query schema: type: string enum: [all, system, order, audit, interaction] responses: '200': content: application/json: schema: type: array items: type: object properties: id: type: string type: type: string title: type: string content: type: string read: type: boolean time: type: string /me/coupons: get: summary: List user coupons parameters: - name: status in: query schema: type: string enum: [unused, used, expired] responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/UserCouponItem' # ============================ # Storage (Presigned) # ============================ /storage/{key}: put: summary: Upload file (Presigned) tags: [Storage] parameters: - name: key in: path required: true schema: type: string - name: expires in: query required: true schema: type: string - name: sign in: query required: true schema: type: string requestBody: content: application/octet-stream: schema: type: string format: binary responses: '200': description: Upload successful get: summary: Download file (Presigned) tags: [Storage] parameters: - name: key in: path required: true schema: type: string - name: expires in: query required: true schema: type: string - name: sign in: query required: true schema: type: string responses: '200': description: Download file content: application/octet-stream: schema: type: string format: binary # ============================ # Transaction # ============================ /orders: post: summary: Create Order requestBody: content: application/json: schema: type: object properties: content_id: type: string sku: type: string quantity: type: integer default: 1 user_coupon_id: type: string responses: '200': content: application/json: schema: type: object properties: order_id: type: string /orders/{id}/pay: post: summary: Pay for order parameters: - name: id in: path required: true schema: type: string requestBody: content: application/json: schema: type: object properties: method: type: string enum: [alipay, balance] responses: '200': content: application/json: schema: type: object properties: pay_params: type: string /orders/{id}/status: get: summary: Check order payment status parameters: - name: id in: path required: true schema: type: string responses: '200': content: application/json: schema: type: object properties: status: type: string enum: [unpaid, paid, completed] /webhook/payment/notify: post: summary: Payment Webhook tags: [Transaction] requestBody: content: application/json: schema: type: object properties: order_id: type: string external_id: type: string responses: '200': description: Success # ============================ # Creator Center # ============================ /creator/apply: post: summary: Apply to become a creator requestBody: content: application/json: schema: type: object properties: name: type: string bio: type: string avatar: type: string responses: '200': description: Application submitted /creator/dashboard: get: summary: Get creator dashboard stats responses: '200': content: application/json: schema: $ref: '#/components/schemas/CreatorStats' /creator/contents: get: summary: List creator contents parameters: - name: status in: query schema: type: string - name: genre in: query schema: type: string - name: keyword in: query schema: type: string responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/ContentItem' post: summary: Create/Publish content requestBody: content: application/json: schema: type: object properties: title: type: string genre: type: string price: type: number media_ids: type: array items: type: string responses: '200': description: Created /creator/contents/{id}: put: summary: Update content parameters: - name: id in: path required: true schema: type: string requestBody: content: application/json: schema: type: object # fields to update responses: '200': description: Updated delete: summary: Delete content parameters: - name: id in: path required: true schema: type: string responses: '200': description: Deleted /creator/orders: get: summary: List sales orders parameters: - name: status in: query schema: type: string - name: keyword in: query schema: type: string responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/Order' /creator/orders/{id}/refund: post: summary: Process refund parameters: - name: id in: path required: true schema: type: string requestBody: content: application/json: schema: type: object properties: action: type: string enum: [accept, reject] reason: type: string responses: '200': description: Processed /creator/settings: get: summary: Get channel settings responses: '200': content: application/json: schema: type: object properties: name: type: string bio: type: string avatar: type: string cover: type: string description: type: string put: summary: Update channel settings requestBody: content: application/json: schema: type: object # fields to update responses: '200': description: Updated /creator/payout-accounts: get: summary: List payout accounts responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/PayoutAccount' post: summary: Add payout account requestBody: content: application/json: schema: $ref: '#/components/schemas/PayoutAccount' responses: '200': description: Added delete: summary: Remove payout account parameters: - name: id in: query required: true schema: type: string responses: '200': description: Removed /creator/withdraw: post: summary: Request withdrawal requestBody: content: application/json: schema: type: object properties: amount: type: number method: type: string enum: [wallet, external] account_id: type: string # Required if method is external responses: '200': description: Withdrawal requested # ============================ # Common / Upload # ============================ /upload: post: summary: Upload file requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary type: type: string enum: [image, video, audio] responses: '200': content: application/json: schema: $ref: '#/components/schemas/UploadResult'