JP_Stripes & Cloudflare Meet-up 岡山でAstro / Stripe / Cloudflare Pagesのワークショップを開催しました
AWS Samurai 2023を受賞した古里さんからのお声掛けで、StripeとCloudflareを学べるイベントに参加しました。ワークショップでは、Astro / Stripe / Cloudflare Pagesについて学びました。StripeとCloudflareの連携については、決済とメールの連携があると紹介されました。具体的なコード例も提供されました。また、サブスクリプションの申込後にユーザーアカウントを作成する方法や、決済が完了するまでの処理についても説明されました。ワークショップは好評で、AstroやStripe、Cloudflareに興味がある方は是非参加してみてください。
目次
AWS Samurai 2023を受賞された古里さんからお声がけを頂きまして、StripeとCloudflareを一度に学べるイベントに参加してきました。
当日のツイートまとめはTogetterにて
Astro / Stripe / Cloudflare Pagesの山盛りワークショップを開催
イベントでは、2時間の枠を頂いてワークショップを行いました。
ワークショップ資料は、Zennにて無料公開しています。
-> [Stripe x Cloudflareワークショップ] Astroを使って、サブスクリプション申し込みページを作ろう
ワークショップ内容のその先へ
Zennの資料からは諸事情で外したのですが、「こんなこともできますよ」を2-3本用意していました。
せっかくなので、こちらの記事でフォローアップとして紹介します。
CloudflareのMailChannelsを使って、顧客作成時などにメールを送信する
サブスクリプションの契約完了時にウェルカムメールを送信するなど、決済とメールの連携はよくあるケースの1つです。
例えば次のサンプルコードでは、「Stripeに顧客データが作成された(Checkout / Payment Linksなどでサブスク契約が完了した)時点で、MailChannelでメールを送信する」動きを実装しています。
// 顧客の作成が成功した場合にトリガーされる
case 'customer.created': {
const customer = event.data.object
await fetch('https://api.mailchannels.net/tx/v1/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
personalizations: [{
to: [{
email: customer.email,
name: customer.name,
}]
}],
from: {
email: import.meta.env.FROM_EMAIL,
name: 'XXXサービス'
},
subject: 'ようこそXXXサービスへ!',
content: [
{
type: 'text/plain',
value: `オンボーディングのためのコンテンツ`,
},
],
})
})
break
}
MailChannelsの使い方は、Qiitaに公開されている記事「Cloudflare Workers から MailChannels でメール送信するついでに Cloudflare Pages でコンタクトフォームを作る」をご覧ください。
Payment Links / Checkout / 料金表での注文内容・数量を取得する
料金表やPayment Links・Checkoutなどのリンク型・リダイレクト型決済フォームを利用した場合、「クロスセルによる商品の追加提案」や「決済ページでの注文数量の変更」などが行えます。
参考: Stripe Checkoutを利用した注文ページで、顧客が商品の個数を変更できるようにする
この場合、Webhookを利用して「実際に顧客が注文した商品と数量」を把握する必要があります。
料金表・Payment Links・Checkoutいずれの場合でも、checkout.session.completed
とcheckout.session.async_payment_succeeded
を利用します。
const body = event
switch (event.type) {
+ case 'checkout.session.completed': {
+ const session = event.data.object
+ const lineItems = await stripe.checkout.sessions.listLineItems(session.id)
+ lineItems.data.forEach(item => {
+ const productId = typeof item.price.product === 'string' ? item.price.product : item.price.product.id
+ console.log([
+ `商品ID: ${productId}`,
+ `注文数量: ${item.quantity}`,
+ `金額: ${item.amount_total}`
+ ].join('\n'))
+ })
break
}
顧客データが作成されました。
Email: [email protected]
新しいサブスクリプション申し込みがありました。
開始日: 1682574904
true: 1400 * 1
商品ID: prod_LFzTo8Pi8xirKs
注文数量: 1
金額: 1400
商品ID: prod_LFzdDEOEwRtuRw
注文数量: 1
金額: 2000
3DSによる追加の認証やコンビニ決済など、「決済が完了するまで少し時間がかかるケース」が存在します。
決済完了が非同期の場合は、checkout.session.async_payment_succeeded
イベントで改めて決済完了後にイベントが送信されます。
checkout.session.completed
にて、payment_status
がpaid
かどうかを判定しましょう。
- case 'checkout.session.completed': {
+ case 'checkout.session.completed':
+ case 'checkout.session.async_payment_succeeded': {
const session = event.data.object
+ if (session.payment_status !== 'paid') {
+ break
+ }
サブスクリプション申込後に、システム側のユーザーアカウントを作成する
サブスクリプションの申し込みが完了してから、ユーザーアカウントを発行する方法では、Webhookを利用します。
このケースでは、customer.created
やcustomer.subscription.created
、checkout.session.completed
のWebhookイベントから、顧客やサブスクリプションの作成時・Checkoutのセッション完了時にユーザーアカウントを発行しましょう。
switch (event.type) {
// 顧客の作成が成功した場合にトリガーされる
case 'customer.created': {
const customer = event.data.object
+ const payload = {
+ name: customer.name,
+ email: customer.email,
+ phone_number: customer.phone,
+ }
+ await AnyUserService.createNewUser(payload)
console.log([
`顧客データが作成されました。`,
`Email: ${customer.email}`
].join('\n'))
break
}
この方法を採用すると、Webhook APIを用意せずにZapierやAWS Step Functionsなどでワークフローを構築できるメリットもあります。
おわりに
盛りだくさんな内容のワークショップでしたが、概ね高評価を頂けたので、すごくホッとしています。
デモサイトを作ったり、他の地域でもこのワークショップを開催できたりすると嬉しいなと思いますので、「AstroやStripe、Cloudflareが気になる!」という方は、お気軽に岡本やJP_Stripesコミュニティにご相談ください。