Stripe Checkoutを利用することで、手軽に安全なオンライン注文ページを顧客に提供することができます。
また、Checkoutの設定を変更することで、「カートの中の商品の数量を変更」したり、「アップセルの提案」を行うことも可能です。
これにより、顧客は注文の直前にカートの中身を再調整することができ、前のページに戻るなどの余計な手間を省くことができます。
カートの中身を取得する方法
「ブラウザがエラーでダウンした・移動中で一時的にオフラインになった」などの理由で、Checkoutのセッションが一時的に途切れるケースが存在します。
この場合、顧客はCheckoutページで変更した後の数量で、注文を再開したいと考えます。
その場合、システム側では、Stripe APIを利用し、カートの中身を取得する必要があります。
const items = await stripe.checkout.sessions.listLineItems(sessionId); // cs_xxxx
このAPIで取得できるデータの例はこちらです。
料金データや数量などが含まれていることが確認できます。
[{
id: 'li_xxxx',
object: 'item',
amount_subtotal: 1000,
amount_total: 1000,
currency: 'jpy',
description: 'Starter plan',
price: {
id: 'price_xxxx',
object: 'price',
active: true,
billing_scheme: 'per_unit',
created: 1639111716,
currency: 'jpy',
livemode: false,
lookup_key: null,
metadata: {},
nickname: null,
product: 'prod_xxxx',
recurring: null,
tax_behavior: 'inclusive',
tiers_mode: null,
transform_quantity: null,
type: 'one_time',
unit_amount: 1000,
unit_amount_decimal: '1000'
},
quantity: 1
}]
顧客に同じCheckoutセッションのURLを再提供したい場合
何かしらの理由で、顧客がCheckoutセッションから離脱してしまった場合、同じURLを再度ユーザーに提供することもできます。
const session = await stripe.checkout.sessions.retrieve(sessionId) // cs_xxxx
if (session.url || session.status !== 'expired') {
return {
url: session.url,
id: session.id,
};
}
// 有効期限が切れているので、セッション再作成
セッションの有効期限が切れていなければ、retrieve
APIのレスポンスにURLが含まれます。
これを利用して、中断したカートセッションを再開しましょう。
Webhookなどで、実際に注文された商品データを取得する
checkout.session.completed
やcheckout.session.async_payment_succeeded
イベントなどを利用し、注文が完了した後の業務を自動化することもできます。
app.post('/webhook', express.raw({type: 'application/json'}), async (request, response) => {
let event = request.body;
/**
* Webhookの署名検証処理がここに入ります
* @see https://stripe.com/docs/webhooks/signatures#verify-official-libraries
**/
const data = event.data.object;
if (
event.type !== 'checkout.session.completed' &&
event.type !== 'checkout.session.async_payment_succeeded'
) {
return response.sendStatus(200);
}
/**
* 支払いが完全に完了している場合のみ処理する
**/
if (data.payment_status === 'paid') {
const { data: items } = await stripe.checkout.sessions.listLineItems(data.id);
/**
* カートの中身の情報を利用して、発送業務などのシステムを呼び出す
**/
}
return response.sendStatus(200);
});
合計金額や配送料データなどはイベントで受信するデータに含まれています。
が、カートの中身については別途APIで取得する必要があることにご注意ください。
応用アイディア: 期限切れの場合のみ、セッションを新しく作成する
これまでの内容を応用すると、以下のような処理が作れます。
- セッションが有効ならば、そのままURLを返して再度Checkoutページに移動させる
- セッションが期限切れの場合、中断されたカートの中身や設定をできるだけ再現させたセッションを再作成する
// TypeScript
const recreateCheckoutSession = async (sessionId: string): Promise<{
url: string;
id: string;
}> => {
const session = await stripe.checkout.sessions.retrieve(sessionId);
if (session.url && session.status !== 'expired') {
return {
url: session.url,
id: session.id,
};
}
const items = await stripe.checkout.sessions.listLineItems(sessionId);
const params: Stripe.Checkout.SessionCreateParams = {
line_items: items.data.map(data => {
if (!data.price) return null;
return {
price: data.price.id,
quantity: data.quantity || 1,
};
}).filter(Boolean) as any,
cancel_url: session.cancel_url,
success_url: session.success_url,
mode: session.mode,
expires_at: session.expires_at,
};
if (session.customer) {
params.customer = session.customer as string;
} else if (session.customer_creation) {
params.customer_creation = session.customer_creation;
}
const newSession = await stripe.checkout.sessions.create(params);
return {
newSession,
items,
};
};
このコードはすべての引数・料金体系をサポートしていません。
そのため、このままではセッションの再開がうまく動かないケースもあることにご注意ください。
[PR] Stripe開発者向け情報をQiitaにて配信中!
- [Stripe Updates]:開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)
など、Stripeを利用してオンラインビジネスを始める方法について週に2〜3本ペースで更新中です。