使用 Webhook 处理 Adapty 订阅事件

Webhooks 让您的服务器能够实时接收 Adapty 订阅事件——包括购买、续订、取消、账单问题和退款——从而授予访问权限、同步后端或触发工作流。本指南将带您在同一页面上完成从端点配置到验证、测试的完整集成流程,并介绍如何让 AI 编程助手为您的技术栈编写处理程序。

正在使用 AI 编程助手?点击标题下方的 Copy for LLM,将整个页面粘贴到您的助手中——它包含所需的配置说明、数据载荷和处理逻辑。

Adapty Webhook 的工作原理

  • 单向实时推送:当事件发生时,Adapty 会向你的服务器发送 HTTP POST 请求,无需轮询。
  • 两种请求类型:一次性验证请求(在你保存集成时发送)和持续的订阅事件通知。
  • 每个环境独立 URL:你需要分别为生产环境和沙盒环境配置独立的接收端点。
  • 需要应答每个请求:请尽快以 2xx 状态码响应,否则 Adapty 会在失败时重试。

构建你的 Endpoint

创建一个能处理以下两种请求类型的公开 HTTPS Endpoint:

  • 验证请求:在你保存集成时发送一次,请求体为空 JSON({})。请返回 2xx 状态码及 JSON 响应体。
  • 订阅事件:持续发来的 POST 请求,事件内容在请求体中。请在 10 秒内返回 200,然后以异步方式处理耗时操作。 选择一个密钥字符串并将其存储为环境变量(例如 ADAPTY_WEBHOOK_SECRET)。在每次请求时,验证 Authorization 请求头是否与其匹配,若不匹配则拒绝该请求——稍后你将在看板中输入相同的密钥。

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.ADAPTY_WEBHOOK_SECRET;

app.post("/adapty/webhook", (req, res) => {
  // 1. Verify the shared secret Adapty echoes back.
  if (req.get("Authorization") !== WEBHOOK_SECRET) {
    return res.sendStatus(401);
  }

  // 2. Acknowledge fast, then process asynchronously.
  res.status(200).json({});

  // 3. The verification request has an empty body — nothing to handle.
  const event = req.body;
  if (!event.event_type) return;

  switch (event.event_type) {
    case "subscription_started":
    case "subscription_renewed":
    case "trial_converted":
      // Grant or extend access.
      break;
    case "subscription_expired":
    case "subscription_refunded":
      // Revoke access.
      break;
    default:
      break;
  }
});

app.listen(3000);

在配置集成之前,请先将端点部署到公开的 HTTPS URL——Adapty 会在你保存的瞬间发送验证请求。

关键事件及其数据载荷

每个事件共享相同的外层结构。字段内容因事件类型、应用商店及所启用的选项而有所不同。以下是一个精简版的 subscription_started 事件示例:

{
  "profile_id": "00000000-0000-0000-0000-000000000000",
  "customer_user_id": "UserIdInYourSystem",
  "event_type": "subscription_started",
  "event_datetime": "2024-11-15T10:45:36.181000+0000",
  "event_properties": {
    "store": "play_store",
    "currency": "USD",
    "price_usd": 4.99,
    "vendor_product_id": "onemonth_no_trial",
    "transaction_id": "0000000000000000",
    "original_transaction_id": "0000000000000000",
    "subscription_expires_at": "2024-12-15T10:45:36.181000+0000",
    "profile_event_id": "00000000-0000-0000-0000-000000000000"
  },
  "event_api_version": 1
}

最常处理的事件:

事件类型触发时机
subscription_started用户开始付费订阅
subscription_renewed订阅成功续期并完成扣款
subscription_renewal_cancelled用户关闭自动续订(访问权限持续至到期)
subscription_expired订阅未续期到期后访问权限终止
trial_started用户开始免费试用
trial_converted试用转换为付费订阅
billing_issue_detected续订付款失败
subscription_refunded订阅购买被退款
完整的事件列表及每个字段的详细说明,请参阅 Webhook 事件类型与字段

不要按 event_datetime 对事件排序——该字段表示事件的业务发生时间,事件可能乱序到达,也可能具有相同的时间戳。请按自己的接收时间排序,并使用 profile_event_id 或事务 ID 进行去重。

在 Adapty 中配置 Webhook

  1. 在 Adapty 看板中打开 Integrations → Webhook
  2. 开启该集成。
  3. Production endpoint URL 中,输入你部署的端点的 HTTPS URL。
  4. Authorization header value for production endpoint 中,输入与端点校验逻辑相同的密钥。Adapty 会在每次请求时通过 Authorization 请求头将该值回传给你的端点。此项为可选,但强烈建议填写。
  5. 如需先在沙盒环境中测试,同样填写 Sandbox endpoint URL 及其 Authorization header value
  6. 点击 Save。Adapty 会立即向你的端点发送验证请求,端点返回 2xx 响应后即完成配置。 要选择发送哪些事件、映射事件名称,或启用可选字段(试用价格、历史事件、归因、用户属性、Play Store token),请参阅设置 Webhook 集成
Adapty 看板 Webhook 集成设置,包含生产环境 endpoint URL 和 Authorization 请求头值字段

用 AI 编程助手来构建

将本指南和以下参考文档以 Markdown 格式提供给你的 AI 编程助手(在任意页面 URL 后加 .md 即可获取),告诉它你的技术栈,让它自动生成处理程序:

示例提示词:

Read these Adapty webhook docs, then write a webhook handler for my Express app:
verify the Authorization header against ADAPTY_WEBHOOK_SECRET, answer the
verification request, acknowledge events with 200, and grant or revoke access
based on event_type.

代理会编写处理程序代码,但无法部署你的端点或配置看板——请自行托管端点,并在 Integrations → Webhook 中设置 URL 和密钥。

测试您的 Webhook

在正式上线前,请先在沙盒环境中进行测试:

  1. 按照上述说明配置沙盒端点和密钥。
  2. 在沙盒应用中完成购买、开启试用或申请退款,以触发相应事件。
  3. 打开集成页面的 Last sent events 部分。已成功投递的事件会显示 Success 状态。

如果事件显示 Sending failed,说明您的服务器返回了 200–399 范围之外的状态码——将鼠标悬停在状态上可查看详情。完整的测试流程,请参阅测试 Webhook 集成

Webhook 集成最近发送事件列表,显示一个状态为成功的已送达事件

限制

  • 10 秒内响应:如果 Adapty 未能在规定时间内收到响应,会将本次尝试标记为失败并重新发送。
  • 重试机制:如果您返回的状态码不在 200–404 范围内,Adapty 会以指数退避策略进行重试——在 24 小时内最多重试 9 次。
  • 取消延迟:取消事件最多可能延迟 2 小时送达。
  • 每个环境仅支持一个 URL:如需将事件推送至多个服务,请将 Webhook 指向您自己的后端,再由后端进行分发。