Skip to content

Asset 业务事件

支持 stripe/paypal/paddle/funnelfox 4 个平台的购买事件。

1. 事件 schema

字段名称类型说明
idstring事件 id
timeint事件发生时间,毫秒级时间戳
namestring事件名称,具体名称见本文档【事件列表】
user_idstringbytepower 用户 id
app_idstringbytepower app id
platformstringstripe/paypal/paddle/funnelfox
app_platformstringbytepower console 上配置的 app platform
bundle_idstringbytepower console 上配置的 bundle_id
bytepower_product_idstringbytepower asset product_id
platform_product_idstring第三方平台的 product_id
client_ipstring用户的客户端 ip
environmentstringbytepower 服务环境,develop, debug 或 product
api_envstring第三方 API 的环境,sandbox 或 product
device_infodevice_info objectdevice_info 对象,merge 了 用户购买时上传的 device_info 以及当前 session 关联的 account_ids 信息。
对于 funnelfox 平台来说,在 bytepower console 的 funnelfox 平台配置中的 extra order info 中的字段也会被 merge 到 device_info 里面。
datamap of object事件关联的对象
data.stripe_data_versionstringstripe 数据结构的版本号(详见本文档【Stripe 数据兼容方案】)

1.1 业务对象字段说明

device_info object

device_info 由客户端在购买时上传。它会优先使用客户端在购买时通过购买接口上传的信息。如果 device_info 中某个信息字段不存在,而 account_ids 表中对应的该字段存在,就会将 account_ids 表中的数据 merge 过来。account_ids 表中的数据由 signup/login 接口上传,且会被购买接口上传的 device_info 更新。

subscription object

字段名称类型说明
sub_idstring订阅 id
platformstringstripe/paypal/paddle/funnelfox
statusstring订阅状态,包括 active (活跃),canceled(已取消),finished(已结束,除 active 和 canceled 之外的所有状态)
is_free_trialbool是否在免费试用期内,且订阅状态正常(status==active)
is_free_trial_cyclebool是否在免费试用期 cycle 内,此时订阅状态不一定正常(status 不一定是 active)
is_trialbool是否在试用期内,且订阅状态正常(status==active)
is_trial_cyclebool是否在试用期 cycle 内,此时订阅状态不一定正常(status 不一定是 active)
platform_statusstring订阅在第三方平台的状态,不同平台 (stripe/paypal/paddle/funnelfox) 的状态取值不同。对于 funnelfox,状态可能是多个值,此时用逗号隔开,如 AUTORENEW_OFF,INTRO。
cycle_countint目前是第几个周期(从 1 开始,试用期包括在内)
paid_cycle_countint目前订阅成功支付几次,不包括免费试用期
created_atint订阅创建时间,毫秒时间戳
updated_atint订阅更新时间,毫秒时间戳

subscription_transaction object

字段名称类型说明
transaction_idstring交易 id
payment_idstring支付 id
platformstringstripe/paypal/paddle/funnelfox
statusstringtransaction 状态,包括 succeeded, failed, pending, refunded
platform_statusstring订阅在第三方平台的状态,不同平台 (stripe/paypal/paddle/funnelfox) 的状态取值不同。
amountint交易金额,标准单位乘以 100 万
currencystring交易币种,如 usd
created_atint创建时间,毫秒时间戳
updated_atint更新时间,毫秒时间戳

oneoff object

字段名称类型说明
order_idstring订单 id
payment_idstring支付 id
platformstringstripe/paypal/paddle/funnelfox
statusstring订单状态,包括 succeeded (成功), failed(失败), pending(处理中), refunded(已全额退款)
platform_statusstring订单在第三方平台的状态,不同平台 (stripe/paypal/paddle/funnelfox) 的状态取值不同
amountint交易金额,标准单位乘以 100 万
currencystring交易币种,如 usd
created_atint创建时间,毫秒时间戳
updated_atint更新时间,毫秒时间戳

refund object

字段名称类型说明
idstringrefund id
platformstringstripe/paypal/paddle/funnelfox
is_latest_payment_refundbool是否是最近一期退款;对一次性购买总是 true
amountint退款金额,标准单位乘以 100 万
currencystring退款币种,如 usd
statusstring退款状态,包括 succeeded(成功), failed(失败),pending(处理中)
platform_statusstring退款在第三方平台的状态,不同第三方平台(stripe/paypal/paddle/funnelfox),该字段取值不一样
created_atint退款创建时间
updated_atint退款更新时间

assets 字段

assets 是一个列表,包含这一订单相关联的用户资产(注:不一定是用户当前的所有资产,因为用户可能有其它的购买),资产格式同 asset/me 接口。

2. 事件列表

事件名称说明data 中的跨平台字段data 中的paypal平台原始数据字段data 中的stripe平台原始数据字段data 中的 paddle 平台原始数据字段data 中 funnelfox 平台原始数据字段
asset.subscription.purchased订阅首次支付成功,金额可能为0(含免费试用期)1. subscription
2. subscription_transaction (paypal / funnelfox 平台免费试用期无此字段)
3. assets
1. paypal_subscription
2. paypal_subscription_transaction(paypal 平台免费试用期无此字段)
3. paypal_subscription_payment (paypal 平台免费试用期无此字段)
4. paypal_subscription_plan
stripe_subscription
stripe_transaction
paddle_subscription
paddle_transaction
funnelfox_subscription
funnelfox_transaction(免费试用期无此字段)
funnelfox_transaction_v2(免费试用期无此字段)
注:transaction 和 v2 只有其一
asset.subscription.renewed订阅续订成功1. subscription
2. subscription_transaction
3. assets
1. paypal_subscription
2. paypal_subscription_transaction
3. paypal_subscription_payment
4. paypal_subscription_plan
stripe_subscription
stripe_transaction
paddle_subscription
paddle_transaction
funnelfox_subscription
funnelfox_transaction
funnelfox_transaction_v2
注:transaction 和 v2 只有其一
asset.subscription.canceled订阅已取消1. subscription
2. subscription_transaction (paypal 免费试用期取消无此字段)
3. assets
1. paypal_subscription
2. paypal_subscription_transaction(paypal 平台免费试用期无此字段)
3. paypal_subscription_payment (paypal 平台免费试用期无此字段)
4. paypal_subscription_plan
stripe_subscriptionpaddle_subscription
paddle_transaction
funnelfox_subscription
funnelfox_transaction(最近一次的付费订单信息,如果订阅没有进行过付费,没有此字段)
funnelfox_transaction_v2
注:transaction 和 v2 只有其一
asset.subscription.switched订阅升降级成功, paypal/stripe/paddle/funnelfox 支持1. subscription
2. subscription_transaction(funnelfox 平台如果 switch (migrate)过程中没有产生费用,则不会有此字段)
3. assets
1. paypal_subscription
2. paypal_subscription_transaction
3. paypal_subscription_payment
4. paypal_subscription_plan
5. paypal_previous_subscription (paypal 升降级之前的订阅)
stripe_subscription
stripe_transaction
paddle_subscription
paddle_transaction
funnelfox_subscription
funnelfox_transaction(如果 switch 没有产生费用,没有此字段)
funnelfox_transaction_v2(如果 switch 没有产生费用,没有此字段)
funnelfox_previous_subscription(funnelfox switch 之前的订阅)
注:transaction 和 v2 只有其一
asset.subscription.purchase_failed订阅首次购买支付失败1. subscription
2. subscription_transaction (对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
3. assets
注: funnelfox 无此事件
1. paypal_subscription
2. paypal_subscription_transaction(对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
3. paypal_subscription_payment(对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
4. paypal_subscription_plan
stripe_subscription
stripe_transaction
paddle 无此事件,因为首次支付失败时,订阅还没有创建
asset.subscription.renew_failed订阅续订支付失败1. subscription
2. subscription_transaction (对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
3. assets
注: funnelfox 无此事件
1. paypal_subscription
2. paypal_subscription_transaction(对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
3. paypal_subscription_payment(对于 paypal 来说,可能为空。实现时取的是最近的一个 transaction 信息,purchase 失败后,购买失败对应的 transaction 可能还没有创建)
4. paypal_subscription_plan
stripe_subscription
stripe_transaction
paddle_subscription
paddle_transaction
asset.subscription.refunded订阅退款1. subscription
2. subscription_transaction
3. refund
4. assets
1. paypal_subscription
2. paypal_subscription_transaction
3. paypal_subscription_payment
4. paypal_subscription_plan
5. paypal_subscription_v1_refund
6. paypal_subscription_v2_refund
注:v1_refund 和 v2_refund 有且只有一个
stripe_subscription
stripe_transaction
stripe_refund
paddle_subscription
paddle_transaction
paddle_refund
funnelfox_subscription
funnelfox_transaction
funnelfox_transaction_v2
funnelfox_refund
注:transaction 和 v2 只有其一
asset.oneoff.purchased一次性购买支付成功1. oneoff
2. assets
1. paypal_oneoff
2. paypal_oneoff_payment
stripe_oneoffpaddle_transaction1. funnelfox_oneoff
asset.oneoff.purchase_failed一次性购买支付失败1. oneoff
2. assets
1. paypal_oneoff
2. paypal_oneoff_payment
stripe_oneoff无,需求没有接入暂未支持
asset.oneoff.refunded一次性购买退款1. oneoff
2. refund
3. assets
1. paypal_oneoff
2. paypal_oneoff_payment
3. paypal_oneoff_v1_refund
4. paypal_oneoff_v2_refund
注:v1_refund 和 v2_refund 有且只有一个
stripe_oneoff
stripe_refund
paddle_transaction
paddle_refund
1. funnelfox_oneoff
2. funnelfox_refund

FunnelFox 说明

funnelfoix 二期上线后,funnelfox_transaction 变为 funnelfox_transaction_v2,且数据结构发生了变化。两者只有其一。

3. 原始事件对应表

下表给出了 bytepower 事件和平台原始事件的对应关系

名称stripepaypalpaddlefunnelfox
asset.subscription.purchasedinvoice.paidBILLING.SUBSCRIPTION.ACTIVATEDtransaction.completedevent_type: subscription
sub_type: starting_trial 或 convertion
asset.subscription.renewedinvoice.paidPAYMENT.SALE.COMPLETEDtransaction.completedevent_type: subscription
sub_type: convertion 或 renewing
asset.subscription.canceledcustomer.subscription.deletedBILLING.SUBSCRIPTION.CANCELLEDsubscription.canceledevent_type: subscription
sub_type: unsubscription
asset.subscription.switchedinvoice.paidBILLING.SUBSCRIPTION.ACTIVATEDtransaction.completedevent_type: subscription
sub_type: starting_trial 或 convertion
asset.subscription.upgraded--不支持,只有 switched 事件不支持,只有 switched 事件
asset.subscription.downgraded--不支持,只有 switched 事件不支持,只有 switched 事件
asset.subscription.purchase_failedinvoice.payment_failedBILLING.SUBSCRIPTION.PAYMENT.FAILED没有此事件,第三方无此 webhook没有此事件,第三方无此 webhook
asset.subscription.renew_failedinvoice.payment_failedBILLING.SUBSCRIPTION.PAYMENT.FAILEDtransaction.past_due没有此事件,第三方无此 webhook
asset.subscription.refundedcharge.refundedPAYMENT.SALE.REFUNDED
PAYMENT.CAPTURE.REFUNDED
adjustment.updatedevent_type: refund
sub_type: settled
asset.oneoff.purchasedpayment_intent.succeededPAYMENT.CAPTURE.COMPLETED无,需求没有接入event_type: order
sub_type: settled
asset.oneoff.purchase_failedpayment_intent.payment_failedPAYMENT.CAPTURE.DECLINED无,需求没有接入没有此事件,第三方无此 webhook
asset.oneoff.refundedcharge.refundedPAYMENT.SALE.REFUNDED
PAYMENT.CAPTURE.REFUNDED
无,需求没有接入event_type: refund
sub_type: settled

4. 平台字段说明

4.1 PayPal 字段文档

字段名称paypal 文档链接
paypal_subscriptionDefinition-Subscription
paypal_subscription_transactionDefinition-Transaction
paypal_subscription_paymentDefinition-Capture
paypal_subscription_planDefinition-Plan
paypal_previous_subscriptionDefinition-Subscription
paypal_subscription_v1_refundDefinition-Refund V1
paypal_subscription_v2_refundDefinition-Refund V2
paypal_oneoffDefinition-Order
paypal_oneoff_paymentDefinition-Capture
paypal_oneoff_v1_refundDefinition-Refund V1
paypal_oneoff_v2_refundDefinition-Refund V2

PayPal 常见问题

  • 为什么 paypal 退款事件中有 v1 和 v2 两个版本的退款信息? 原因是 paypal 的退款回调有两个,这两个回调带回的退款信息版本不同,分为 v1 和 v2 两个版本,且不能互相转换。退款时触发哪个 paypal 回调,带回哪个版本的退款信息取决于退款的渠道。一次性购买的退款只返回 v2 版本的退款;paypal 后台的订阅型退款返回 v1 版本的退款信息,其它渠道的订阅型退款返回 v2 版本的退款信息。

  • 为什么 paypal 订阅免费试用期的事件中没有 transaction 信息? 原因是 paypal 在免费试用期时,不会产生 transaction 对象。这和 stripe 不同,stripe 的免费试用期会返回一个支付金额为 0 的 transaction 对象。

  • 为什么 paypal 的 asset.subscription.switched 事件中有一个 paypal_previous_subscription 字段? 原因是当前 paypal 订阅的升降级是通过购买新订阅,然后再取消并退款现有的老订阅来实现的,这个字段里的信息就是被取消的老订阅。

  • paypal_subscription_transaction 和 paypal_subscription_payment 有什么关系? 对于同一个交易来说,两者的 id 是一样的,代表同一笔交易。只不过这两者由 paypal 的两套 API 返回,返回的字段不同。

4.2 Stripe 说明

  • stripe_oneoff 表示 stripe payment_intent
  • stripe_subscription 表示 stripe subscription
  • stripe_transaction 表示 stripe invoice
  • stripe_refund 表示 stripe refund
  • stripe 平台会添加 _stripe_event_raw 表示 BP 实际收到并且处理的平台原始数据(仅在 BP debug 环境)

4.3 FunnelFox 数据示例

由于 FunnelFox 官方未提供数据结构说明文档,这里给出具体的例子。

Subscription 数据结构

funnelfox_subscription 和 funnelfox_previous_subscription 数据结构如下 :

json
{
  "event_id": "33cc79d3-0f8c-4662-a137-759642e1f805",
  "event_timestamp": "2025-12-18T05:33:48.025758",
  "event_type": "subscription",
  "external_id": "UUF5BJRD2KOBX",
  "is_livemode": false,
  "order": {
    "amount": "2",
    "created_at": "2025-12-18T05:33:44.814196",
    "currency_code": "USD",
    "decline_reason": null,
    "external_id": "UUF5BJRD2KOBX",
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_851363003449749504",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "oneoff_id": null,
    "order_id": "cba3e784-c66f-4a44-b921-501d5fd888ff",
    "psp": "stripe",
    "retry_step": null,
    "status": "settled",
    "subs_id": "c81994c7-f80d-447b-93dd-d9a15d99ba2e",
    "user_uuid": "bd1d39c2-359c-48e9-b708-a1e7cbbef4ca"
  },
  "subscription": {
    "available_actions": [ "pause", "defer", "disable_autorenew", "create_discount", "migration" ],
    "current_period_ends_at": "2025-12-19T07:33:30.815991",
    "current_period_starts_at": "2025-12-18T07:33:30.815991",
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_851363003449749504",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "is_active": true,
    "iteration": 3,
    "next_check_at": "2025-12-19T05:33:30.815991",
    "price_point": {
      "currency": { "code": "USD", "minor_units": 2, "symbol": "$", "title": "US Dollar" },
      "features": [ { "ident": "product_01K99H50E9S6CZFPPNE3QGES8K" } ],
      "ident": "price_01K99H5THCKZ98TJSJB02B711X",
      "next_period": 1,
      "next_period_duration": "days",
      "next_price": "2"
    },
    "started_at": "2025-12-16T07:33:30.815991",
    "status": [ "RECURRING" ],
    "subs_id": "c81994c7-f80d-447b-93dd-d9a15d99ba2e"
  },
  "subtype": "renewing",
  "user": {
    "email": "user@example.com",
    "external_id": "UUF5BJRD2KOBX"
  }
}

Transaction 数据结构

funnelfox_transaction (只在 funnelfox 二期上线前有此字段):

json
{
  "event_id": "19d1962a-7103-4ad8-beff-0fb17311504c",
  "event_timestamp": "2025-12-17T05:33:46.042209",
  "event_type": "order",
  "is_livemode": false,
  "oneoff": null,
  "order": {
    "amount": "1.6",
    // ...
    "order_id": "18e7f77e-9822-4186-8005-b68a790f8c54",
    "status": "settled",
    "subs_id": "c81994c7-f80d-447b-93dd-d9a15d99ba2e"
  }
}

funnelfox_transaction_v2 (只在 funnelfox 二期上线后有此字段):

json
{
    "order_id": "40cb1883-510e-431c-aeb0-7569d1b89dd1",
    "amount": "2",
    "currency_code": "USD",
    "external_id": "UUF6XO3DIGEKL",
    "subs_id": "7b2cb919-7c3f-41da-8370-9c2d8c2e6026",
    "user_uuid": "8c8d5a42-8a4a-4dbb-92f8-5e516050a3e2",
    "oneoff_id": null,
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_858986190014525440",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "status": "authorized",
    "decline_reason": null,
    "retry_step": null,
    "psp": "stripe",
    "created_at": "2026-01-06T08:24:56.910284Z"
 }

Refund 数据结构

funnelfox_refund 数据结构如下 :

订阅退款,有 subscription 相关字段:

json
{
  "amount_refunded": "1",
  "created_at": "2025-12-16T09:26:34.988980",
  "currency_code": "USD",
  "event_id": "874eeca9-3a61-4be9-89e3-3f8e34b544e0",
  "event_timestamp": "2025-12-16T09:26:34.988980",
  "event_type": "refund",
  "external_id": "UUF5BP2CBOXRM",
  "is_livemode": false,
  "oneoff": null,
  "order": {
    "amount": "2",
    "created_at": "2025-12-16T09:23:07.172827",
    "currency_code": "USD",
    "decline_reason": null,
    "external_id": "UUF5BP2CBOXRM",
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_851390623214219264",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "oneoff_id": null,
    "order_id": "3c2f1f7b-e0ea-4b86-ae0d-25702cdc62fc",
    "retry_step": null,
    "status": "settled",
    "subs_id": "6f9a9a64-f26b-4834-851b-a8667bb6700f",
    "user_uuid": "ed11dbf3-8a2d-4e0c-aaba-76b069d2d05f"
  },
  "order_id": "3c2f1f7b-e0ea-4b86-ae0d-25702cdc62fc",
  "refund_at": "2025-12-16T09:26:32.907975",
  "subs_id": "6f9a9a64-f26b-4834-851b-a8667bb6700f",
  "subscription": {
    "available_actions": [
      "pause",
      "defer",
      "disable_autorenew",
      "create_discount",
      "migration"
    ],
    "current_period_ends_at": "2025-12-17T09:23:31.292268",
    "current_period_starts_at": "2025-12-16T09:23:31.292268",
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_851390623214219264",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "is_active": true,
    "iteration": 1,
    "next_check_at": "2025-12-17T07:23:31.292268",
    "price_point": {
      "currency": {
        "code": "USD",
        "minor_units": 2,
        "symbol": "$",
        "title": "US Dollar"
      },
      "features": [
        {
          "ident": "product_01K99H50E9S6CZFPPNE3QGES8K"
        }
      ],
      "ident": "price_01K99H5THCKZ98TJSJB02B711X",
      "intro_free_trial_period": null,
      "intro_free_trial_period_duration": null,
      "intro_paid_trial_period": null,
      "intro_paid_trial_period_duration": null,
      "intro_paid_trial_price": null,
      "intro_type": "no_intro",
      "lifetime_price": null,
      "next_period": 1,
      "next_period_duration": "days",
      "next_price": "2"
    },
    "started_at": "2025-12-16T09:23:31.292268",
    "status": [
      "RECURRING"
    ],
    "subs_id": "6f9a9a64-f26b-4834-851b-a8667bb6700f"
  },
  "subtype": "settled",
  "trx_id": "9bf31d09-cbba-4e13-9d9a-a9f4802beb50",
  "user": {
    "email": "user@example.com",
    "external_id": "UUF5BP2CBOXRM"
  }
}

一次性购买退款,有一次性购买相关字段:

json
{
  "amount_refunded": "0.8",
  "created_at": "2025-12-16T09:13:19.634004",
  "currency_code": "USD",
  "event_id": "62cba982-8f0a-4710-8d93-2e3f21beaafc",
  "event_timestamp": "2025-12-16T09:13:19.634004",
  "event_type": "refund",
  "external_id": "UUF5BPBX4VUNO",
  "is_livemode": false,
  "oneoff": {
    "initial_order_metadata": {
      "abc": "def",
      "bp_tx_id": "BPTX_851387278873341953",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "is_active": true,
    "oneoff_id": "faf3e396-09be-408f-9119-87eb7ef0c133",
    "order_id": "4f67461d-74de-495c-953f-361c9306e45f",
    "price_point": {
      "currency": {
        "code": "USD",
        "minor_units": 2,
        "symbol": "$",
        "title": "US Dollar"
      },
      "features": [
        {
          "ident": "product_01KB4XKKVKV0YN1PJY4A1CDTFC"
        }
      ],
      "ident": "price_01KB4XM0RWXPP5C8XNFE5BWHMS",
      "intro_free_trial_period": null,
      "intro_free_trial_period_duration": null,
      "intro_paid_trial_period": null,
      "intro_paid_trial_period_duration": null,
      "intro_paid_trial_price": null,
      "intro_type": "no_intro",
      "lifetime_price": "1.5",
      "next_period": null,
      "next_period_duration": null,
      "next_price": null
    },
    "revoked_at": null,
    "started_at": "2025-12-16T09:10:19.116300"
  },
  "order": {
    "amount": "1.5",
    "created_at": "2025-12-16T09:09:55.885353",
    "currency_code": "USD",
    "decline_reason": null,
    "external_id": "UUF5BPBX4VUNO",
    "initial_order_metadata": {
      "abc": "def",
      "bp_tx_id": "BPTX_851387278873341953",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "oneoff_id": "faf3e396-09be-408f-9119-87eb7ef0c133",
    "order_id": "4f67461d-74de-495c-953f-361c9306e45f",
    "retry_step": null,
    "status": "settled",
    "subs_id": null,
    "user_uuid": "b3a9ad65-f88f-402d-a9be-772878c6803b"
  },
  "order_id": "4f67461d-74de-495c-953f-361c9306e45f",
  "refund_at": "2025-12-16T09:13:17.652425",
  "subs_id": null,
  "subscription": null,
  "subtype": "settled",
  "trx_id": "e9a5e58c-305c-40ee-923b-f8dd3b342da8",
  "user": {
    "email": "user@example.com",
    "external_id": "UUF5BPBX4VUNO"
  }
}

funnelfox_oneoff

{
    "order_id": "40cb1883-510e-431c-aeb0-7569d1b89dd1",
    "amount": "2",
    "currency_code": "USD",
    "external_id": "UUF6XO3DIGEKL",
    "subs_id": null,
    "user_uuid": "8c8d5a42-8a4a-4dbb-92f8-5e516050a3e2",
    "oneoff_id": "7b2cb919-7c3f-41da-8370-9c2d8c2e6026",
    "initial_order_metadata": {
      "abc": "def",
      "bp_sub_id": "BPSUB_858986190014525440",
      "cde": "fgh",
      "email": "user@example.com"
    },
    "status": "authorized",
    "decline_reason": null,
    "retry_step": null,
    "psp": "stripe",
    "created_at": "2026-01-06T08:24:56.910284Z"
}

5. Stripe 平台数据兼容方案

event.data 中的 stripe_subscription, stripe_transaction, stripe_refund, stripe_oneoff 数据结构是 stripe 平台的数据结构,而随着 stripe API 版本的不同,这些数据结构会发生一些变化,所以在解析这些数据结构时,需要先确定这些数据结构的版本,再进行解析。

在新版本的 bytepower 中(新版本待上线),添加了 data.stripe_data_version 字段,存储了上述 stripe 数据结构的版本号,如果程序在处理事件时用到了上述字段,需要做以下事情,以正确处理不同版本的事件数据结构:

  1. 如果事件没有 data.stripe_data_version 字段(目前 bytepower 生产环境的状态),则说明事件是老版本事件,仍按现有的方式进行使用。
  2. 如果事件有 data.stripe_data_version 字段(说明 bytepower 已升级为新版本),需要按照该字段存储的 stripe API 版本对上述 stripe 的数据结构进行解析。bytepower 待发布新版本使用的版本是 2025-08-27.basil,如果后续再有版本升级,会提前发通知。

解析不同版本的 stripe 数据结构,需要用到 stripe 不同版本的 SDK,如解析 2025-08-27.basil,需要用到的 stripe go SDK 是 v82 版本。

5.1 Stripe Expand 机制

在已经上线的 bytepower 支持 stripe 新版本中,对以上 stripe 数据结构的部分内嵌数据结构进行了扩展(expand),具体情况如下:

字段名称对应 stripe 的数据结构expand 的子数据结构
data.stripe_subscriptionsubscriptionlatest_invoice
latest_invoice.payments
default_payment_method
pending_setup_intent
customer
data.stripe_transactioninvoicepayments
payments.data.payment.charge
payments.data.payment.payment_intent
data.stripe_oneoffpayment_intentlatest_charge
latest_charge.refunds
latest_charge.payment_intent
data.stripe_refundrefundcharge
payment_intent

stripe expand 机制文档参考:https://docs.stripe.com/api/expanding_objects

子数据结构 expand 与否,同一字段的数据类型会发生变化,现以 subscription (即 data.stripe_subscription 对应的数据结构)的 latest_invoice 举例如下:

不 expand latest_invoice,相关字段如下,可以看到 latest_invoice 字段是字符串类型,保存了 latest_invoice 的 id:

json
{
  "id": "sub_1S6o4iJeDjdpBmRtD6s0yfH6",
  "object": "subscription",
  "latest_invoice": "in_1SCFDLJeDjdpBmRtImUzpEO1"
}

expand latest_invoice 后,相关字段如下,可以看到 latest_invoice 字段变成了一个完整的数据结构,不再是字符串了:

json
{
  "id": "sub_1S6o4iJeDjdpBmRtD6s0yfH6",
  "object": "subscription",
  "latest_invoice": {
    "id": "in_1SCFDLJeDjdpBmRtImUzpEO1",
    "object": "invoice",
    "account_country": "GB",
    "account_name": null,
    "account_tax_ids": null,
    "amount_due": 3000,
    "amount_overpaid": 0,
    "amount_paid": 3000,
    "amount_remaining": 0,
    "amount_shipping": 0,
    "application": null,
    "application_fee_amount": null,
    "attempt_count": 1,
    "attempted": true,
    "auto_advance": false
    // other fields...
   }
}

stripe SDK 隐藏了以上细节,如果使用 stripe SDK,在没有 expand 时,subscription.latest_invoice 只有 id 字段有值(即 subscription.latest_invoice.id 有值), latest_invoice 的其它字段都没有值。在 expand 后,subscription.latest_invoice 每个字段都有对应的值。需要注意的是,上面的例子只是 expand 了 latest_invoice,而 latest_invoice 下仍有嵌套的子数据结构,这些数据结构并没有展开。

6. 事件示例

json
{
  "id": "NzYyNjAzNDExNTY4MzQwOTky",
  "time": 1744708400720,
  "name": "asset.subscription.purchased",
  "user_id": "UUFJKT3ZYIHXS",
  "app_id": "APPFXTBPTSARSU6B",
  "platform": "paypal",
  "app_platform": "android",
  "bundle_id": "zhoufeng_test_app",
  "byte_power_product_id": "BUY4GM3SSXAKHI56",
  "client_ip": "103.100.64.122",
  "environment": "develop",
  "api_env": "sandbox",
  "device_info": {
        "uuid": "xxxx"
  },
  "data": {
    "assets": [
      {
        "bp_product_id": "BUY4GM3SSXAKHI56",
        "custom_expire_time": "0001-01-01T00:00:00Z",
        "expire_time": "2025-04-17T09:13:16Z",
        "is_auto_renewable": true,
        "is_consumable": true,
        "is_refund": false,
        "is_trial_period": false,
        "name": "superv",
        "origin": "purchase",
        "platform": "paypal",
        "product_id": "PROD-7X917145DM3139335",
        "quantity": 200,
        "receipt_id": "I-5TN95H90FV7P",
        "refund_time": "0001-01-01T00:00:00Z",
        "sub_canceled": false,
        "sub_canceled_time": "0001-01-01T00:00:00Z",
        "sub_canceled_ts": 0,
        "total_quantity": 200,
        "type": "subscription",
        "valid_seconds": 172773
      },
      {
        "bp_product_id": "BUY4GM3SSXAKHI56",
        "custom_expire_time": "0001-01-01T00:00:00Z",
        "expire_time": "2025-04-17T09:13:16Z",
        "is_auto_renewable": true,
        "is_consumable": true,
        "is_refund": false,
        "is_trial_period": false,
        "name": "vip",
        "origin": "purchase",
        "platform": "paypal",
        "product_id": "PROD-7X917145DM3139335",
        "quantity": 100,
        "receipt_id": "I-5TN95H90FV7P",
        "refund_time": "0001-01-01T00:00:00Z",
        "sub_canceled": false,
        "sub_canceled_time": "0001-01-01T00:00:00Z",
        "sub_canceled_ts": 0,
        "total_quantity": 100,
        "type": "subscription",
        "valid_seconds": 172773
      },
      {
        "bp_product_id": "BUY4GM3SSXAKHI56",
        "custom_expire_time": "0001-01-01T00:00:00Z",
        "expire_time": "2025-04-17T09:13:16Z",
        "is_auto_renewable": true,
        "is_consumable": true,
        "is_refund": false,
        "is_trial_period": false,
        "name": "vip1",
        "origin": "purchase",
        "platform": "paypal",
        "product_id": "PROD-7X917145DM3139335",
        "quantity": 150,
        "receipt_id": "I-5TN95H90FV7P",
        "refund_time": "0001-01-01T00:00:00Z",
        "sub_canceled": false,
        "sub_canceled_time": "0001-01-01T00:00:00Z",
        "sub_canceled_ts": 0,
        "total_quantity": 150,
        "type": "subscription",
        "valid_seconds": 172773
      }
    ],
    "paypal_subscription": {
      "plan_id": "P-86E6357727421122EMXOZZOI",
      "start_time": "2025-04-15T09:12:30Z",
      "quantity": "1",
      "shipping_amount": {
        "currency_code": "USD",
        "value": "0.0"
      },
      "subscriber": {
        "payer_id": "DVQ47262CJSTW",
        "shipping_address": {
          "address": {
            "address_line_1": "1 Main St",
            "admin_area_1": "CA",
            "admin_area_2": "San Jose",
            "postal_code": "95131",
            "country_code": "US"
          }
        },
        "name": {
          "given_name": "test",
          "surname": "buyer"
        },
        "email_address": "zhoufengloop-buyer@gmail.com"
      },
      "custom_id": "{\"app_id\":\"APPFXTBPTSARSU6B\",\"ip\":\"103.100.64.122\",\"test_field\":\"a\",\"user_id\":\"UUFJKT3ZYIHXS\"}",
      "id": "I-5TN95H90FV7P",
      "status": "ACTIVE",
      "status_update_time": "2025-04-15T09:13:17Z",
      "billing_info": {
        "outstanding_balance": {
          "currency": "",
          "value": "0.0"
        },
        "cycle_executions": [
          {
            "tenure_type": "REGULAR",
            "sequence": 1,
            "cycles_completed": 1
          }
        ],
        "last_payment": {
          "amount": {
            "currency_code": "USD",
            "value": "10.0"
          },
          "time": "2025-04-15T09:13:16Z"
        },
        "next_billing_time": "2025-04-16T10:00:00Z"
      },
      "create_time": "2025-04-15T09:13:16Z",
      "update_time": "2025-04-15T09:13:17Z",
      "links": [
        {
          "href": "https://api.sandbox.paypal.com/v1/billing/subscriptions/I-5TN95H90FV7P/cancel",
          "rel": "cancel",
          "method": "POST"
        },
        {
          "href": "https://api.sandbox.paypal.com/v1/billing/subscriptions/I-5TN95H90FV7P",
          "rel": "edit",
          "method": "PATCH"
        },
        {
          "href": "https://api.sandbox.paypal.com/v1/billing/subscriptions/I-5TN95H90FV7P",
          "rel": "self",
          "method": "GET"
        },
        {
          "href": "https://api.sandbox.paypal.com/v1/billing/subscriptions/I-5TN95H90FV7P/suspend",
          "rel": "suspend",
          "method": "POST"
        },
        {
          "href": "https://api.sandbox.paypal.com/v1/billing/subscriptions/I-5TN95H90FV7P/capture",
          "rel": "capture",
          "method": "POST"
        }
      ]
    },
    "paypal_subscription_payment": {
      "status": "COMPLETED",
      "id": "8KA609050M480543P",
      "amount": {
        "currency_code": "USD",
        "value": "10.00"
      },
      "custom_id": "{\"app_id\":\"APPFXTBPTSARSU6B\",\"ip\":\"103.100.64.122\",\"test_field\":\"a\",\"user_id\":\"UUFJKT3ZYIHXS\"}",
      "seller_protection": {
        "status": "ELIGIBLE",
        "dispute_categories": [
          "ITEM_NOT_RECEIVED",
          "UNAUTHORIZED_TRANSACTION"
        ]
      },
      "final_capture": true,
      "seller_receivable_breakdown": {
        "gross_amount": {
          "currency_code": "USD",
          "value": "10.00"
        },
        "paypal_fee": {
          "currency_code": "USD",
          "value": "0.84"
        },
        "net_amount": {
          "currency_code": "USD",
          "value": "9.16"
        }
      },
      "links": [
        {
          "href": "https://api.sandbox.paypal.com/v2/payments/captures/8KA609050M480543P",
          "rel": "self",
          "method": "GET"
        },
        {
          "href": "https://api.sandbox.paypal.com/v2/payments/captures/8KA609050M480543P/refund",
          "rel": "refund",
          "method": "POST"
        }
      ],
      "update_time": "2025-04-15T09:13:16Z",
      "create_time": "2025-04-15T09:13:16Z"
    },
    "paypal_subscription_transaction": {
      "status": "COMPLETED",
      "id": "8KA609050M480543P",
      "amount_with_breakdown": {
        "gross_amount": {
          "currency_code": "USD",
          "value": "10.00"
        },
        "fee_amount": {
          "currency_code": "USD",
          "value": "0.84"
        },
        "shipping_amount": {
          "currency_code": "",
          "value": ""
        },
        "tax_amount": {
          "currency_code": "",
          "value": ""
        },
        "net_amount": {
          "currency_code": "USD",
          "value": "9.16"
        }
      },
      "payer_name": {
        "given_name": "test",
        "surname": "buyer"
      },
      "payer_email": "zhoufengloop-buyer@gmail.com",
      "time": "2025-04-15T09:13:16Z"
    },
    "subscription": {
      "sub_id": "I-5TN95H90FV7P",
      "platform": "paypal",
      "status": "active",
      "platform_status": "ACTIVE",
      "is_trial": false,
      "cycle_count": 1,
      "paid_cycle_count": 1,
      "created_at": 1744708422241,
      "updated_at": 1744708422241
    },
    "subscription_transaction": {
      "transaction_id": "8KA609050M480543P",
      "payment_id": "8KA609050M480543P",
      "platform": "paypal",
      "platform_status": "COMPLETED",
      "status": "succeeded",
      "amount": 9000000,
      "currency": "usd",
      "created_at": 1744708396000,
      "updated_at": 1744708396000
    }
  }
}

7. 其它配置

7.1 Server 配置

server 配置 (config.yaml) 中需要新增配置,向第三方平台(如 caspian) 上报事件

yaml
services:
  webhook:
    keys:
      - name: caspian
        key_id: fc140f5312b54a98
        key_secret: d9558f440740406b960c57397a33ba69

7.2 Console 配置

webhook 系统设计文档:bytepower webhook 模块设计文档

京ICP备19011570号-2