← 全記事
チュートリアル

取りこぼしたLINE MINI App購入Webhookを復旧する:7日間の照合Runbook

日本向けLINE MINI Appで取りこぼした購入Webhookを復旧するには、7日以内にLINE公式のイベント履歴を照会し、最初に指定した時間範囲とフィルターを変えずにページを取得し、返された各purchaseCompleteイベントをorderIdをキーとする冪等なハンドラーで再処理します。購入予約の成功は決済完了の証明ではありません。また、履歴エンドポイントは障害復旧のための情報源であり、リアルタイムWebhookの監視を止めてよい理由にはなりません。

要点

  • LINEのイベント履歴では、過去7日間のWebhook配信を確認でき、1ページあたり最大100件が返されます。
  • status=FAILEDはWebhookの配信失敗を示すものであり、購入者の決済失敗を意味しません。
  • 購入予約時にorderIdを記録し、リアルタイムと履歴から取得した両方のpurchaseCompleteイベントを同じキーで重複排除します。
  • 決済復旧と顧客メッセージのルーティングは分離してください。イベント種別、認証情報、署名方式、運用責任者が異なります。

購入予約の成功が購入完了を意味しない理由

LINE MINI Appのアプリ内購入は、複数の段階からなる公式フローです。まずサーバーがPOST https://api.line.me/iap/v1/product/reserveで購入を予約すると、LINEからorderIdが返されます。しかし、その後もユーザーがアプリを閉じる、アプリストアでキャンセルする、通信が切れる、決済を最後まで完了しない、といった可能性があります。このためLINEの実装ガイドでは、購入完了Webhookを受信してからデジタルアイテムを付与するよう求めています。

この境界により、障害時に確認すべき事項は4つに分かれます。

確認事項信頼すべき証跡
購入予約リクエストは成功したかreserveレスポンス、保存済みのorderIdx-line-request-id
購入は完了したかpurchaseCompleteイベントまたは公式の照合結果
エンドポイントはリアルタイム配信を受信したか生のリクエストログとWebhook処理記録
ビジネスハンドラーは権利を一度だけ付与したかorderIdをキーとする冪等性レコード

既存のLINE MINI Appの手数料とサポートWebhookのガイドでは、決済イベントと顧客メッセージを別システムとして扱うべき理由を説明しています。このRunbookが扱うのは、さらに一段深い障害です。つまり、決済Webhookは送られたはずなのに、エンドポイントが利用できなかった、またはアプリケーション内の処理が失敗したケースです。

取りこぼしたLINE MINI App購入Webhookを7日以内に復旧する方法

1. 7日間の期限を過ぎる前に欠落を検知する

購入予約時に、少なくとも次の値を保存してください。

  • 自社のチェックアウトID
  • LINEのorderId
  • レスポンスヘッダーのx-line-request-id
  • 予約時刻と対象商品
  • purchaseCompleteイベントが適用済みかどうか

購入予約が通常のチェックアウト所要時間を超えても未解決なら、アラートを発生させます。すぐに支払済みと判断してはいけません。また、調査を7日目まで待たないでください。公式の履歴エンドポイントが受け付けるのは、直近7日以内の時間範囲だけです。

2. 固定した復旧対象期間を照会する

LINE公式のMINI App APIリファレンスには、次の復旧用エンドポイントが記載されています。

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"

上記のtimestampは2026年7月22日の明示的なサンプル期間であり、本番環境へそのままコピーする値ではありません。障害の開始・終了時刻からUTCのepoch秒を生成してください。LINEが配信を完了できなかったイベントを探す場合はstatus=FAILEDを使います。対象期間の全配信を照合する場合はstatusを省略します。SUCCESSFAILEDが表すのは配信状態であり、決済結果ではありません。

3. ページネーション中は検索条件を固定する

結果は、LINEが各Webhookの送信を開始した時刻順に並びます。1ページは最大100件で、nextCursorが含まれる場合があります。2ページ目以降も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がすでに適用済みなら何もしない設計にします。同じWebhookが複数回配信される可能性があるため、LINEのアプリ内購入開発ガイドラインでも、重複付与を防ぐためにorderIdを使うよう明示的に推奨しています。

4. 履歴とリアルタイム処理を照合する

復旧専用の権利付与経路を新たに作らないでください。履歴から取得したイベントを、リアルタイムWebhookと同じ内部コマンドへ変換し、取得元だけをline_event_historyとして記録します。そのうえで、次の情報を比較します。

  1. 購入予約済みで、内部状態が未完了のorderId
  2. リアルタイムWebhookのログ
  3. 固定した障害対象期間の履歴レコード
  4. 冪等性レコードと権利の変更履歴

イベント履歴のレスポンスはチャネルアクセストークンで取得します。これは元のHTTP配信そのものではないため、元のx-line-signatureヘッダーが含まれると想定してはいけません。リアルタイムWebhookでは、このヘッダーの検証を継続してください。LINEはチャネルシークレットを使って生のリクエストボディのHMAC-SHA256ダイジェストを計算し、Base64形式で送信します。

5. 測定可能なチェックポイントで障害対応を完了する

対象となるすべての購入予約を「完了・適用済み」「未完了」「キャンセル済み」「手動調査へエスカレーション」のいずれかに分類できた時点で、復旧は完了です。正確なUTC範囲、フィルター、ページ数、復旧したorderId、最後に成功した実行時刻を記録します。週末の障害が気付かないうちに保持期限を超えないよう、7日間の保持期限よりも短い間隔で軽量な照合ジョブを実行してください。

現在のイベント履歴ドキュメントでは、このエンドポイントが取得するのはpurchaseCompleteイベントであり、返金履歴は別途対応予定とされています。同じ復旧経路で返金まで扱えると判断する前に、最新のリファレンスを確認してください。

UnifyPortが担う範囲と担わない範囲

UnifyPortは、LINE MINI App購入の予約、アプリストア決済の確認、LINE決済イベントの復旧、デジタルアイテムの付与、LINEの審査要件への対応を行いません。これらはすべてLINE公式のアプリ内購入フローが担うべき処理です。

UnifyPortが適するのは、その次に通常の顧客メッセージが発生する場面です。たとえば、購入後もアイテムが表示されず、購入者が問い合わせるケースです。対応するLINEアカウントでは、その会話を正規化されたmessage.receivedイベントとして配信できます。UnifyPortのWebhookエンドポイントにsigning_secretが設定されている場合、配信ではX-Device-TimestampX-Device-Signatureを使用します。これはLINEの決済Webhookにおけるx-line-signatureとは別の署名方式です。

顧客メッセージ側の再試行と冪等性をさらに詳しく確認するには、Webhook HMACのリプレイ防止:タイムスタンプ、再試行、冪等性を参照してください。最終的に同じサポートシステムや注文システムを更新する場合でも、2つのハンドラーは分離します。

制約とトレードオフ

  • LINE公式の履歴APIが、MINI App購入Webhookを復旧する正規の手段です。非公式なインターフェースで保持期間を延長したり、プラットフォームの決済記録を復元したりすることはできません。
  • 7日間の遡及期間は長期保存用の台帳ではありません。購入予約、イベント、権利、精算の各記録は自社でも保持してください。
  • status=FAILEDは配信失敗を絞り込めますが、エンドポイントが受理した後にアプリケーション処理が失敗した配信は見落とす可能性があります。配信経路ではなくアプリケーションが障害点だった場合は、より広い範囲で照合してください。
  • アプリ内購入は現在も日本向けで、審査が必要なMINI Appの機能です。決済フローを設計する前に、最新の利用資格を確認してください。先行する判断については、認証済み/未認証MINI Appのチェックリストで説明しています。

FAQ

LINE MINI App購入Webhookの履歴は何日間取得できますか?

公式エンドポイントで取得できるWebhook履歴は過去7日間です。この期限を過ぎる前に復旧を実行し、それより古い障害に備えて自社の永続的な台帳を保持してください。

status=FAILEDは購入者の決済失敗を意味しますか?

いいえ。これはLINEによるWebhook配信が失敗したことを意味します。購入状態と配信状態は別です。返されたイベントに購入予約と権利付与の記録を組み合わせて注文を照合してください。

購入予約エンドポイントが200を返したらアイテムを付与できますか?

できません。購入予約の成功は購入完了を保証しません。purchaseCompleteイベントを処理した後にのみアイテムを付与し、orderIdで冪等性を確保してください。

履歴から復旧すると同じ購入を二重処理する可能性はありますか?

照会結果には、リアルタイムハンドラーがすでに適用したイベントが含まれる可能性があります。どちらの経路もorderIdをキーとする同じ原子的で冪等なハンドラーを呼び出すようにすれば、2回目の処理は何も変更しません。

LINEのx-line-signatureとUnifyPortのWebhook署名は同じですか?

いいえ。LINEは決済Webhookの生のリクエストボディに署名し、Base64形式の署名を送信します。UnifyPortはsigning_secretが有効な場合、タイムスタンプと生のリクエストボディに署名し、専用のタイムスタンプヘッダーと署名ヘッダーを送信します。それぞれのプロトコルを個別に検証してください。

次のステップ

LINE公式のMINI App APIリファレンスに沿って復旧クエリを実装・テストし、7日間の保持期間内に実行するようスケジュールしてください。通常のLINEサポートメッセージを受信するという別の要件がある場合は、決済経路が安定してからUnifyPort LINE認証ガイドに沿って接続してください。

公式情報源

公式情報は2026年7月22日に確認しました。