---
title: "事件流"
description: "了解 Adapty 中订阅事件流的详细方案。学习订阅事件如何生成并发送到各集成渠道，帮助您追踪客户旅程中的关键节点。"
---

在 Adapty 中，您将在用户使用应用的整个历程中收到各种订阅事件。以下订阅流程涵盖了常见场景，帮助您了解 Adapty 在用户订阅、取消或重新激活订阅时生成的事件。

请注意，Apple 会在实际开始/续订时间前数小时处理订阅付款。为保持图表简洁，以下流程图将订阅开始/续订与付款扣除显示为同时发生。
此外，与同一操作相关的事件会同时发生，在 **Event Feed** 中的显示顺序可能不固定，与我们图示中的顺序也可能有所不同。
## 订阅生命周期 \{#subscription-lifecycle\}
### 初次购买流程 \{#initial-purchase-flow\}

当用户首次购买订阅且没有试用期时，会触发以下事件：

- **Subscription started**
- **Access level updated**：授予用户访问权限

当订阅到达续期日期时，订阅将自动续期，并触发以下事件：

- **Subscription renewal**：开始新一个订阅周期
- **Access level updated**：更新订阅到期日期，将访问权限延长至下一个周期
付款失败或用户取消续订的情况分别在[账单问题结果流程](event-flows#billing-issue-outcome-flow)和[订阅取消流程](event-flows#subscription-cancellation-flow)中描述。

  <img src="/assets/shared/img_webhook_flows/Initial_Purchase_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 订阅取消流程 \{#subscription-cancellation-flow\}

当用户取消订阅时，系统会创建以下事件：

- **Subscription renewal canceled**：表示订阅在当前周期结束前仍保持有效，之后用户将失去访问权限
- **Access level updated**：用于禁用该访问等级的自动续费功能

订阅到期后，系统会触发 **Subscription expired (churned)** 事件，标志着订阅的结束。

  <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

如果退款申请获批，以下事件将替代 **Subscription expired (churned)**：

- **Subscription refunded**：终止订阅并提供退款详情

  <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow_with_a_Refund.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

对于 Stripe，订阅可以立即取消，跳过剩余的订阅周期。在这种情况下，所有事件会同时创建：

- **Subscription renewal cancelled**
- **Subscription expired (churned)**
- **Access Level updated**（用于移除用户的访问等级）
如果退款申请获批，系统还会触发 **Subscription refunded** 事件。

  <img src="/assets/shared/img_webhook_flows/Subscription_Immediate_Cancellation_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 订阅重新激活流程 \{#subscription-reactivation-flow\}

如果用户取消订阅后，订阅到期，之后又重新购买了同一订阅，系统将创建一个 **Subscription renewed** 事件。即使中间存在访问中断，Adapty 也会通过 `vendor_original_transaction_id` 将其视为同一交易链，因此此次重购被视为续订。

**Access level updated** 事件将被创建两次：

- 在订阅结束时，撤销用户的访问权限
- 在订阅重新购买时，授予访问权限

  <img src="/assets/shared/img_webhook_flows/Subscription_Rejoin_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 订阅暂停流程（仅限 Android）\{#subscription-pause-flow-android-only\}

此流程适用于用户在 Android 上暂停并随后恢复订阅的情况。

暂停订阅会产生延迟效果。如果用户在订阅续期前将其暂停，订阅仍保持有效，用户在当前计费周期剩余时间内继续享有付费访问权限。
1. 当用户暂停订阅时，会触发 **Subscription paused (Android only)** 事件。
2. 订阅周期结束时，Adapty 会触发 **Access level updated** 事件以撤销用户的访问权限。
3. 当用户恢复订阅时，将触发以下事件：

    - **Subscription renewed**
    - **Access level updated**（用于恢复用户的访问权限）

这些订阅将属于同一交易链，并通过相同的 **vendor_original_transaction_id** 关联。

  <img src="/assets/shared/img_webhook_flows/Subscription_Paused_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

## 试用流程 \{#trial-flows\}

如果您在应用中使用试用功能，您将收到额外的试用相关事件。
### 试用期成功转化流程 \{#trial-with-successful-conversion-flow\}

最常见的流程是：用户开始试用、绑定信用卡，并在试用期结束后成功转化为标准订阅。在此场景中，试用开始时会生成以下事件：

- **Trial started**：标记试用开始
- **Access level updated**：授予访问权限

当标准订阅正式生效时，系统会生成 **Trial converted** 事件。

  <img src="/assets/shared/img_webhook_flows/Trial_Flow_with_Successful_Conversion.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 试用未成功转化的流程 \{#trial-without-successful-conversion-flow\}

如果用户在试用期转化为订阅之前取消，系统会在取消时创建以下事件：

- **Trial renewal cancelled**：禁用试用期自动转化为订阅
- **Access level updated**：禁用访问等级续订

用户仍可使用至试用期结束，届时系统会创建 **Trial expired** 事件，标记试用期正式结束。

  <img src="/assets/shared/img_webhook_flows/Trial_Flow_without_Successful_Conversion.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 试用期到期后重新激活订阅的流程 \{#subscription-reactivation-after-expired-trial-flow\}

如果试用期因账单问题或取消而到期，用户后续购买订阅时，系统将创建以下事件：

- **访问等级已更新**，为用户授予访问权限
- **试用已转化**

即使试用期与订阅之间存在时间间隔，Adapty 也会通过 `vendor_original_transaction_id` 将两者关联起来。此次转化被视为一条连续交易链的一部分，该链从零价格的试用期开始。这就是系统创建 **试用已转化** 事件而非 **订阅已开始** 事件的原因。

  <img src="/assets/shared/img_webhook_flows/Subscription_Reactivation_Flow_after_Expired_Trial.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

## 产品变更 \{#product-changes\}

本节涵盖对活跃订阅所做的各类调整，例如升级、降级，或购买其他组合中的产品。
### 立即生效的产品变更流程 \{#immediate-product-change-flow\}

用户变更产品后，系统可以在订阅结束前立即完成切换（通常发生在升级或替换产品的情况下）。此时，在产品变更的瞬间：
- 访问等级发生变更，系统创建两个 **Access level updated** 事件：
  1. 撤销第一个产品的访问权限。
  2. 授予第二个产品的访问权限。
- 旧订阅结束，并退款（系统创建 **Subscription refunded** 事件，`cancellation_reason` = `upgraded`）。请注意，此时不会创建 **Subscription expired (churned)** 事件；**Subscription refunded** 事件将替代它。
- 新订阅开始（系统为新产品创建 **Subscription started** 事件）。

  <img src="/assets/shared/img_webhook_flows/Immediate_Product_Change_Flow_Upgrade.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

如果用户降级订阅，第一个订阅将持续到已付费周期结束，届时将被新的低级别订阅替换。在这种情况下，系统会立即创建 **Access level updated** 事件以禁用自动续订访问权限。所有其他事件将在订阅实际发生替换时创建：
- 另一个 **Access level updated** 事件被创建，以授予对第二个产品的访问权限。
- **Subscription expired (churned)** 事件被创建，以结束第一个产品的订阅。
- **Subscription started** 事件被创建，以开始新产品的新订阅。

  <img src="/assets/shared/img_webhook_flows/Delayed_Product_Change_Downgrade.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

### 延迟产品变更流程 \{#delayed-product-change-flow\}

还有一种情况：用户在订阅续费时更改产品。这种情况与前一种非常相似：系统会立即创建一个 **Access level updated** 事件，以禁用旧产品的访问等级自动续费。所有其他事件将在用户更改订阅且变更生效于系统时创建：
- 另一个 **Access level updated** 事件被创建，以授予对第二个产品的访问权限。
- **Subscription expired (churned)** 事件被创建，以结束第一个产品的订阅。
- **Subscription started** 事件被创建，以启动新产品的新订阅。

  <img src="/assets/shared/img_webhook_flows/Product_Change_on_Renewal_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

## 账单问题结果流程 \{#billing-issue-outcome-flow\}

如果试用转换或订阅续费因账单问题失败，后续流程取决于是否启用了宽限期。

启用宽限期时，若付款成功，试用将完成转换或订阅将完成续费。若付款失败，应用商店会继续尝试向用户收取订阅费用，如仍失败，则应用商店将自行终止试用或订阅。

因此，在账单问题发生时，Adapty 中会创建以下事件：
- **检测到账单问题**
- **已进入宽限期**（如果已启用宽限期）
- **访问等级已更新**，将访问权限延续至宽限期结束

如果后续付款成功，Adapty 会记录 **Trial converted** 或 **Subscription renewed** 事件，用户不会失去访问权限。

如果付款最终失败且应用商店取消了订阅，Adapty 将生成以下事件：

- **Trial expired** 或 **Subscription expired (churned)**，附带 `cancellation_reason: billing_error`
- **访问等级已更新**，撤销用户的访问权限

  <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_with_Grace_Period.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

如果没有宽限期，账单重试期（应用商店持续尝试向用户收费的时段）将立即开始。
如果在宽限期结束前付款始终未能成功，流程相同：当应用商店自动终止订阅时，会生成相同的事件：

- **Trial expired** 或 **Subscription expired (churned)** 事件，其 `cancellation_reason` 为 `billing_error`

- **Access level updated** 事件，用于撤销用户的访问等级

  <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_without_Grace_Period.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

## 跨用户账户共享购买的流程 \{#sharing-purchases-across-user-accounts-flows\}
当一个 <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration) 和 [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> 尝试恢复或续期已绑定到另一个 <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration) 和 [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> 的订阅时，Adapty 的 **Sharing paid access between user accounts** 设置将决定如何管理访问权限。具体流程会因所选选项而有所不同。
:::note
对于 Apple 家庭共享交易（`in_app_ownership_type=FAMILY_SHARED`），只会触发 **Access level updated** 事件——下方各产品的订阅事件不会触发。完整的事件矩阵请参阅 [Apple 家庭共享](apple-family-sharing)。
:::

:::note
如果用户点击 **Restore Purchases** 时，当前用户画像已拥有访问权限，则此次恢复操作无效，不会触发任何 Webhook 事件。本节中的事件仅在访问权限实际在用户画像之间转移时才会触发。
:::
要快速了解第二个用户画像领取现有订阅时会触发哪些事件，请参阅下方矩阵。后续各节将展示每种流程的完整 JSON 载荷。
| 事件 | 已启用（默认） | 将访问等级转移至新用户 | 已禁用 |
| --- | --- | --- | --- |
| 新用户画像：**Access level updated**（`is_active=true`） | 触发 | 触发 | 不触发 |
| 旧用户画像：**Access level updated**（`is_active=false`） | 不触发——两个用户画像均保留访问等级 | 当新识别设备传播交易时触发 | 不触发——原始用户画像保留访问等级 |
| 新事件中的 `profiles_sharing_access_level` 字段 | 列出共享该访问等级的其他用户画像 | `null` | 不适用——不触发任何事件 |
已转移订阅的续订、退款和到期事件，将继续在当前持有该访问等级的用户画像上触发 `subscription_renewed`、`subscription_refunded` 和 `subscription_expired` 事件。转移事件本身不会触发 `subscription_started` 事件，因为没有记录新的交易——只有归因关系发生了变化。

有关各模式的详细约定，请参阅[实用参考](sharing-paid-access-between-user-accounts#practical-reference)。
### 将访问等级转移给新用户的流程 \{#transfer-access-to-new-user-flow\}

推荐的做法是将访问等级转移给新用户。这样可以保留原始用户的交易记录，确保分析数据的一致性。整个过程只会产生 2 个 **Access level updated** 事件：

1. 移除第一个用户的访问等级
2. 授予第二个用户访问等级

  <img src="/assets/shared/img_webhook_flows/Transfer_Access_to_New_User_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

以下是此场景中生成的事件里，与访问等级分配及转移相关字段的说明：

- **用户 A：访问等级已更新（当用户 A 在应用内购买订阅时发送）**
```json showLineNumbers
  {
    "profile_id": "00000000-0000-0000-0000-000000000000",
    "customer_user_id": UserA,
    "event_properties": {
      "profile_has_access_level": true,
    },
    "profiles_sharing_access_level": null
  }
  ```

- **用户 A：访问等级已更新（当应用重新安装并由用户 B 登录，撤销用户 A 的访问权限时发送）**
```json showLineNumbers
  {
    "profile_id": "00000000-0000-0000-0000-000000000000",
    "customer_user_id": UserA,
    "event_properties": {
      "profile_has_access_level": false,
    },
    "profiles_sharing_access_level": null
  }
  ```

- **用户 B：访问等级已更新（当用户 B 登录并获得访问权限时发送）**

  ```json showLineNumbers
  {
    "profile_id": "00000000-0000-0000-0000-000000000001",
    "customer_user_id": UserB,
    "event_properties": {
      "profile_has_access_level": true,
    },
    "profiles_sharing_access_level": null
  }
  ```
### 用户间共享访问流程 \{#shared-access-between-users-flow\}
此选项允许多个用户共享同一访问等级，前提是他们的设备登录了相同的 Apple/Google ID。当用户重新安装应用并使用不同的邮箱登录时，仍可访问之前的购买内容，此选项非常适合这种场景。启用此选项后，多个已识别用户可以共享同一访问等级。在共享访问等级期间，所有交易记录均归属于原始 <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration) 和 [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip>，以确保完整的交易历史记录和分析数据。
因此，只会创建 1 个事件：**Access level updated**，用于向第二个用户授予访问权限。

  <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>

以下是该场景中生成的事件里，与访问等级分配和共享相关的字段说明：

**用户 B：Access level updated（当用户 B 登录并获得访问权限时发送）**
```json showLineNumbers
  {
    "profile_id": "00000000-0000-0000-0000-000000000000",
    "customer_user_id": UserA,
    "event_properties": {
      "profile_has_access_level": true,
    },
    "profiles_sharing_access_level": [
      {
        "profile_id": "00000000-0000-0000-0000-000000000001,
        "customer_user_id": UserB
      }
    ]
  }
  ```
### 用户之间访问权限不共享的流程 \{#access-not-shared-between-users-flow\}
使用此选项时，只有第一个获得该访问等级的用户画像能永久保留它。如果购买需要绑定到唯一的 <InlineTooltip tooltip="Customer User ID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration) 和 [Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip>，这是最理想的选择。

  <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Disabled_Flow.webp"
  style={{
    border: 'none', /* border width and color */
    width: '700px', /* image width */
    display: 'block', /* for alignment */
    margin: '0 auto' /* center alignment */
  }}
/>