§6 Webhook仕様(イベント一覧)

AppCotton は Stripe決済ライセンス状態 を自動で同期させるために、
Webhook(サーバー間イベント通知) を利用します。

  • 課金が成功 → ライセンスを active に維持 / 再有効化
  • 支払い失敗 → 猶予期間経過後に expired
  • 返金 → revoked(利用権の取り消し)

これにより、管理者が注文を手動で管理する必要はありません。


Webhook 受信エンドポイント

/wp-json/appcotton/v1/stripe/webhook

注意:
このエンドポイントは署名検証を行うため、Stripe 側で Signing Secret を必ず設定してください。


Webhookで処理される Stripe イベント一覧

Stripe Event役割ライセンスへの影響
checkout.session.completed新規購入が完了ライセンス発行 → active
invoice.payment_succeededサブスク更新成功ライセンス期限更新 → active
invoice.payment_failed支払い失敗(リトライ期間)即停止はせず様子を見る
customer.subscription.deletedサブスク終了 / キャンセルexpires_at 到達後に expired
charge.refunded返金発生ライセンス revoked(利用停止)
customer.subscription.updated契約変更(月→年 / 年→月)プラン変更に応じて plan_id も更新
price.updated / product.updatedStripe側の価格変更AppCotton上の価格自動同期(任意)

状態遷移ルール

新規購入(Buy)

checkout.session.completed
↓
ライセンス作成
status = active
expires_at = NULL または 次回請求日

更新(Subscription Renew)

invoice.payment_succeeded
↓
expires_at が +1 期間延長
status = active 維持

支払い失敗(Grace Period あり)

invoice.payment_failed
↓
ユーザーの決済状況を Stripe 側でリトライ
↓
期限が切れたタイミングで
status = expired

返金 / チャージバック

charge.refunded
↓
status = revoked(完全使用停止)

ライセンス更新ロジック(pseudo)

on invoice.payment_succeeded:
    license.status = 'active'
    license.expires_at = next_billing_cycle_date

on invoice.payment_failed:
    // 即停止はしない、expires_at 到達に委ねる

on customer.subscription.deleted:
    // サブスク終了 → 現在の expires_at まで使える
    // expires_at 以降に expired へ遷移

on charge.refunded:
    license.status = 'revoked'

差額アップグレード対応

アップグレードは常に 一回決済(通常 purchase と同じ)として記録されます。

イベントライセンスへの作用
checkout.session.completed(Upgrade)plan_id の更新 / price 差額決済済み

既存ライセンスを再発行するのではなく、同じ license_id のまま plan_id を更新します。


署名検証(セキュリティ)

受信した Webhook は、必ず Stripe が提供する署名チェックで検証されます:

$event = \Stripe\Webhook::constructEvent(
    $payload,
    $sig_header,
    $webhook_secret
);

失敗した場合:

HTTP 400 Bad Request

失敗時のリトライ

Stripe は失敗した Webhook を 自動再送 します:

再送間隔仕組み
最長 72時間バックオフ再試行

→ Webhook が一時的に落ちても ライセンスは整合性を保てる 設計です。


チェックリスト

  • Stripe Dashboard → Webhooks → URL を登録した
  • Signing Secret を AppCotton 設定画面にコピーした
  • 本番環境とテスト環境で Webhook を分離した
  • charge.refunded → revoked が動作することを確認した
  • invoice.payment_succeeded → active 維持が動作することを確認した

まとめ

• Webhookによりライセンス状態は自動同期される
• 購入 → active、更新 → active維持、未払い → expired
• 返金時は revoked(利用権の完全停止)
• 差額アップグレードは checkout.session.completed で plan_id 更新
• Signing Secret による署名検証が必須