# 会员订阅:iOS

# 一、概述

# 1. 能力说明

小程序虚拟支付在 iOS 端提供会员订阅能力。用户完成一次签约后,由 Apple 按周期自动扣费。

特性 说明
签约入口 wx.requestAppleSubscribeSign
扣款方 Apple 自动续费(非开发者发起)
退订方式 用户在 App Store 设置中退订
费率 12%(Apple 佣金)
物品互通 订阅物品安卓、苹果双端通用
版本要求 微信客户端 ≥ 8.0.71,小程序基础库 ≥ 3.16.1

# 2. 支持的签约类型

签约类型 说明 首开价格 续费价格
原价 首开和续费均为原价 物品原价 物品原价
优惠价 首开优惠,续费恢复原价 自定义优惠价 物品原价
免费试用 首开 0 元,续费恢复原价 0 元 物品原价

# 3. 准入条件

# 条件 说明
1 已接入小程序虚拟支付 基础前提
2 已开通 iOS 支付 苹果订阅依赖 iOS 支付通道,必须先完成 iOS 支付接入
3 已开通小程序订阅制 安卓和苹果的订阅均需提前开通小程序订阅制

# 二、接入流程

# Step 1:申请开通

收件人:wx_virtualpayment@tencent.com

前置条件

  1. 已接入小程序虚拟支付
  2. 小程序首次发布时间至今 ≥ 90 天
  3. 小程序完成认证备案
  4. 近 30 天日均 DAU ≥ 1 万

邮件主题申请开通小程序订阅 - 小程序昵称 - 申请日期

邮件正文

小程序昵称:
小程序appid:
虚拟支付商户号:
小程序主体:
小程序类目:
业务模式:主营业务、小程序 DAU、交易金额
申请用途:苹果订阅相关产品
页面交互:(开通、续费、管理流程,图片 jpg/png 格式,文件大小不超过 2MB)

交互示意:

交互图片注意事项

  1. 不允许使用拍照图片
  2. 需将完整交互放在一张图片中
  3. 购买记录页面需要出现客服电话,且客服电话需要完成认证

# Step 2:物品配置

在 MP 后台配置订阅道具,配置方式与安卓订阅一致:

小程序后台 → 虚拟支付 → 基础配置 → 道具配置 → 添加道具 → 选择「会员订阅」

物品的 product_id 在安卓和苹果端通用,不需要为苹果端单独创建新的订阅物品。


# Step 3:苹果订阅签约

签约前提:若用户已签约并完成解约,需等待当前订阅周期结束后,才能再次发起签约。

# 3.1 接口说明

项目 说明
接口名 wx.requestAppleSubscribeSign
用途 调起苹果订阅签约支付页(iOS 端使用)
版本要求 微信客户端 ≥ 8.0.71,小程序基础库 ≥ 3.16.1

# 3.2 入参

层级 字段 类型 必填 说明
顶层 signData string 支付参数,需通过 JSON.stringify() 转为字符串
paySig string 支付签名,计算方式:to_hex(hmac_sha256(appKey, uri + '&' + signData)),appKey 见 MP 后台虚拟支付基础配置
signature string 用户态签名,计算方式同 paySig
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(成功、失败都会执行)
signData offerId string 支付侧申请的应用 ID
productId string 订阅道具 ID
goodsPrice number 道具单价(单位:分)
activitySellingPrice number 见下方签约类型控制
attach string 透传数据,签约成功通知 / 发货通知时透传给开发者,字段长度不要超过 200,不允许有特殊字符

# 3.3 签约类型控制

三种签约类型通过 activitySellingPrice 参数控制:

签约类型 activitySellingPrice 效果
原价签约 不填 首开和续费均为原价
优惠价签约 填大于 0 的值 首开为优惠价,续费恢复原价
免费试用 0 首开 0 元,续费恢复原价

# 3.4 调用示例

原价签约

wx.requestAppleSubscribeSign({
  signData: JSON.stringify({
    offerId: '1450032323',
    productId: 'subscription_vip_monthly',
    goodsPrice: 3000,
    attach: 'uid=12345'
  }),
  paySig: '...',
  signature: '...',
  success(res) { /* 拉起成功 */ },
  fail(err) { /* 用户取消或失败 */ }
})

优惠价签约(首开 9.9 元,续费恢复原价 30 元):

wx.requestAppleSubscribeSign({
  signData: JSON.stringify({
    offerId: '1450032323',
    productId: 'subscription_vip_monthly',
    goodsPrice: 3000,
    activitySellingPrice: 990,
    attach: 'uid=12345'
  }),
  paySig: '...',
  signature: '...',
  success(res) { /* 拉起成功 */ },
  fail(err) { /* 用户取消或失败 */ }
})

免费试用签约(首开 0 元,续费恢复原价):

wx.requestAppleSubscribeSign({
  signData: JSON.stringify({
    offerId: '1450032323',
    productId: 'subscription_vip_monthly',
    goodsPrice: 3000,
    activitySellingPrice: 0,
    attach: 'uid=12345'
  }),
  paySig: '...',
  signature: '...',
  success(res) { /* 拉起成功 */ },
  fail(err) { /* 用户取消或失败 */ }
})

注意:该接口返回值不能作为签约成功的判定标准,需以签约成功通知或签约查询结果为准。


# Step 4:接收通知

# 4.1 通知场景

场景 通知事件 说明
签约成功 xpay_apple_subscribe_signing_result_notify 用户首次签约成功,告知开发者建立签约关系、开通权益
扣款成功 xpay_goods_deliver_notify 扣款成功,开发者发货或延长会员有效期
解约(退订) xpay_apple_subscribe_unsigning_result_notify 用户关闭自动续费(解约)时下发

# 4.2 签约成功通知(xpay_apple_subscribe_signing_result_notify

触发时机:用户首次签约成功时下发一次。续费场景不会再次发送此通知。

基础字段

字段 类型 说明
ToUserName String 小程序原始 ID
FromUserName String openid
CreateTime Number 消息发送时间
MsgType String 消息类型,固定为 event
Event String 事件类型 xpay_apple_subscribe_signing_result_notify
OpenId String 用户 openid
Attach String 签约时透传的 attach
AppleSubscriptionInfo Object 苹果订阅签约信息,详见下方

AppleSubscriptionInfo 内容

字段 类型 说明
OriginalTransactionId String 苹果原始交易 ID。以 App Store 账号为维度标识用户,同一 App Store 账号在同一订阅道具上的签约关系中该值保持不变(续费、扣款均沿用),可作为该条订阅关系的唯一标识。
ProductId String 订阅道具 ID
AutoRenewStatus Number 自动续费状态:1 开启 / 0 关闭
RenewalDate Number 下次续费时间(毫秒级 Unix 时间戳)
SignedTime Number 签约成功时间(毫秒级 Unix 时间戳)

# 4.3 扣款发货通知(xpay_goods_deliver_notify

触发时机:每次扣款成功后下发。首次扣款与后续自动续费扣款通知格式一致。

基础字段

字段 类型 说明
ToUserName String 小程序原始 ID
FromUserName String 该事件消息的 openid,固定为微信官方的 openid
CreateTime Number 消息发送时间
MsgType String 消息类型,固定为 event
Event String 事件类型 xpay_goods_deliver_notify
OpenId String 用户 openid
OutTradeNo String 业务订单号
WeChatPayInfo Object 支付信息
GoodsInfo Object 道具参数信息
AppleSubscriptionInfo Object 苹果订阅关系信息(苹果订阅场景携带;安卓订阅 / 普通支付不携带)

GoodsInfo 内容

字段 类型 说明
ProductId String 道具 ID
Quantity Number 数量
OrigPrice Number 物品原始价格(单位:分)
ActualPrice Number 物品实际支付价格(单位:分)
Attach String 透传信息

AppleSubscriptionInfo 内容

字段 类型 说明
OriginalTransactionId String 苹果原始交易 ID。以 App Store 账号为维度标识用户,同一 App Store 账号在同一订阅道具上的签约关系中该值保持不变(续费、扣款均沿用),可作为该条订阅关系的唯一标识。
AutoRenewStatus Number 自动续费状态:1 开启 / 0 关闭
RenewalDate Number 下次续费时间(毫秒级 Unix 时间戳)

# 4.4 解约通知(xpay_apple_subscribe_unsigning_result_notify

触发时机:用户关闭自动续费(解约)时下发。

基础字段

字段 类型 说明
ToUserName String 小程序原始 ID
FromUserName String openid
CreateTime Number 消息发送时间
MsgType String 消息类型,固定为 event
Event String 事件类型 xpay_apple_subscribe_unsigning_result_notify
OpenId String 用户 openid
Attach String 签约时透传的 attach
Action String 动作类型,固定为 unsubscribe
AppleSubscriptionInfo Object 苹果订阅解约信息,详见下方

AppleSubscriptionInfo 内容

字段 类型 说明
OriginalTransactionId String 苹果原始交易 ID。以 App Store 账号为维度标识用户,同一 App Store 账号在同一订阅道具上的签约关系中该值保持不变(续费、扣款均沿用),可作为该条订阅关系的唯一标识。
ProductId String 订阅道具 ID(开发者的 out_product_id)
AutoRenewStatus Number 自动续费状态,解约时固定为 0(已关闭)
RenewalDate Number 订阅到期时间(毫秒级 Unix 时间戳),即当前订阅周期的结束时间
UnsignedTime Number 解约时间(毫秒级 Unix 时间戳)

# 4.5 返回参数

各类通知的返回格式一致,开发者收到通知后需按以下格式返回:

字段 类型 必填 说明
ErrCode Number 处理状态:0 成功,其他为失败
ErrMsg String 错误原因,用于调试

XML 示例:

<xml>
  <ErrCode>0</ErrCode>
  <ErrMsg>success</ErrMsg>
</xml>

# Step 5:平台自动写入苹果订阅订单

# 5.1 背景

苹果订阅的扣款由 Apple 自动发起,小程序平台无法主动发起扣款,只能被动接收 Apple 的扣款通知。为保证订单数据完整,平台会在收到 Apple 扣款通知后,自动在虚拟支付订单表中写入一条苹果订阅扣款成功的订单记录,订单类型标记为苹果订阅。

# 5.2 写入时机

平台收到 Apple 的扣款通知后:

  • 向开发者推送 xpay_goods_deliver_notify(开发者处理发货)
  • 同步在平台订单库写入一条订单记录(订单类型 = 苹果订阅)

# Step 6:订阅状态查询

开发者可随时查询用户的订阅状态,包括自动续费开关、下次续费时间等。

# 6.1 接口说明

项目 说明
接口地址 POST https://api.weixin.qq.com/xpay/query_subscribe_contract?access_token=ACCESS_TOKEN&pay_sig=PAY_SIG
查询口径 通过 mode 字段区分安卓 / 苹果订阅;不填默认查安卓订阅
注意事项 苹果订阅状态更新依赖苹果通知,苹果通知最多有 10 秒 延迟

# 6.2 请求参数

参数 类型 必填 说明
mode String 查询模式:android(默认)/ apple
openid String 用户 openid
product_id String 道具 ID,需为订阅制道具
out_contract_code String mode=android 时必传,签约时传入的协议号

# 6.3 响应参数

公共响应

参数 类型 说明
errcode Number 错误码,0 表示成功
errmsg String 错误信息
authorization_state String 签约授权状态:SIGNED 签约生效中 / TERMINATED 已解约 / UNBINDUSER 从未签约
apple_subscription_info Object 苹果订阅信息(仅 mode=apple 返回)

apple_subscription_info 内容

字段 类型 说明
original_transaction_id String 苹果原始交易 ID。以 App Store 账号为维度标识用户,同一 App Store 账号在同一订阅道具上的签约关系中该值保持不变(续费、扣款均沿用),可作为该条订阅关系的唯一标识。
auto_renew_status Number 自动续费状态:1 开启 / 0 关闭
recent_subscription_start_date Number 在一系列订阅购买中,自动续订订阅的最早起始日期;该日期将忽略所有时长为 60 天或更短的付费服务中断期(毫秒级 Unix 时间戳)
renewal_date Number 下次续费到期时间(毫秒级 Unix 时间戳)

# 6.4 响应示例(mode=apple)

{
  "errcode": 0,
  "errmsg": "ok",
  "authorization_state": "SIGNED",
  "apple_subscription_info": {
    "original_transaction_id": "2000001147426510",
    "auto_renew_status": 1,
    "recent_subscription_start_date": 1775226065000,
    "renewal_date": 1775226245000
  }
}

# Step 7:退款处理

# 7.1 退款基本规则

  • Apple 支付不支持开发者主动向用户发起退款
  • 用户可在 App Store 申请退款

# 7.2 用户申请退款流程

  1. 用户在 App Store 提出退款申请
  2. Apple 支付根据自身策略判断,并向开发者发起连续三次退款问询
  3. 开发者可根据自身策略响应问询
  4. Apple 支付只会参考开发者的问询结果,最终结果仍由 Apple 支付处理

详情可咨询苹果公司(Apple)。

# 7.3 退款问询通知(xpay_subscribe_ios_refund_query_notify

消息推送和原有规范保持一致:消息推送

重要提示:如果连续 3 次、在 3 秒内均未应答退款问询,微信平台会向 Apple 支付返回**「不确定」**作为退款参考,也即退款决定权交由苹果公司(Apple)处理。

问询消息内容WxaVirtualPayIosRefundQueryNotifyEvent):

字段 类型 备注
refund_time string 问询时间,Unix 时间戳
order_time string 该笔退款的订单时间(退款订单对应的交易时间),Unix 时间戳
channel_bill string Apple 支付票据号
bundleid string 应用的 Apple bundleid
product_id string 道具 id
p_count string 道具 / 代币数量
refund_request_reason string 用户请求退款的原因
provide_status string 发货状态,0:未发货,1:已发货,2:发货中
pay_order_id string 退款对应支付订单号

# 7.4 应答响应(IosRefundQueryResponse

字段 类型 备注
result_code int32 结果码,0 - 放过(建议退款);1 - 拦截(拒绝退款)
result_info string 结果描述
evidence string 决策凭据(必填),业务需返回建议退款 / 拒绝退款的依据,用于退款审计

# 7.5 退款成功后续通知

如 Apple 支付发起退款并退款成功,平台会通过原有的退款推送接口通知开发者: