← 所有文章
教程

LINE MINI App 支付 Webhook 漏单恢复:7 天对账 Runbook

恢复遗漏的 LINE MINI App 支付 Webhook,应在 7 天内查询 LINE 官方事件历史,分页时保持原始时间范围和筛选条件不变,再把每个 purchaseComplete 事件交给以 orderId 为幂等键的同一套处理逻辑。购买预留成功不代表支付完成;事件历史是故障恢复来源,不能替代实时 Webhook 监控。

核心结论

  • LINE 的事件历史可查询过去 7 天的 Webhook 投递,每页最多返回 100 条记录。
  • status=FAILED 表示 Webhook 投递失败,不表示用户支付失败。
  • 预留购买时就保存 orderId,实时和恢复得到的 purchaseComplete 都用它去重。
  • 支付恢复与客服消息路由应保持分离:两者的事件、凭据、签名协议和责任人都不同。

为什么预留成功不等于购买完成

LINE MINI App 应用内购买是一个多步骤的官方流程。服务端先调用 POST https://api.line.me/iap/v1/product/reserve 预留购买,LINE 返回 orderId。但用户仍可能关闭应用、在应用商店取消支付、断网,或者没有走完整个付款流程。因此,LINE 的集成指南明确要求:只有收到购买完成 Webhook 后,才能发放数字内容或权益。

这条边界把故障判断拆成四个问题:

问题应信任的证据
预留请求是否成功?reserve 响应、保存的 orderIdx-line-request-id
购买是否真正完成?purchaseComplete 事件或官方对账结果
实时投递是否到达你的端点?原始请求日志和 Webhook 处理记录
业务系统是否只发放一次权益?orderId 为键的幂等记录

已有的 LINE MINI App 费用与客服 Webhook 指南解释了为什么支付事件和客户消息应属于两套系统。本文从更深一层的故障场景开始:支付 Webhook 本应到达,但端点宕机或应用处理失败了。

如何恢复遗漏的 LINE MINI App 支付 Webhook

1. 在 7 天窗口关闭前发现缺口

预留购买时至少保存:

  • 内部 checkout ID;
  • LINE 返回的 orderId
  • 响应头 x-line-request-id
  • 预留时间和预期商品;
  • purchaseComplete 是否已经应用。

如果一条预留记录超过正常结账时长仍未结束,应立即告警。不要直接把它标成已支付,也不要等到第 7 天才调查;官方历史接口只接受过去 7 天内的时间范围。

2. 查询固定的恢复窗口

LINE 官方 MINI App API Reference 给出的恢复接口是:

curl --get "https://api.line.me/iap/v1/webhook/events" \
  -H "Authorization: Bearer ${LINE_CHANNEL_ACCESS_TOKEN}" \
  --data-urlencode "startEpochSeconds=1784678400" \
  --data-urlencode "endEpochSeconds=1784700000" \
  --data-urlencode "pageSize=100" \
  --data-urlencode "status=FAILED"

上面的时间戳只是 2026 年 7 月 22 日的一段示例窗口,不能直接用于生产。请根据事故的 UTC 起止时间生成 epoch 秒。用 status=FAILED 查询 LINE 未能完成的投递;如果要核对窗口内的所有记录,则省略 statusSUCCESSFAILED 描述的是投递状态,不是支付结果。

3. 分页时保持查询条件不变

结果按 LINE 开始发送 Webhook 的时间升序排列。每页最多 100 条,响应可能包含 nextCursor。查询后续页面时,应保持 startEpochSecondsendEpochSecondspageSizestatus 不变,只修改 cursor

下面的 Node.js 示例把这条边界写进了代码:

const baseUrl = "https://api.line.me/iap/v1/webhook/events";
const fixedQuery = {
  startEpochSeconds: "1784678400",
  endEpochSeconds: "1784700000",
  pageSize: "100",
  status: "FAILED",
};

let cursor;

do {
  const query = new URLSearchParams(fixedQuery);
  if (cursor) query.set("cursor", cursor);

  const response = await fetch(`${baseUrl}?${query}`, {
    headers: { Authorization: `Bearer ${process.env.LINE_CHANNEL_ACCESS_TOKEN}` },
  });

  if (!response.ok) {
    throw new Error(`LINE event history failed: ${response.status}`);
  }

  const page = await response.json();
  for (const record of page.events) {
    if (record.event.type === "purchaseComplete") {
      await applyPurchaseOnce(record.event.orderId, record.event);
    }
  }

  cursor = page.nextCursor ?? undefined;
} while (cursor);

applyPurchaseOnce 是业务事务边界:它应在同一个原子操作中插入幂等记录并发放权益;如果该 orderId 已处理,就什么也不做。LINE 的应用内购买开发指南也明确建议用 orderId 防止重复发放,因为同一个 Webhook 可能被投递多次。

4. 用同一套处理逻辑核对实时与历史事件

不要为恢复任务再写一套权益发放逻辑。把恢复得到的事件转换成实时 Webhook 使用的同一个内部命令,只额外记录来源为 line_event_history。然后逐项比对:

  1. 已预留但内部状态未完成的 orderId
  2. 实时 Webhook 日志;
  3. 固定事故窗口内的历史记录;
  4. 幂等记录和权益变更。

事件历史通过 channel access token 查询,它不是原始 HTTP 投递,因此不要期待历史响应包含原来的 x-line-signature。实时 Webhook 仍必须校验该请求头:LINE 使用 channel secret 对原始请求体计算 HMAC-SHA256,再以 Base64 编码签名。

5. 用可审计的检查点结束事故

只有当范围内的每条预留记录都被归类为“完成且已发放”“未完成”“已取消”或“转人工调查”,恢复才算结束。保存本次 UTC 范围、筛选条件、总页数、恢复的 orderId 列表和最后成功时间。把轻量对账任务安排在 7 天保留期限之内,避免周末故障过期后无法查询。

当前事件历史文档说明该接口查询 purchaseComplete 事件,退款历史支持将单独提供。不要假设同一恢复路径已经覆盖退款;实施前应再次核对实时 Reference。

UnifyPort 适合处理什么、不处理什么

UnifyPort 不负责预留 LINE MINI App 购买、确认应用商店支付、恢复 LINE 支付事件、发放数字权益,也不能替代 LINE 的审核要求。这些任务应始终由 LINE 官方应用内购买流程负责。

UnifyPort 适合承接支付之后的普通客户消息。例如,买家付款后发现权益未到账,随后通过 LINE 咨询;已支持的 LINE 账号可以把该对话作为标准化的 message.received 事件送入客服系统。如果 UnifyPort Webhook 端点配置了 signing_secret,投递会使用 X-Device-TimestampX-Device-Signature;它与 LINE 支付 Webhook 的 x-line-signature 是两套不同的签名协议。

如果要深入处理客服消息侧的重试和幂等,请阅读 Webhook HMAC 重放防护、重试与幂等指南。即使两种事件最终都会更新同一订单或客服系统,也应保持两个 handler 分离。

限制与取舍

  • LINE 官方历史 API 是恢复 MINI App 支付 Webhook 的正确路径;非官方接口不能延长其保留时间,也不能找回平台支付记录。
  • 7 天回溯不是长期账本。应自行持久化预留、事件、权益和结算记录。
  • status=FAILED 能定位投递失败,却可能漏掉“端点已接收、应用处理失败”的事件。故障发生在应用层时,应执行不带状态筛选的完整对账。
  • 应用内购买仍是面向日本、需要审核的 MINI App 能力。设计支付流程前先确认最新资格;已认证与未认证 MINI App 检查表覆盖了更前面的决策。

常见问题

LINE MINI App 支付 Webhook 历史能查询多久?

官方接口只接受过去 7 天内的 Webhook 历史。请在期限内完成恢复,并用自己的持久化账本处理更早的事故。

status=FAILED 是否表示用户支付失败?

不是。它表示 LINE 的 Webhook 投递失败。支付状态与投递状态不同,需要结合返回事件、预留记录和权益记录完成对账。

reserve 接口返回 200 后可以发放权益吗?

不可以。预留成功不保证购买完成。只有处理 purchaseComplete 事件后才能发放,并用 orderId 保证幂等。

历史恢复会不会把同一笔购买处理两次?

查询可能返回已经被实时 handler 处理过的事件。让两条路径调用同一个以 orderId 为键的原子幂等 handler,第二次尝试就会成为无操作。

LINE 的 x-line-signature 和 UnifyPort Webhook 签名一样吗?

不一样。LINE 对支付 Webhook 原始请求体签名并发送 Base64 签名;UnifyPort 在启用 signing_secret 后,对时间戳与原始请求体签名,并发送自己的时间戳和签名请求头。两种协议必须分别校验。

下一步

先按照官方 LINE MINI App API Reference实现并测试恢复查询,再把任务安排在 7 天保留窗口内。如果你的另一项需求是接收普通 LINE 客服消息,请在支付路径稳定后使用 UnifyPort LINE 授权指南接入独立的消息路径。

官方来源

官方事实核验日期:2026 年 7 月 22 日。