openapi: 3.0.3 info: title: 虚拟商品充值服务商系统 - 对外接口 description: | 服务商系统对外提供的接口,被邮储银行服务开放平台调用。 ## 接口列表 - 服务预约接口:接收预约请求,获取券码链接 - 服务取消接口:接收取消请求,作废券码 - 订单过期积分查询接口:查询过期幸福点信息 - 服务详情查询接口:获取券码链接展示服务详情 - 对账文件查询接口:查询可用的对账文件列表 - 对账文件下载接口:根据文件ID下载对账文件 - 批量补推接口:手动批量触发服务完成通知 ## 公共响应结构 所有接口统一使用以下响应结构: ```json { "code": 0, "msg": "成功", "traceId": "请求追踪ID", "data": {} } ``` ## 公共响应码 | 响应码 | 描述 | |-------|------| | 0 | 成功 | | 1 | 系统异常 | | 2 | 参数错误 | | 3 | 签名错误 | | 4 | 业务错误 | ## 时间格式 系统统一使用 `yyyyMMddHHmmss` 格式存储和传输时间字段。 version: 1.0.0 contact: name: 服务商系统技术支持 servers: - url: https://api.example.com description: 生产环境 - url: https://api-test.example.com description: 测试环境 tags: - name: 服务预约 description: 服务预约相关接口 - name: 服务取消 description: 服务取消相关接口 - name: 积分查询 description: 积分查询相关接口 - name: 服务详情 description: 服务详情查询接口 - name: 对账管理 description: 对账管理相关接口 paths: /api/v1/service/appointment: post: tags: - 服务预约 summary: 服务预约接口 description: | 接收邮储银行服务开放平台的预约请求,为客户预约虚拟商品充值服务。 ## 业务规则 1. 查询数据库验证服务编码(type)是否存在 2. 使用AES解密request参数,解析出type、code、mac 3. 基于权益码(code)获取分布式锁,防止重复请求 4. 对code(权益码)进行幂等验证 5. 验证权益码是否过期 6. 创建/更新订单记录 7. 请求邮储服务开放平台发起预约 8. 请求蓝色兄弟营销平台获取券码链接 operationId: serviceAppointment requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AppointmentRequest' examples: normal: summary: 正常预约请求 value: type: "310001" request: "AES加密字符串" channel: "12" tranChnl: "12" backUrl: "https://mobile.psbc.com/back" instType: "01" provinceInstNo: "100000" responses: '200': description: 预约成功 content: application/json: schema: $ref: '#/components/schemas/AppointmentResponse' examples: success: summary: 预约成功 value: code: 0 msg: "成功" traceId: "26031314253001000001" data: url: "https://lsb.example.com/redeem/abc123" tranChnl: "12" instType: "01" backUrl: "https://mobile.psbc.com/back" '400': description: 参数错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000002" serviceNotFound: summary: 服务编码不存在 value: code: 4 msg: "暂不支持此服务" traceId: "26031314253001000003" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000004" /api/v1/service/cancel: post: tags: - 服务取消 summary: 服务取消接口 description: | 接收邮储银行服务开放平台的取消请求,取消已预约的服务。 ## 业务规则 1. 对request进行AES解密,解析出type、code、mac 2. 基于权益码(code)获取分布式锁,防止重复请求 3. 检查订单状态必须是已预约状态才能取消 4. 调用邮储预约服务状态查询接口查询状态 5. 调用蓝色兄弟作废接口发起作废 6. 调用邮储接口发起预约取消 7. 订单状态更新为"已取消"(400) operationId: serviceCancel requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CancelRequest' examples: normal: summary: 正常取消请求 value: type: "310001" request: "AES加密字符串" channel: "12" tranChnl: "12" backUrl: "https://mobile.psbc.com/back" instType: "01" provinceInstNo: "100000" responses: '200': description: 取消成功 content: application/json: schema: $ref: '#/components/schemas/CancelResponse' examples: success: summary: 取消成功 value: code: 0 msg: "成功" traceId: "26031314253001000005" data: tranChnl: "12" instType: "01" backUrl: "https://mobile.psbc.com/back" '400': description: 参数错误或业务错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000006" serviceNotFound: summary: 服务编码不存在 value: code: 4 msg: "暂不支持此服务" traceId: "26031314253001000007" serviceExpired: summary: 服务已过期 value: code: 4 msg: "服务已过期" traceId: "26031314253001000008" serviceCompleted: summary: 服务已生效无法取消 value: code: 4 msg: "服务已生效无法取消" traceId: "26031314253001000009" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000010" /api/v1/order/expired-points: post: tags: - 积分查询 summary: 订单过期积分查询接口 description: | 查询订单退还时已过期的幸福点信息,用于取消前提醒客户。 ## 业务规则 1. 验证服务编码(type),查询数据库获取AES解密密钥 2. 服务编码不存在返回"暂不支持此服务" 3. 解密request参数获取服务编码、权益码、客户ID 4. 调用邮储「高端客户权益订单退还时已过期积分查询」接口 5. 返回邮储接口查询结果 operationId: queryExpiredPoints requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ExpiredPointsRequest' examples: normal: summary: 正常查询请求 value: type: "310001" request: "AES加密字符串" channel: "12" tranChnl: "12" backUrl: "https://mobile.psbc.com/back" instType: "01" provinceInstNo: "100000" responses: '200': description: 查询成功 content: application/json: schema: $ref: '#/components/schemas/ExpiredPointsResponse' examples: success: summary: 查询成功 value: code: 0 msg: "成功" traceId: "26031314253001000011" data: tranIntglNum: 1000 ovdueIntglNum: 200 noticeMsg: "您有200幸福点已过期,取消后将无法退回" '400': description: 参数错误或业务错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000012" serviceNotFound: summary: 服务编码不存在 value: code: 4 msg: "暂不支持此服务" traceId: "26031314253001000013" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "查询失败,请重试" traceId: "26031314253001000014" /api/v1/service/detail: post: tags: - 服务详情 summary: 服务详情查询接口 description: | 提供给邮储银行跳转服务详情页面,根据参数获取上游券码链接展示服务详情。 ## 业务规则 1. 验证服务编码(type),查询数据库获取AES解密密钥 2. 服务编码不存在返回"暂不支持此服务" 3. 解密request参数获取服务编码、权益码、客户ID 4. 根据权益码查询订单获取券码链接 5. 返回券码链接用于页面展示 operationId: queryServiceDetail requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ServiceDetailRequest' examples: normal: summary: 正常查询请求 value: type: "310001" request: "AES加密字符串" channel: "12" tranChnl: "12" backUrl: "https://mobile.psbc.com/back" instType: "01" provinceInstNo: "100000" responses: '200': description: 查询成功 content: application/json: schema: $ref: '#/components/schemas/ServiceDetailResponse' examples: success: summary: 查询成功 value: code: 0 msg: "成功" traceId: "26031314253001000015" data: url: "https://lsb.example.com/redeem/abc123" backUrl: "https://mobile.psbc.com/back" '400': description: 参数错误或业务错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000016" serviceNotFound: summary: 服务编码不存在 value: code: 4 msg: "暂不支持此服务" traceId: "26031314253001000017" orderNotFound: summary: 订单不存在 value: code: 1 msg: "订单不存在" traceId: "26031314253001000018" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000019" /api/v1/reconciliation/files: post: tags: - 对账管理 summary: 对账文件查询接口 description: | 查询可用的对账文件列表,用于管理员或运营人员获取本地处理后的对账文件信息。 ## 业务规则 1. 每月3号生成上月服务状态为「服务已完成(300)」的权益订单对账文件 2. 对账月份规则:服务完成时间所在月份为对账月份 3. 对账文件名称格式:RIGHTS_SERVICE_CHK_{providerCode} 4. 返回文件ID、文件名称等信息 operationId: queryReconciliationFiles requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReconciliationFilesRequest' examples: normal: summary: 正常查询请求 value: accountingDate: "20251201" fileIntfcName: "RIGHTS_SERVICE_CHK_A101" responses: '200': description: 查询成功 content: application/json: schema: $ref: '#/components/schemas/ReconciliationFilesResponse' examples: success: summary: 查询成功 value: code: 0 msg: "成功" traceId: "26031314253001000020" data: fileList: - fileId: "FILE202512A101001" fileName: "RIGHTS_SERVICE_CHK_A101_202512.csv" fileSize: 12560 createTime: "20260103100000" emptyResult: summary: 无对账数据 value: code: 0 msg: "成功" traceId: "26031314253001000021" data: fileList: [] '400': description: 参数错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000022" monthExceed: summary: 对账月份超过当前月 value: code: 4 msg: "对账月份不能超过上月" traceId: "26031314253001000023" fileIntfcNameNotFound: summary: 文件接口名不存在 value: code: 4 msg: "文件接口名不存在" traceId: "26031314253001000024" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000024" /api/v1/reconciliation/download: post: tags: - 对账管理 summary: 对账文件下载接口 description: | 根据文件ID和文件接口名下载对账文件,用于管理员或运营人员获取具体的对账文件内容。 ## 业务规则 1. 根据文件ID和文件接口名查询对账文件 2. 验证下载密码,密码错误拒绝下载 3. 文件格式为CSV,编码UTF-8-BOM(兼容Excel中文显示) 4. 直接返回文件流 ## 对账文件内容字段 | 序号 | 字段名 | 说明 | |-----|-------|------| | 1 | 统计月份 | YYYYMM | | 2 | 一分机构序号 | province_inst_no | | 3 | 一分机构名称 | 根据机构号映射 | | 4 | 网点机构属性 | 01-自营,02-代理 | | 5 | 积分客户服务编码 | type字段 | | 6 | 服务内容 | 服务名称 | | 7 | 预约时间 | yyyyMMddHHmmss | | 8 | 实际完成时间 | yyyyMMddHHmmss | | 9 | 权益兑换码 | code字段 | | 10 | 订单号 | order_no | | 11 | 券码状态 | 1-正常,2-已核销,3-已作废,4-已过期 | operationId: downloadReconciliationFile requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReconciliationDownloadRequest' examples: normal: summary: 正常下载请求 value: fileId: "FILE202512A101001" fileIntfcName: "RIGHTS_SERVICE_CHK_A101" password: "your_password" responses: '200': description: 下载成功 content: text/csv: schema: type: string format: binary headers: Content-Disposition: description: 文件名 schema: type: string example: 'attachment; filename="RIGHTS_SERVICE_CHK_A101_202512.csv"' '400': description: 参数错误或文件不存在 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误" traceId: "26031314253001000025" passwordError: summary: 密码错误 value: code: 3 msg: "密码错误" traceId: "26031314253001000028" fileNotFound: summary: 文件不存在 value: code: 4 msg: "文件不存在" traceId: "26031314253001000026" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000027" /api/v1/reconciliation/batch-repush: post: tags: - 对账管理 summary: 批量补推接口 description: | 手动批量触发服务完成通知,用于处理蓝色兄弟已核销但邮储银行未收到服务完成通知的订单。 ## 业务规则 1. 查询本地订单状态为「服务已预约(200)」且券码状态为「已核销(2)」的订单 2. 批量创建服务完成通知任务(task_type=1) 3. 支持按时间范围、权益码列表筛选(二选一) 4. 单次补推数量限制:最多100笔 5. 幂等处理:已存在相同类型的待处理任务时跳过 6. 支持试运行模式(dryRun),只查询不创建任务 operationId: batchRepush requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BatchRepushRequest' examples: byCodes: summary: 按权益码列表补推 value: codes: - "16800G-VN4724-NX874-30VHR" - "16800G-VN4724-NX874-30VHS" dryRun: false byTimeRange: summary: 按时间范围补推 value: startTime: "20251201000000" endTime: "20251231235959" dryRun: false dryRunMode: summary: 试运行模式 value: startTime: "20251201000000" endTime: "20251231235959" dryRun: true responses: '200': description: 补推成功 content: application/json: schema: $ref: '#/components/schemas/BatchRepushResponse' examples: success: summary: 补推成功 value: code: 0 msg: "成功" traceId: "26031314253001000024" data: totalCount: 3 createdCount: 2 skippedCount: 1 dryRunSuccess: summary: 试运行成功 value: code: 0 msg: "成功" traceId: "26031314253001000025" data: totalCount: 3 createdCount: 0 skippedCount: 0 orders: - orderNo: "26031314253001000001" code: "16800G-VN4724-NX874-30VHR" status: 200 keyStatus: 2 keyUsageTime: "20251215143000" hasTask: false - orderNo: "26031314253001000002" code: "16800G-VN4724-NX874-30VHS" status: 200 keyStatus: 2 keyUsageTime: "20251216101530" hasTask: true '400': description: 参数错误或业务错误 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: paramError: summary: 参数错误 value: code: 2 msg: "参数错误:权益码列表和时间范围必须二选一" traceId: "26031314253001000026" exceedLimit: summary: 超过数量限制 value: code: 2 msg: "单次补推数量不能超过100笔" traceId: "26031314253001000027" tooManyOrders: summary: 符合条件订单超过限制 value: code: 4 msg: "符合条件的订单超过100笔,请缩小时间范围或使用权益码列表" traceId: "26031314253001000028" '500': description: 系统异常 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: systemError: summary: 系统异常 value: code: 1 msg: "系统异常" traceId: "26031314253001000029" components: schemas: # ============ 请求参数 ============ BaseRequest: type: object required: - type - request - channel - tranChnl - instType - provinceInstNo properties: type: type: string description: 服务编码,用于查询数据库获取AES解密密钥 example: "310001" maxLength: 6 request: type: string description: | AES加密字符串 解密后格式:type=服务编码&code=权益码&mac=加密后的客户id 加密算法:AES/CBC/PKCS5Padding Key长度:16位 IV长度:16位 编码方式:Base64 example: "U2FsdGVkX1+abc123..." channel: type: string description: 渠道标识 enum: - "12" - "17" - "41" x-enum-descriptions: - 手机银行 - 电话银行 - CRM零售 example: "12" maxLength: 4 tranChnl: type: string description: 渠道标识 enum: - "12" - "17" - "41" x-enum-descriptions: - 手机银行 - 电话银行 - CRM零售 example: "12" maxLength: 4 backUrl: type: string description: 返回手机银行的地址,可为空 example: "https://mobile.psbc.com/back" maxLength: 256 instType: type: string description: 客户自营代理属性 enum: - "01" - "02" x-enum-descriptions: - 自营 - 代理 example: "01" maxLength: 2 provinceInstNo: type: string description: 客户归属一分机构号 example: "100000" maxLength: 20 AppointmentRequest: allOf: - $ref: '#/components/schemas/BaseRequest' description: 服务预约请求参数 CancelRequest: allOf: - $ref: '#/components/schemas/BaseRequest' description: 服务取消请求参数 ExpiredPointsRequest: allOf: - $ref: '#/components/schemas/BaseRequest' description: 订单过期积分查询请求参数 ServiceDetailRequest: allOf: - $ref: '#/components/schemas/BaseRequest' description: 服务详情查询请求参数 BatchRepushRequest: type: object description: | 批量补推请求参数 注意:codes 和 startTime/endTime 必须二选一 properties: codes: type: array description: 权益码列表,最多100个,与时间范围二选一 items: type: string maxItems: 100 example: - "16800G-VN4724-NX874-30VHR" - "16800G-VN4724-NX874-30VHS" startTime: type: string description: 开始时间,格式:yyyyMMddHHmmss,与codes二选一 pattern: '^\d{14}$' example: "20251201000000" endTime: type: string description: 结束时间,格式:yyyyMMddHHmmss,与codes二选一 pattern: '^\d{14}$' example: "20251231235959" dryRun: type: boolean description: 是否试运行,默认false。true时只返回待补推订单列表,不实际创建任务 default: false example: false ReconciliationFilesRequest: type: object description: 对账文件查询请求参数 required: - accountingDate - fileIntfcName properties: accountingDate: type: string description: 会计日期,格式:YYYYMMDD pattern: '^\d{8}$' maxLength: 8 example: "20251201" fileIntfcName: type: string description: 文件接口名,固定值,如:RIGHTS_SERVICE_CHK_A101 maxLength: 64 example: "RIGHTS_SERVICE_CHK_A101" ReconciliationDownloadRequest: type: object description: 对账文件下载请求参数 required: - fileId - fileIntfcName - password properties: fileId: type: string description: 文件唯一标识,从查询接口获取 maxLength: 32 example: "FILE202512A101001" fileIntfcName: type: string description: 文件接口名,固定值,如:RIGHTS_SERVICE_CHK_A101 maxLength: 64 example: "RIGHTS_SERVICE_CHK_A101" password: type: string description: 下载密码,用于验证下载权限 maxLength: 32 example: "your_password" # ============ 响应参数 ============ BaseResponse: type: object required: - code - msg - traceId properties: code: type: integer description: | 公共响应码 - 0: 成功 - 1: 系统异常 - 2: 参数错误 - 3: 签名错误 - 4: 业务错误 enum: - 0 - 1 - 2 - 3 - 4 example: 0 msg: type: string description: 响应描述信息,当code!=0时为错误信息 example: "成功" traceId: type: string description: 请求追踪ID,用于问题排查。使用雪花算法或UUID确保全局唯一 example: "26031314253001000001" maxLength: 32 AppointmentResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 required: - url - tranChnl - instType properties: url: type: string description: 蓝色兄弟营销平台的兑换地址 example: "https://lsb.example.com/redeem/abc123" maxLength: 125 tranChnl: type: string description: 渠道标识 example: "12" maxLength: 4 instType: type: string description: 客户自营代理属性 example: "01" maxLength: 2 backUrl: type: string description: 返回手机银行的地址 example: "https://mobile.psbc.com/back" maxLength: 256 CancelResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 required: - tranChnl - instType properties: tranChnl: type: string description: 渠道标识 example: "12" maxLength: 4 instType: type: string description: 客户自营代理属性 example: "01" maxLength: 2 backUrl: type: string description: 返回手机银行的地址 example: "https://mobile.psbc.com/back" maxLength: 256 ExpiredPointsResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 properties: tranIntglNum: type: integer description: 交易总幸福点 example: 1000 ovdueIntglNum: type: integer description: 已过期的幸福点 example: 200 noticeMsg: type: string description: 提醒信息文本 example: "您有200幸福点已过期,取消后将无法退回" ServiceDetailResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 required: - url - backUrl properties: url: type: string description: 券码链接,用于展示服务详情 example: "https://lsb.example.com/redeem/abc123" maxLength: 125 backUrl: type: string description: 返回手机银行的地址 example: "https://mobile.psbc.com/back" maxLength: 256 ErrorResponse: allOf: - $ref: '#/components/schemas/BaseResponse' description: 错误响应 ReconciliationFilesResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 required: - fileList properties: fileList: type: array description: 对账文件列表 items: $ref: '#/components/schemas/ReconciliationFileItem' ReconciliationFileItem: type: object description: 对账文件信息 required: - fileId - fileName - fileSize - createTime properties: fileId: type: string description: 文件唯一标识,用于下载接口 example: "FILE202512A101001" maxLength: 32 fileName: type: string description: 文件名称 example: "RIGHTS_SERVICE_CHK_A101_202512.csv" maxLength: 64 fileSize: type: integer format: int64 description: 文件大小(字节) example: 12560 createTime: type: string description: 文件创建时间 yyyyMMddHHmmss example: "20260103100000" BatchRepushResponse: allOf: - $ref: '#/components/schemas/BaseResponse' - type: object properties: data: type: object description: 业务数据 required: - totalCount - createdCount - skippedCount properties: totalCount: type: integer description: 符合条件的订单总数 example: 3 createdCount: type: integer description: 新创建的任务数(dryRun=true时为0) example: 2 skippedCount: type: integer description: 跳过的订单数(已有待处理任务) example: 1 orders: type: array description: 订单列表(dryRun=true时返回) items: $ref: '#/components/schemas/RepushOrderItem' RepushOrderItem: type: object description: 补推订单信息 required: - orderNo - code - status - keyStatus - hasTask properties: orderNo: type: string description: 订单号 example: "26031314253001000001" maxLength: 32 code: type: string description: 权益码 example: "16800G-VN4724-NX874-30VHR" maxLength: 32 status: type: integer description: | 订单状态 - 100: 服务未预约 - 200: 服务已预约 - 300: 服务已完成 - 400: 服务已取消 - 500: 服务已过期 example: 200 keyStatus: type: integer description: | 券码状态 - 0: 待生成 - 1: 正常 - 2: 已核销 - 3: 已作废 - 4: 已过期 example: 2 keyUsageTime: type: string description: 核销时间,格式:yyyyMMddHHmmss example: "20251215143000" hasTask: type: boolean description: 是否已有待处理任务 example: false # ============ 枚举定义 ============ Channel: type: string description: 渠道标识 enum: - "12" - "17" - "41" x-enum-descriptions: - 手机银行 - 电话银行 - CRM零售 InstType: type: string description: 客户自营代理属性 enum: - "01" - "02" x-enum-descriptions: - 自营 - 代理 ResponseCode: type: integer description: 公共响应码 enum: - 0 - 1 - 2 - 3 - 4 x-enum-descriptions: - 成功 - 系统异常 - 参数错误 - 签名错误 - 业务错误 OrderStatus: type: integer description: 订单状态 enum: - 100 - 200 - 300 - 400 - 500 x-enum-descriptions: - 服务未预约 - 服务已预约 - 服务已完成 - 服务已取消 - 服务已过期 KeyCodeStatus: type: integer description: 券码状态 enum: - 0 - 1 - 2 - 3 - 4 x-enum-descriptions: - 待生成 - 正常 - 已核销 - 已作废 - 已过期