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.updated | Stripe側の価格変更 | 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 による署名検証が必須