:三步跑通 Stripe 訂閱付費與 Webhook 回調(diào))
open-saas 支付接入實戰(zhàn)三步跑通 Stripe 訂閱付費與 Webhook 回調(diào)【免費下載鏈接】open-saasA 100% free modern JS SaaS boilerplate (React, NodeJS, Prisma). Full-featured: Auth (email, google, github, slack, MS), Email sending, Background jobs, Landing page, Payments (Stripe, Polar.sh), Shadcn UI, S3 file upload. AI-ready with tailored AGENTS.md, skills, and Claude Code plugin. One cmd deploy. Powered by Wasp full-stack framework.項目地址: https://gitcode.com/GitHub_Trending/op/open-saas假設(shè)你的 SaaS 產(chǎn)品已經(jīng)做完現(xiàn)在要加上訂閱付費還希望用戶能上傳文件——但不想從零寫支付流程、簽名校驗和訂閱狀態(tài)流轉(zhuǎn)。open-saasReact Node.js Prisma 的免費 SaaS 模板已經(jīng)把這些都實現(xiàn)了。讀完這篇你會知道付費模塊該看哪幾個文件、Stripe 的 Key 填在哪、回調(diào)怎么接才能自動更新訂閱狀態(tài)、前端的購買按鈕到底是怎么調(diào)通后端的。? 架構(gòu)全景一次購買請求怎么走一圈先建立地圖前端只發(fā)買哪個計劃這一個參數(shù)后端 operations.ts 先做登錄態(tài)和參數(shù)校驗再把活兒交給 Stripe 處理器創(chuàng)建結(jié)賬會話并返回支付 URL用戶付完款Stripe 會異步回調(diào)/payments-webhook后端驗簽后把訂閱狀態(tài)寫回數(shù)據(jù)庫。整個流程不經(jīng)過任何輪詢支付結(jié)果的臟活。分層文件職責前端頁面payment/PricingPage.tsx渲染定價卡片、觸發(fā)購買、打開客戶門戶路由與操作注冊payment/payment.wasp.ts掛載 /pricing、/checkout 頁面和 webhook業(yè)務邏輯payment/operations.ts401/403 權(quán)限校驗 Zod 參數(shù)校驗計劃定義payment/plans.tsHobby、Pro、Credits10 三個計劃及其效果Stripe 實現(xiàn)payment/stripe/結(jié)賬創(chuàng)建、計費門戶、回調(diào)處理回調(diào)入口payment/webhook.ts把請求轉(zhuǎn)發(fā)給當前處理器的 webhook關(guān)鍵設(shè)計是 paymentProcessor.ts 里的接口抽象Stripe、Lemon Squeezy、Polar.sh 三家實現(xiàn)了同一套接口換支付渠道只改一行export const paymentProcessor: PaymentProcessor stripePaymentProcessor; // export const paymentProcessor: PaymentProcessor lemonSqueezyPaymentProcessor; // export const paymentProcessor: PaymentProcessor polarPaymentProcessor;? 動手路線后端填環(huán)境變量讀三個關(guān)鍵文件先打開 payment/plans.ts它定義了三個計劃Hobby 和 Pro 是訂閱subscription 效果Credits10 是一次性積分充值credits 效果。你要增刪計劃就改這里的枚舉和 paymentPlans 對象再走一遍完整流程驗證。再打開 .env把付費相關(guān)的環(huán)境變量填齊全部有 Zod 校驗缺一個應用直接起不來PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_IDprice_1xxx PAYMENTS_PRO_SUBSCRIPTION_PLAN_IDprice_1yyy PAYMENTS_CREDITS_10_PLAN_IDprice_1zzz STRIPE_API_KEYsk_test_xxx STRIPE_WEBHOOK_SECRETwhsec_xxx前三個是 Stripe 控制臺的 Price ID后兩個分別是密鑰和 webhook 簽名密鑰。自測方法啟動應用用測試賬號登錄后調(diào)用 getCustomerPortalUrl 操作未付過款的用戶應返回 null 而不是報錯。前端購買按鈕怎么接不用自己包 API 請求Wasp 會根據(jù) payment.wasp.ts 里注冊的 operations 自動生成類型安全的客戶端前端不寫 fetch。PricingPage.tsx 里立即購買的核心邏輯就三步const checkoutSession await generateCheckoutSession(paymentPlanId); if (checkoutSession?.sessionUrl) { window.open(checkoutSession.sessionUrl, _self); }管理訂閱按鈕則用useQuery(getCustomerPortalUrl)拿門戶地址且設(shè)了enabled: isUserSubscribed只有已訂閱用戶才發(fā)請求。你通常只需要改paymentPlanCards里的價格和功能文案請求邏輯一行都不用動。聯(lián)調(diào)本地把回調(diào)閉環(huán)跑通回調(diào)是最容易漏的一環(huán)。開一個終端跑 Stripe 本地轉(zhuǎn)發(fā)stripe listen --forward-to localhost:3000/payments-webhook把終端打印的 whsec_ 開頭的簽名密鑰復制進 STRIPE_WEBHOOK_SECRET。注意 webhook.ts 用express.raw解析原始請求體——Stripe 驗簽必須基于原始字節(jié)換成 JSON 解析驗簽必掛。驗簽通過后按事件分發(fā)switch (event.type) { case invoice.paid: /* 寫訂閱狀態(tài)或加積分 */ break; case customer.subscription.updated: /* 狀態(tài)流轉(zhuǎn)取消時發(fā)挽留郵件 */ break; case customer.subscription.deleted: /* 標記為 deleted */ break; }聯(lián)調(diào)流程打開定價頁 → 立即購買 → 用測試卡 4242 4242 4242 4242 付款 → 回到 /checkout 成功頁 → 查數(shù)據(jù)庫subscriptionStatus 應為 active。最后去計費門戶取消訂閱觀察狀態(tài)變?yōu)?cancel_at_period_end并確認收到挽留郵件。?? 踩坑清單現(xiàn)象webhook 一直 400報簽名驗證失敗。原因把 STRIPE_API_KEY 的值填進了 STRIPE_WEBHOOK_SECRET兩者不是一回事。改法webhook secret 必須是 whsec_ 開頭的簽名密鑰本地用stripe listen打印的那個。現(xiàn)象付款成功但用戶 subscriptionStatus 沒變。原因Stripe 控制臺給 webhook 勾選的事件太多后端遇到?jīng)]處理的事件會拋 UnhandledWebhookEventError而你要的事件被淹沒在日志里。改法控制臺只勾選上面那 3 個事件然后盯后端日志確認事件真的到了。現(xiàn)象一次性積分購買沒有任何回調(diào)觸發(fā)。原因Stripe 只對訂閱自動生成 invoice.paid一次性支付必須顯式開啟 invoice 創(chuàng)建。改法stripe/checkoutUtils.ts 已對 payment 模式啟用invoice_creation你照抄這份文件時別把這行刪掉。現(xiàn)象調(diào)購買接口返回 403 User needs an email to make a payment。原因你的認證方式是 usernameAndPassword拿不到郵箱而 Stripe 建客戶必須用郵箱。改法換成帶郵箱的認證方式如郵箱密碼或 OAuth。現(xiàn)象換 Lemon Squeezy 后支付報Unknown payment processor plan ID。原因paymentProcessorPlans.ts 用環(huán)境變量把內(nèi)部計劃映射到渠道側(cè)的計劃 ID換渠道后這三個值沒換。改法把三個 PAYMENTS_*_PLAN_ID 重填為新渠道的 ID。? 驗收清單付費環(huán)境變量全部填齊三個 PLAN_ID 與 Stripe 控制臺 Price ID 一致webhook 只配置 3 個事件本地觸發(fā)后日志無 Unhandled 報錯測試卡購買后用戶 subscriptionStatus 變?yōu)?active管理后臺能看到收入計費門戶取消訂閱后狀態(tài)變?yōu)?cancel_at_period_end并收到挽留郵件一次性積分計劃購買后用戶積分余額正確增加未登錄調(diào)購買接口返回 401非管理員調(diào)用戶管理接口返回 403文件上傳白名單 ALLOWED_FILE_TYPES 已改成你業(yè)務需要的類型S3 桶已建好下一步打開 template/blog 的 docs/guides 目錄讀支付集成章節(jié)逐項核對你的環(huán)境變量然后在 template/app 目錄跑npm run dev把購買 → 回調(diào) → 取消完整閉環(huán)走一遍跑通后就可以基于 subscriptionStatus 字段寫你自己的付費功能門控邏輯了。【免費下載鏈接】open-saasA 100% free modern JS SaaS boilerplate (React, NodeJS, Prisma). Full-featured: Auth (email, google, github, slack, MS), Email sending, Background jobs, Landing page, Payments (Stripe, Polar.sh), Shadcn UI, S3 file upload. AI-ready with tailored AGENTS.md, skills, and Claude Code plugin. One cmd deploy. Powered by Wasp full-stack framework.項目地址: https://gitcode.com/GitHub_Trending/op/open-saas創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考