Stripeのダッシュボードを見ると「成功」になっている。決済は通っている。でも管理表のスプレッドシートは何も変わっていない。
この状態を2回経験しました。原因は毎回違いました。
1回目の詰まり: 署名検証の壁
最初の相談はこういう書き出しでした。
このコードを見てほしい STRIPEで購入手続きをすると、実際に購入できるのだが、スプシに情報が反映されない。スプシIDや、スプシ列などの情報は正しく、シークレット情報が正しいとすると原因はなにか
スプレッドシートのIDも列の番号も合ってる。シークレットキーも正しい。なのに動かない。こういうケースは大抵、「見えないところで弾かれている」ことが多いです。
確認すると、Webhookの署名検証(注:決済サービスからの通知が本物かどうか確かめる処理)の段階で止まっていました。Stripeは通知を送るとき、ヘッダーに署名情報を付けてきます。それを受け取り側で照合しないと処理を進めない設計になっていた。
問題は、GAS(Googleのスクリプト実行環境)がこのヘッダーを取れない仕様だったことです。
あー、そういうことで でもGASってヘッダー取れない仕様だよ
これを知らずに「署名を取ってきて照合する」コードを書いても、そもそも署名情報が届かないので永遠に失敗します。ヘッダーが取れないなら署名検証ができない。署名検証ができないならStripe公式の検証フローはGASでは使えない。
対処として、署名検証を諦めてイベントID方式に切り替えました。通知が届いたらStripe側にイベントIDを使って問い合わせ、そのイベントが本物か確かめる。GASがヘッダーを取れなくても、APIを叩いて確認すればいい。
ただし今度は302(注:リダイレクトを意味するHTTPステータスコード)ループという別の問題が出てきました。
302 署名が確認できない?
GASへのPOSTリクエストはデフォルトでリダイレクトが発生します。StripeはGASのエンドポイントに通知を送ると302が返ってくる。Stripeはエラーとみなして何度も再送する。それが積み重なって「過去の購入メッセージを何度も受信してしまう」状態になっていました。
あれー まだだめだわ STRIPEイベント発生させたら過去の購入メッセージ受信しちゃったよ
これは送信側(Stripe)の挙動に依存している問題で、GASの受け取り側だけ直しても解消しません。Qiitaの記事でその構造をオーナー自身が確認して、この件は「GASへのLINE通知を止める」という判断に切り替えました。複数回送られると困るので、その処理自体を省いたほうが安全、という判断です。
2回目の詰まり: 列のズレ
しばらく後、別のサブスク管理システムで同じ症状が出ました。
このコードで、スプシが更新されない stripeでは購入完了するのに Stirpeではエラーはでていない GASでエラーがでる
1回目と似ていますが、今回はStripe側にエラーがない。GAS側でエラーが出ている。ならWebhookの受け取りは動いていて、スプレッドシートへの書き込みで失敗している可能性が高い。
そこで「スプシはこういう構成になっているが、問題ない?」と実際のシート構成をコードと突き合わせてもらいました。すると列のインデックスがずれていました。
コードの中でメールアドレスを何列目に書く、プランIDを何列目に書く、という指定が実際のシートの並びと一致していなかった。コードが想定している列番号と、実際のシートで値が入っている列番号がひとつぶんずれている、といった状態です。
きたきた いけたわ なんでできるようになった?
解消の瞬間がこれです。原因は列の指定ミスでした。
この種のズレは、シートを後から作り直したり、列を追加したときに起きやすい。コードとシートの対応は視覚的に見えないので、「シートIDは合ってるし」で終わりにしがちです。でも列の番号がひとつずれているだけで、書き込みは静かに失敗します。エラーが出ないこともあります。
2つの原因の見分け方
整理すると、「決済は通るのにスプシが動かない」のパターンは大きく2種類あります。
Stripeでエラーが出ている
→ Webhook受け取り側の問題(署名検証・302ループ等)
Stripeではエラーなし、GASでエラーが出ている
→ スプシへの書き込み処理の問題(列指定ズレ等)
どちらも症状は同じ「スプシが動かない」なので、まずどちらのエラーなのかを確認するのが先です。Stripeのダッシュボードでイベントのステータスを見れば、受け取り側がちゃんと応答しているかどうかは分かります。
GASは「Webhookの署名検証ができない」「302を返す」という癖があります。便利な実行環境ですが、Stripeと組み合わせるときはこの2点だけ最初に知っておくと詰まらずに済みます。
実際にAIへ頼むとしたら、こんな順番で渡すのが結果として早かったです。
まず、Stripeダッシュボードでイベントのステータスを確認してください。エラーが出ているなら「Webhookが届いていない/弾かれている」側の問題。エラーがなくGASのログだけにエラーが出るなら「スプシへの書き込み」側の問題。切り分けてから修正方針を決めましょう。
症状が同じでも、原因が違えば直すべき場所も変わります。GASとStripeを繋ぐ系の話は、特にこの切り分けを先にやるのが結局早いと思っています。
AIへの渡し方
自分でコードを書いたわけではなく、現象をそのまま渡してコードを直してもらう進め方をしました。
このコードを見てほしい STRIPEで購入手続きをすると、実際に購入できるのだが、スプシに情報が反映されない
専門用語は要らない。原因の見当をつけてから渡す必要もない。でも、環境の前提は最初に共有しておいたほうがいいです。
「GASでStripeのWebhookを受け取るときはヘッダーが取れない」を知らずにコードだけ渡すと、署名検証ありきの修正を繰り返すことになります。実際そうなりました。仕様の制限を伝えた後は、それを前提にした設計に切り替えてもらえて、そこから先は早かった。
ピント外れの提案が続くときは、大抵「環境の制限を渡せていない」か「どちら側のエラーか切り分けていない」どちらかです。
