与 Stripe 的初始集成
Adapty 通过追踪通过 Stripe 完成的网页支付和订阅,支持 web2app 订阅流程。
此集成涵盖网页端发起的购买(Stripe Checkout、托管支付页面或自定义网页流程),并将其与移动应用的访问权限和数据分析进行同步。
适用于以下场景:
- 为在网页端完成购买、之后安装应用并登录账户的用户自动开通付费功能
- 在单一 Adapty 看板中查看所有订阅分析数据(包括同期群、趋势预测及其他分析工具)
尽管网页端购买在应用中越来越普遍,但 Apple App Store 目前仅允许美国地区对数字商品采用应用内购买以外的支付方式。请确保不要在其他国家的应用内推广您的网页订阅,否则应用可能会被拒审或下架。
以下步骤介绍如何配置 Stripe 集成。
本集成的重点是追踪和同步 Stripe 网页端购买。如果您需要将用户从应用引导至网页结算页面,请参阅网页付费墙。
1. 将 Stripe 连接到 Adapty
此集成主要依靠 Adapty 通过 webhook 从 Stripe 拉取订阅数据。因此,您需要提供 API 密钥,并在 Stripe 中使用 Adapty 的 webhook URL,将您的 Adapty 账户与 Stripe 账户关联起来。为自动配置 webhook,请在 Stripe 中安装 Adapty 应用:
以下步骤对 Stripe 的生产模式和测试模式均适用,但每种模式需要使用不同的 API 密钥。
-
确认您是以测试模式还是正式模式连接 Stripe。如果您最初在测试模式下操作,之后还需要对正式模式重复以下步骤。
-
前往 Stripe 应用市场 安装 Adapty 应用。请注意,沙盒模式不支持安装应用,只能在生产模式或测试模式下安装。
- 授予应用所需权限,这将允许 Adapty 访问订阅数据和历史记录。然后点击 Continue to app settings 继续。
在权限弹窗底部,您可以选择以正式模式还是测试模式安装应用。
- 在弹窗中生成一个新的受限密钥。您需要通过邮件、Touch ID 或安全密钥验证身份。密钥生成后将无法再次查看,请将其安全存储在密码管理器或密钥存储中。
- 从弹窗中复制生成的密钥,然后前往 Adapty 的 App Settings → Stripe。根据您的模式,将密钥粘贴到 Stripe App Restricted API Key 对应区域。请注意,测试模式和正式模式需要生成不同的密钥。
大功告成!接下来,在 Stripe 中创建产品并将其添加到 Adapty。
已弃用的安装流程
- 在 Stripe 中前往 Developers → API Keys:
- 点击 Secret key 旁边的 Reveal live (test) key button,复制密钥后前往 Adapty 的 App Settings → Stripe,将密钥粘贴到此处:
- 接下来,从 Adapty 同一页面底部复制 Webhook URL。在 Stripe 中前往 Developers → Webhooks,点击 Add endpoint 按钮:
-
将 Adapty 的 webhook URL 粘贴到 Endpoint URL 字段中。然后在 webhook 的 Version 字段中选择 Latest API version,并选择以下事件:
- charge.refunded
- customer.subscription.created
- customer.subscription.deleted
- customer.subscription.paused
- customer.subscription.resumed
- customer.subscription.updated
- invoice.created
- invoice.updated
- payment_intent.succeeded
- 点击”Add endpoint”,然后在”Signing secret”下点击”Reveal”。这是用于在 Adapty 端解码 webhook 数据的密钥,显示后请复制:
- 最后,将此密钥粘贴到 Adapty 的 App Settings → Stripe 中的”Stripe Webhook Secret”字段:
2. 在 Stripe 中创建产品
如果您是在测试模式下进行配置,请在继续此步骤之前确认 Stripe 已切换到测试模式。
前往 Stripe 的产品目录,创建您想要销售的产品及其定价方案。请注意,Stripe 支持每个产品配置多个定价方案,无需创建额外产品即可灵活调整您的产品组合。
目前 Adapty 仅支持固定价格($9.99/月)或打包定价($9.99/10 个单位),因为这两种方式与应用商店的行为类似。阶梯定价、基于用量的收费和客户自定义价格选项目前不受支持。
3. 将 Stripe 产品添加到 Adapty
产品是必须配置的!请务必在 Adapty 看板中创建您的 Stripe 产品。Adapty 仅追踪与这些产品关联的交易事件,请不要跳过此步骤——否则交易事件将无法创建。
我们对待 Stripe 的方式与 App Store 和 Google Play 相同:它只是您销售数字产品的另一个渠道,配置方式也类似。只需将 Stripe 产品(即其 product_id 和 price_id)添加到 Adapty 的产品区域即可:
Stripe 中的产品 ID 格式为 prod_...,价格 ID 格式为 price_...。在 Stripe 的产品目录中打开任意产品,即可轻松找到这些信息:
添加完所有必要产品后,下一步是告知 Stripe 哪位用户正在完成购买,以便 Adapty 能够识别!
4. 在网页端购买中附加用户 ID
Adapty 依赖来自 Stripe 的 webhook 作为唯一数据来源,用于为用户提供和更新访问等级。但在使用 Stripe 时,您需要从您这端提供额外信息,才能确保集成正常运行。
为了让访问等级在各平台(网页或移动端)保持一致,您需要确保使用单一用户 ID,让 Adapty 能够通过 webhook 识别该用户。这可以是用户的邮箱、手机号,或您所使用的授权系统中的任意其他 ID。
确定您希望用于识别用户的 ID。然后在代码中找到通过 Stripe 初始化支付的部分,并将该用户 ID 以 customer_user_id 为键添加到 Stripe Subscription(sub_...)或 Checkout Session(ses_...)对象的 metadata 字段中,如下所示:
{'customer_user_id': "YOUR_USER_ID"}
这一简单的改动是您在代码层面唯一需要做的事情。之后,Adapty 会解析从 Stripe 接收到的所有 webhook,提取该 metadata,并将订阅正确关联到您的客户。
用户 ID 是必填项
否则,我们将无法匹配该用户并在移动端为其授予访问等级。
如果您没有在 metadata 中提供 customer_user_id,可以选择让 Adapty 在其他位置查找 customer_user_id:要么使用 Stripe 客户对象中的 email,要么使用 Stripe Session 中的 client_reference_id。
了解更多关于配置用户画像创建行为的信息,请参阅下方内容。
Stripe 中的 Customer 也是必需的
如果您使用 Checkout Sessions,请确保创建了 Stripe Customer,将 customer_creation 设置为 always。
5. 为移动端用户开通访问权限
为确保从网页端进入的移动用户能够访问付费功能,只需使用与上一步相同的 customer_user_id 调用 Adapty.activate() 或 Adapty.identify()(详情请参阅 识别用户 iOS、Android、React Native、Flutter 和 Unity )。
6. 测试集成
请确保已分别为沙盒环境和生产环境完成上述步骤。通过 Stripe 测试模式发起的交易在 Adapty 中将被识别为沙盒交易。
大功告成!
您的用户现在可以在网页端完成购买,并在应用中访问付费功能。同时,您也可以在同一个地方查看所有订阅分析数据。
用户画像创建行为
Adapty 需要将购买记录与客户用户画像绑定,才能在移动端使用——因此默认情况下,它会在收到 Stripe 的 webhook 时创建用户画像。您可以选择将以下内容用作 Adapty 中的客户用户 ID:
- 默认且推荐: 您在上方第 4 步的 metadata 中提供的
customer_user_id - Stripe 客户对象中的
email(参见 Stripe 文档) - Stripe Session 对象中的
client_reference_id(参见 Stripe 文档)
您可以在 App Settings → Stripe 中配置使用哪种 ID。
注意: 如果来自 Stripe 的某笔交易不包含指定的 ID,我们将不会创建用户画像。该交易将保持匿名状态,直到被某个用户画像认领(例如,如果您之后使用 S2S validate 手动告知我们该交易信息)。
该交易会出现在 Analytics 中,但不会出现在依赖用户画像计数的区域(LTV、同期群、转化率等),您也无法在事件流中看到它。
您还有第四个选项——完全不创建用户画像,但由于上述分析限制,不建议这样做。
当前限制
升级、降级与按比例计费
订阅变更(如升级或降级)可能产生按比例计费。Adapty 不会在收入计算中考虑这些费用。建议通过 Stripe 看板手动禁用这些选项。您也可以通过 Stripe API 将 proration_behaviour 属性值设为 none 来禁用它们。
取消订阅
Stripe 提供两种订阅取消方式:
- 立即取消:订阅立即取消,可选是否进行按比例计费
- 在当前计费周期结束时取消:订阅在当前计费周期结束时取消(与应用商店中的应用内订阅类似)
Adapty 支持这两种方式,但立即取消的收入计算将忽略按比例计费选项。
账单问题与宽限期
当客户遇到付款问题时,Adapty 将生成账单问题事件并撤销访问权限。我们目前尚不支持 Stripe 的宽限期功能——这将在未来版本中实现。
退款
Adapty 仅追踪全额退款,目前不支持按比例退款或部分退款。
交易 ID 唯一性
Adapty 使用 store_transaction_id 和 store_original_transaction_id 来匹配用户画像和交易。这些 ID 在测试环境和生产环境之间必须保持唯一。
为何这很重要
如果同一个交易 ID 在两个环境中都存在,Adapty 会将其视为同一笔交易,从而导致:
- 生产环境的购买继承测试环境的访问等级和产品 ID
- API 响应中出现错误的产品 ID 和环境信息
- 用户画像关联和订阅事件被干扰
如何确保唯一性
Stripe 的发票 ID 在测试环境和正式环境之间可能重叠。为避免跨环境冲突,请选择以下一种方式:
方案一:账户级编号加环境前缀
为每个环境分别配置前缀:
- 在 Stripe 看板中切换到测试模式。
- 前往 Settings → Billing → Invoices。
- 将 Invoice numbering 设置为 Sequentially across your account。
- 将 Invoice prefix 设置为 TEST-(或其他专用于测试环境的前缀)。
- 切换到正式模式,重复第 2-4 步,使用 LIVE-(或其他专用于正式环境的前缀)作为前缀。
方案二:客户级编号
在 Stripe 设置 -> Billing -> Invoices 标签页中,将 Invoice numbering 设置为 Sequentially for each customer (customer-level)。
即使进行了上述配置,如果您删除了某张发票,Stripe 可能会将该 ID 重新分配给同一客户的新发票。因此请尽量避免删除发票。
通过 Stripe Checkout 或 Payment Links 进行的一次性购买
Adapty 仅在 Stripe 为购买生成发票时,才会追踪通过 Stripe Checkout(mode=payment)或 Payment Links 完成的一次性(非订阅)购买。默认情况下,Stripe 不会为一次性 Checkout 购买创建发票。在这种情况下,payment_intent.succeeded 事件不包含发票数据,Adapty 无法据此记录交易。
要在 Adapty 中追踪一次性 Checkout 购买,请在创建 session 时启用发票创建。这样 Stripe 就会生成发票并触发相关的 invoice.created 和 invoice.updated 事件,Adapty 通过处理这些事件来记录交易。
充分利用您的 Stripe 数据
完成 Stripe 集成后,Adapty 即可立即提供数据洞察。为充分利用您的 Stripe 数据,您可以设置额外的 Adapty 集成来转发 Stripe 事件——将所有订阅分析数据汇聚到单一 Adapty 看板中。
为获得更丰富的分析数据,您可以在 Stripe metadata 中添加 variation_id,以将购买归因到特定的付费墙实例。这在实现自建网页付费墙时尤为有用,可以追踪是哪个具体的付费墙展示带来了转化。
请注意,variation_id 仅从 Stripe Subscription(sub_...)和 Checkout Session(ses_...)对象的 metadata 中读取:
{
'customer_user_id': "YOUR_USER_ID",
'variation_id': "YOUR_VARIATION_ID"
} 可用于转发和分析 Stripe 事件的集成:
支持的 Stripe 事件
Adapty 支持以下 Stripe 事件:
- charge.refunded
- customer.subscription.created
- customer.subscription.deleted
- customer.subscription.paused
- customer.subscription.resumed
- customer.subscription.updated
- invoice.created
- invoice.updated
- payment_intent.succeeded