Table of Contents
7.1 创建订阅订单【未授权拦截通过,待登录态联调】
POST /tieup/api/v1/subscriptions
请求头:
Idempotency-Key: subscription_10001_20260602143000_x7f9k2
请求体:
{
"artist_id": 1,
"subscription_plan_code": "month_30",
"sub_type": "month",
"subscription_action": "initial",
"payment_method": "wechat",
"is_auto_renew": 2
}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
artist_id |
integer | 是 | 目标艺人 ID |
subscription_plan_code |
string | 是 | 必须等于目标艺人在定价设置中当前选择的档位代码,且该代码在当前渠道、平台和市场可用 |
sub_type |
string | 是 | 订阅周期类型:month=月订阅,year=年订阅 |
subscription_action |
string | 否 | 订阅动作:initial=首订,renewal=续订;不传、传 null 或空字符串时默认 initial |
payment_method |
string | 是 | wechat=微信,alipay=支付宝,apple_iap=苹果内购 |
is_auto_renew |
integer | 否 | 1=自动续订,2=单次订阅;Apple 必须显式传 1,微信/支付宝未传时默认 2 |
return_url |
string | 否 | 仅微信 H5、支付宝 WAP 支持的支付完成回跳地址;完整 HTTP(S) 地址,最长 2048 字符。非空值优先于后台配置,未传、null、空字符串或纯空白时使用后台配置;APP、Apple IAP 传入会返回 422 |
首次创建或相同购买意图恢复成功响应:
{
"code": 200,
"message": "成功",
"data": {
"recharge_no": "RC202606060001",
"order_no": "TO202606060001",
"transaction_no": "TP202606060001",
"artist_id": 1,
"subscription_plan_code": "month_30",
"payment_amount": "30.00",
"paid_amount": "0.00",
"currency": "CNY",
"subscription_days": 30,
"subscription_action": "initial",
"is_auto_renew": 2,
"status": 1,
"payment": {
"order_no": "TO202606060001",
"transaction_no": "TP202606060001",
"order_status": 1,
"payment_status": 1,
"payment_method": "wechat",
"provider_code": "wechat_app",
"payment_account_id": 1,
"payment_amount": "30.00",
"currency": "CNY",
"pay_params": {
"trade_type": "APP",
"appid": "wx1234567890",
"partnerid": "1900000001",
"prepayid": "wx_prepay_id",
"package": "Sign=WXPay",
"noncestr": "a1b2c3d4",
"timestamp": "1785128400",
"sign": "base64-signature",
"sign_type": "RSA"
}
},
"reused_order": true,
"payment_expires_at": "2026-07-27 15:30:00",
"remaining_seconds": 1020
}
}
年订阅请求示例:
{
"artist_id": 1,
"subscription_plan_code": "month_30",
"sub_type": "year",
"subscription_action": "initial",
"payment_method": "apple_iap",
"is_auto_renew": 1
}
Apple 年订阅响应示例:
{
"code": 200,
"message": "成功",
"data": {
"recharge_no": "RC202606060002",
"order_no": "TO202606060002",
"transaction_no": "TP202606060002",
"artist_id": 1,
"subscription_plan_code": "month_30",
"payment_amount": "288.00",
"paid_amount": "0.00",
"currency": "CNY",
"subscription_days": 365,
"subscription_action": "initial",
"is_auto_renew": 1,
"status": 1,
"payment": {
"order_no": "TO202606060002",
"transaction_no": "TP202606060002",
"order_status": 1,
"payment_status": 1,
"payment_method": "apple_iap",
"provider_code": "apple_iap",
"payment_account_id": 1,
"payment_amount": "288.00",
"currency": "CNY",
"pay_params": {
"bundle_id": "com.tieup.app",
"product_id": "com.tieup.sub.year288",
"application_username": "550e8400-e29b-41d4-a716-446655440000",
"sandbox": false,
"requires_client_receipt_confirm": true,
"storekit": "storekit1"
}
},
"reused_order": false,
"payment_expires_at": "2026-07-27 15:30:00",
"remaining_seconds": 1800
}
}
响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
recharge_no |
string | 订阅充值业务单号 |
order_no |
string | 平台订单号 |
transaction_no |
string | 支付流水号 |
artist_id |
integer | 订阅艺人 ID |
subscription_plan_code |
string | 订阅档位代码 |
payment_amount |
string | 订单金额,单位元,固定两位小数 |
paid_amount |
string | 已支付金额,单位元,固定两位小数 |
currency |
string | 币种,当前为 CNY |
subscription_days |
integer | 本次订阅天数 |
subscription_action |
string | 归一化后的订阅动作:initial=首订,renewal=续订 |
is_auto_renew |
integer | 1=自动续订,2=不自动续订 |
status |
integer | 订阅充值业务单状态 |
payment |
object | 本次支付信息 |
payment.order_no |
string | 平台订单号 |
payment.transaction_no |
string | 支付流水号 |
payment.order_status |
integer | 订单状态 |
payment.payment_status |
integer | 支付流水状态:0=创建,1=预支付成功,2=支付成功,3=支付失败,4=已关闭,5=已退款 |
payment.payment_method |
string | wechat=微信,alipay=支付宝,apple_iap=苹果内购 |
payment.provider_code |
string | 接入产品:wechat_app、wechat_h5、alipay_app、alipay_wap、apple_iap |
payment.payment_account_id |
integer | 实际命中的支付账号 ID |
payment.payment_amount |
string | 支付金额,单位元,固定两位小数 |
payment.currency |
string | 币种 |
payment.pay_params |
object | 客户端拉起支付所需参数 |
payment.pay_params.trade_type |
string | APP、MWEB 或 WAP |
payment.pay_params.pay_url |
string | H5 支付跳转地址,仅 MWEB/WAP 返回 |
payment.pay_params.h5_url |
string | 微信返回的原始 H5 地址,仅 MWEB 返回 |
payment.pay_params.return_url |
string | 本次支付最终使用的完成回跳地址,仅微信 H5、支付宝 WAP 返回;客户端非空值优先,否则为后台配置 |
reused_order |
boolean | 是否复用了当前 Tieup 账号的相同购买意图待支付订单 |
payment_expires_at |
string | 支付参数失效时间 |
remaining_seconds |
integer | 支付窗口剩余秒数,最小为 0 |
H5 微信订阅请求完整示例:
POST /tieup/api/v1/subscriptions
Authorization: Bearer <access_token>
X-App-Platform: h5
Idempotency-Key: subscription_h5_10001_20260731143000_x7f9k2
Content-Type: application/json
{
"artist_id": 1,
"subscription_plan_code": "month_30",
"sub_type": "month",
"subscription_action": "initial",
"payment_method": "wechat",
"is_auto_renew": 2,
"return_url": "https://h5.example.com/payment/result?source=subscription"
}
H5 微信订阅响应完整示例:
{
"code": 200,
"message": "成功",
"data": {
"recharge_no": "RC202607150001",
"order_no": "TO202607150001",
"transaction_no": "TP202607150001",
"artist_id": 1,
"subscription_plan_code": "month_30",
"payment_amount": "30.00",
"paid_amount": "0.00",
"currency": "CNY",
"subscription_days": 30,
"subscription_action": "initial",
"is_auto_renew": 2,
"status": 1,
"payment": {
"order_no": "TO202607150001",
"transaction_no": "TP202607150001",
"order_status": 1,
"payment_status": 1,
"payment_method": "wechat",
"provider_code": "wechat_h5",
"payment_account_id": 3,
"payment_amount": "30.00",
"currency": "CNY",
"pay_params": {
"trade_type": "MWEB",
"pay_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx_example&package=123&redirect_url=https%3A%2F%2Fh5.example.com%2Fpayment%2Fresult%3Fsource%3Dsubscription",
"h5_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx_example&package=123",
"return_url": "https://h5.example.com/payment/result?source=subscription"
}
},
"reused_order": false,
"payment_expires_at": "2026-07-27 15:30:00",
"remaining_seconds": 1800
}
}
H5 回跳地址幂等规则:
- 支付参数已生成后,同一订单重试未传
return_url时沿用首次地址;显式传入与首次地址完全相同(去除首尾空白后比较)时复用首次支付参数。 - 显式传入不同地址,或历史支付流水没有
pay_params.return_url快照但本次传入地址时,返回422,data.error_code = payment_return_url_conflict;服务端不会创建新流水或重新请求微信、支付宝。 - 客户端地址允许任意完整 HTTP(S) 域名,客户端必须只提交可信业务页面,不能使用用户输入直接拼接不可信跳转目标。
回跳地址冲突完整响应示例:
{
"code": 422,
"message": "return_url与首次支付请求不一致",
"data": {
"error_code": "payment_return_url_conflict"
}
}
原订单正在关闭完整响应示例:
{
"code": 422,
"message": "原待支付订单正在关闭,请稍后重试",
"data": {
"error_code": "pending_order_closing",
"pending_order": {
"order_no": "TO202607270001",
"artist_id": 1,
"subscription_plan_code": "month_30",
"sub_type": "month",
"subscription_action": "initial",
"payment_method": "wechat",
"payment_amount": "30.00",
"payment_expires_at": "2026-07-27 15:30:00",
"remaining_seconds": 0
},
"retry_after_seconds": 2
}
}
业务规则:
- 创建时写入
tieup_order和tieup_user_recharge,recharge_type = 2或自动订阅时为3。 - 新订单必须使用
tieup_artist_pricing.status = 1且subscription_plan_code与请求完全一致的艺人当前档位;服务端在订单事务内锁定定价行,防止艺人并发切换档位。未选择、定价禁用或请求其他档位返回422。 - 普通单次订阅不要求艺人在
tieup_artist_subscription_config配置该档位;单次订单的配置 ID、配置版本和第三方订阅资源快照为null,但仍固化业务档位、价格、结算基数和权益天数。 - 自动续订必须存在匹配且启用的“艺人 + 档位”配置,并固化配置 ID、版本、第三方资源、价格、结算基数和权益天数;后续配置修改不改变历史订单和协议。
- APP 判断支付入口时,以艺人详情
subscription_plan.auto_renew_methods为准:数组为空仍可展示微信、支付宝单次订阅;只有请求is_auto_renew=1时才要求对应自动续订渠道存在。 -
subscription_action非必填,不传、传null或空字符串时按initial处理;其他值返回422。同一Idempotency-Key重试必须保持订阅动作一致。 - 从未订阅当前艺人时只允许
initial;历史订阅已经断续时允许initial或renewal;当前存在有效非自动订阅时只允许renewal;当前存在有效自动订阅时禁止客户端重复首订或续订,Apple 已扣款的服务端自动续订通知仍正常处理。 - 支付窗口统一为 30 分钟并在订单创建时固化。相同 Tieup 账号换设备或更换
Idempotency-Key后,只要用户、艺人、套餐、周期、订阅动作、支付方式、金额、自动续订属性及支付路由兼容,接口返回原订单和仍有效的支付参数,reused_order=true。 - 精确命中既有
Idempotency-Key的重放先按原购买意图复用订单,不因艺人后续切换档位破坏原请求的幂等结果;非精确重放和新订单必须重新校验当前艺人档位。 - 同一用户、同一艺人允许同时存在多笔待支付订阅订单;不同
Idempotency-Key的请求每次创建独立订单,客户端可按订单号分别继续支付或取消。 - 同一
Idempotency-Key仍只对应一笔订阅订单;同键重试复用原订单及其支付参数,不会创建第二笔订单。 - 到达 30 分钟边界、订单已申请取消或第三方关单未确认时返回
422,data.error_code=pending_order_closing;客户端按retry_after_seconds短暂等待并轮询订单详情,不得立即创建新单。 - 原订单已支付但权益尚未发放时返回
422,data.error_code=payment_delivery_pending,服务端同时投递支付发放补偿。 -
sub_type必须传入month或year,服务端会把该值固化到tieup_user_recharge.extra.sub_type,支付成功后写入tieup_subscription.sub_type。 -
sub_type=month的普通结算价使用订阅档位price_cent,订阅天数使用duration_days;platform=1的 iOS 订单实付金额使用config.ios_month_price_cent,其他平台实付金额等于普通月费。 -
sub_type=year的普通结算价使用config.annual_price_cent,订阅天数固定为 365 天;platform=1的 iOS 订单实付金额使用config.ios_year_price_cent。缺少对应普通年费或 iOS 年费时返回422,不得静默回退其他价格。 - iOS 月费不得低于普通月费,iOS 年费不得低于普通年费。订阅下单时同时把实付金额和普通结算价固化到业务单,后续档位改价不影响已创建订单的艺人结算。
- 支付成功后生成或续期
tieup_subscription,订阅记录使用subscription_plan_code、plan_name_snapshot、amount_cent、settlement_base_amount_cent、duration_days、sub_type快照;amount_cent是本周期实付金额,settlement_base_amount_cent是艺人分成使用的购买时普通价格,sub_type是月卡/年卡唯一可信来源。 - 新订阅
started_at取支付平台可信支付时间与当前连续订阅最终结束时间中的较晚者;提前续订从原连续结束时间开始,断续后从实际支付时间开始。客户端不能提交续订时间。 - 每生成一条新的
tieup_subscription记录,服务端都会登记并异步发送一条Tieup:Subscribe超级群定向消息,包括首次订阅、连续续费、手动续费和 Apple 自动续订;重复支付回调按subscription_no幂等,不重复创建消息。 -
tieup_user_recharge.uk_idempotency_key (user_id, idempotency_key)保留原请求幂等约束;tieup_subscription_order_request.uk_user_idempotency记录换设备产生的多个幂等键到同一订单的映射。 - 同一
Idempotency-Key重复请求:已生成可支付参数时返回原支付参数;上一请求仍在创建支付流水时返回422,提示“支付流水已创建或正在创建中,请稍后查询订单支付状态”,避免重复拉起第三方支付。同一个幂等键不能在month和year之间复用。 - iOS/Android 微信和支付宝继续返回 APP SDK 参数;H5 必须传
X-App-Platform: h5,微信 MWEB 和支付宝 WAP 返回payment.pay_params.pay_url,浏览器跳转后仍需查询订单状态,不能把回跳页面当作支付成功依据。 - Apple IAP 使用 StoreKit 1 / SwiftyStoreKit。创建订单时必须传
payment_method=apple_iap、is_auto_renew=1和X-App-Platform: ios。服务端按“艺人 + 档位 + 周期”从艺人订阅配置读取 Product ID 并固化 Subscription Group;客户端不提交这些标识。响应返回payment.pay_params.product_id和application_username,购买成功后只提交完整小票到POST /tieup/api/v1/payment-orders/apple-iap-receipts。 - Apple
is_auto_renew=2返回422。微信、支付宝is_auto_renew=2保持现有 APP/H5 单次支付;当前代码库尚无真实签约代扣网关,传is_auto_renew=1返回422“当前支付渠道自动续订签约能力尚未接入”,不会创建假协议或普通支付订单。 - Apple 订阅链按 Bundle ID、环境和
original_transaction_id唯一绑定 Tieup 用户、艺人和agreement_id;续费只按协议快照创建原艺人订单。Product ID 切换必须命中协议中同一 Subscription Group 的月/年商品快照。