[← Docs](/docs/)  |  [Home](/)

# Stripe Webhook Plan Update (v1) — Phase3-1 (minimal)

> ⚠️ **運用者/開発者向け（上級）**  
> この文書は Stripe Webhook の運用・実装メモです。一般の利用者は読む必要はありません。  
> 申込・購入の正面導線は **/subscribe.htm** です。  


## 目的
Stripe Webhook を受け取り、**D1 の `projects.plan` を更新するだけ**を最小で成立させる。
- キー自動発行はまだやらない（Phase3.5）
- plan更新が効いていることを、`proof_bundle_v3.json` で検収できる形にする

## エンドポイント
- `POST /v1/stripe/webhook`

## 必須シークレット（Workers）
- `STRIPE_WEBHOOK_SECRET`（Stripe Dashboard の Webhook signing secret）

設定（例）:
```bash
wrangler secret put STRIPE_WEBHOOK_SECRET --env=""
```

## 受けるイベント（最小3つ）
- `checkout.session.completed`
- `customer.subscription.updated`
- `customer.subscription.deleted`

## 重要：metadata を前提にする（最小の事故防止）
本Phaseでは **Stripeオブジェクトに metadata を付ける**前提にします。
Webhookは次を探します：

- `metadata.project_id`（必須）
- `metadata.plan`（checkout.completed / subscription.updated で必須）
  - plan値の推奨：`free` / `basic` / `team`

例（Checkout Session / Subscription どちらにも）:
```json
{
  "metadata": {
    "project_id": "p_free",
    "plan": "basic"
  }
}
```

`customer.subscription.deleted` は `plan=free` に落とします（metadata.plan不要）。

## 凍結ルール（Phase3-1 次の事故防止）
- Webhookは **原則 200** を返して Stripe の再送地獄を避ける（**署名不一致だけ 400** / fail-close）
- plan更新は **metadata 前提**（`project_id/plan` が無いイベントは ignore）


## 動作
- 署名検証（Stripe-Signature + HMAC-SHA256）
- timestamp tolerance（既定 300s）
- KV で event.id を 24h デデュープ（同一イベントの再送対策）
- `projects` へ plan を upsert（行が無ければ作る）

## 検収（RunProof側）
1) webhook を1回通す（plan更新）
2) `.\scripts\proof_bundle_v3.ps1` を実行
3) `out\proof_bundle_v3.json` の `d1.projects.parsed` で `plan` が更新されていることを確認

## 失敗時の原則
- 署名不一致 → 400（fail-close）
- `project_id` が無い → 200 で ignore（Stripe再送地獄を避ける）
- 未対応イベント → 200 で ignore



## Stripe側 最小チェックリスト（テストモード限定）

Phase3-1 を「外部と接続して検収可能」にするために、Stripe側で最低限これだけ行います（スクショ無しで迷子にならない版）。

1. Stripeダッシュボードの新規登録 → ログイン（メール認証まで）
2. 2段階認証(2FA)をON（最初にやる。権限が強いので事故防止）
3. Webhookエンドポイントを作成（テストモード）
   - Dashboard: 開発者 → Webhooks →「エンドポイントを追加」
   - URL: `https://<your-worker-base>/v1/stripe/webhook`
   - 送るイベント（最小）：`checkout.session.completed` / `customer.subscription.updated` / `customer.subscription.deleted`
4. 表示される Signing secret（`whsec_...`）を Workers に設定
   - `wrangler secret put STRIPE_WEBHOOK_SECRET --env=""` で上書き
5. テスト送信（Dashboard の「テストイベントを送信」 または stripe-cli）
   - `checkout.session.completed` の object に `metadata.project_id` と `metadata.plan` を付けて送る
6. 送信後に RunProof 側で証拠化
   - `.\scripts\proof_bundle_v3.ps1`
   - `out\proof_bundle_v3.json` の `d1.projects` で `plan` が更新されていれば検収完了
