Stripe Connect là một hệ sinh thái webhook khác với Stripe thông thường. Toán chữ ký giống nhau. Mọi thứ khác đều khác. Nếu bạn đang truy tìm vì sao handler Connect của mình âm thầm bỏ qua account.application.deauthorized, bài này dành cho bạn.
Connect thay đổi sự kiện bạn nhận
Webhook Stripe thông thường đến từ tài khoản nền tảng của bạn: charges, customers, subscriptions. Webhook Connect đến từ các tài khoản kết nối và từ các sự kiện vòng đời đặc thù Connect trên nền tảng của bạn. Danh sách trùng lặp nhiều nhưng gồm các sự kiện bạn chỉ thấy khi bật Connect:
account.updated— trạng thái xác minh, capabilities, yêu cầuaccount.application.deauthorized— tài khoản kết nối thu hồi quyền truy cập của bạncapability.updated— trạng thái kích hoạt payouts/transfersperson.created,person.updated— cho tài khoản Custom và Expresspayout.failed,payout.paid— trên tài khoản kết nối, không phải nền tảng của bạn
Hầu hết đội phát hiện điều này sau khi deploy. Kiểm thử cục bộ thì phơi bày vấn đề trong vài phút.
Header Stripe-Account thay đổi mọi thứ
Khi một sự kiện xảy ra trên tài khoản kết nối, Stripe đính kèm header Stripe-Account với ID của tài khoản kết nối (acct_xxx). Handler của bạn cần định tuyến theo header đó, không theo những gì bên trong payload.
const connectedAccountId = req.headers['stripe-account'];
const event = stripe.webhooks.constructEvent(
rawBody,
req.headers['stripe-signature'],
endpointSecret,
);
// Now process the event in the context of connectedAccountId
await handleConnectEvent(event, connectedAccountId);
Nếu bạn quên đọc header, handler coi mọi sự kiện Connect như thể nó xảy ra trên nền tảng của bạn. Bug từ mẫu này thường hiện ra dưới dạng "payout hiển thị cho sai merchant".
Kiểm thử Connect cục bộ với PortPreview
Thiết lập giống kiểm thử Stripe thông thường cục bộ, cộng một bước thêm:
- Chạy app nền tảng cục bộ.
- Khởi động một tunnel:
npx portpreview 3000. - Trong dashboard Stripe, thêm URL tunnel làm endpoint webhook và tick tùy chọn Events on Connected accounts. Đó là công tắc thay đổi toàn bộ luồng sự kiện.
- Dùng một tài khoản kết nối thử Express hoặc Custom. Chế độ test của Stripe có một trình tạo tài khoản giả "Jenny Rosen" bắn ra sự kiện thực tế.
- Kích hoạt sự kiện từ giao diện test Connect: hoàn tất onboarding, yêu cầu payout, hủy ủy quyền một tài khoản.
Luồng hủy ủy quyền là cái khó
Khi một tài khoản kết nối thu hồi quyền truy cập của app bạn, Stripe bắn account.application.deauthorized đúng một lần. Nếu handler của bạn crash, trả về 5xx, hoặc không xác nhận sự kiện kịp thời, Stripe thử lại — nhưng tài khoản kết nối đã đi rồi. Các lời gọi API sau đó cho tài khoản đó trả về 401.
Kiểm thử luồng deauth cẩn thận. Dùng chế độ test Connect để hủy ủy quyền tài khoản thử, bắt webhook, và chạy logic dọn dẹp của bạn với payload đã bắt. Replay cho tới khi đường đi chống đạn.
Express vs Standard vs Custom
Loại tài khoản thay đổi sự kiện person/capability bạn nhận. Tài khoản Express và Custom phát sự kiện person.* vì nền tảng của bạn giúp hoàn tất onboarding. Tài khoản Standard tự xử lý onboarding qua màn hình do Stripe host, nên bạn thấy ít sự kiện hơn. Nếu bạn đổi loại tài khoản giữa dự án — và người ta có làm — handler webhook của bạn cần điều chỉnh.
Điều chúng tôi thực sự sẽ làm
Cho một marketplace thật với analytics cấp nền tảng và báo cáo theo từng merchant, hãy dựng hai đường handler riêng biệt từ ngày đầu: một cho sự kiện nền tảng (không có header Stripe-Account), một cho sự kiện tài khoản kết nối. Định tuyến ở đầu hàm. Điều này tránh 90% bug "cái này cho ta hay cho merchant" về sau.
Webhook Connect dùng chung scheme chữ ký của Stripe, nên cơ chế xác minh giống hệt kiểm thử webhook Stripe thông thường. Về nền tảng toán chữ ký qua các nhà cung cấp, xem hướng dẫn xác minh chữ ký. Tham gia danh sách chờ PortPreview để kiểm thử Connect với bắt và replay tích hợp sẵn.