Share
Embed
JavaScriptで始める店舗インフラ決済構築/stripe_terminal_workshop
JavaScriptで始める店舗インフラ決済構築:
Stripe Terminal簡易ワークショップ
https://connect2026.jpstripes.com/sessions/track-b-1655/
Masahiko Sakakibara
August 01, 2026
Transcript
32 slides
-
ハンズオン前にこちらを作業ください 完成品を先に体験 HANDS-ON / SETUP git clone git clone --branch
starter https://stripe-terminaworkshop.netlify.app/ https://github.com/rdlabo-team/ stripe-terminal-workshop.git npm install → npm run dev ZIPでDL:https://github.com/rdlabo-team/stripe-terminal-workshop/ archive/refs/heads/starter.zip 15 -
Stripe Terminal の 具体的な選択肢 1つの店舗サービスを、 事業に合う形で届ける 端末なしから、 Apps on Devicesまで
Stripe Terminal × Capacitor 榊原昌彦 -
最初の判断は、専用の決済端末を用意するか TERMINAL / CHOICE 店舗へ専用端末を購入・配送するかで、事業の始め方が変わります。 用意しない 用意する Tap to Pay
Stripe Reader iPhoneそのものが決済端末になる 単体で使う/外からつなぐ/ 端末上で自社アプリを動かす 購入・配送・在庫・交換が不要 機能と運用を深く作り込める 02 -
専用端末を配らないなら、 Tap to Pay TERMINAL / NO DEVICE iPhoneが、そのまま決済端末になる。 専用端末の購入がいらない
配送・在庫・交換の運用を持たない 小規模店舗や事業検証から始めやすい https://www.apple.com/jp/business/t ap-to-pay-on-iphone/ 日本では iPhoneのみ・iOSアプリが必要 03 -
端末を配るなら、作らない・つなぐ・載せる TERMINAL / WITH DEVICE 作らない つなぐ 載せる Standalone mode
既存システムと接続 Apps on Devices アプリ不要 S700単体で金額入力・決済 (公開プレビュー) Internet:Web / iOS / Android Bluetooth:iOS / Android USB:Androidのみ S700上で自社アプリを実行 決済前後の体験まで設計 ※ Bluetooth/USB接続では Webブラウザは利用できません 04 -
端末なしで始め、必要になったら深くできる BUSINESS / GROWTH 最初から高価な専用端末を全店舗へ配る必要はありません。 STEP 1 STEP 2 STEP
3 Tap to Pay Web+S700 Apps on Devices iPhoneで小さく検証 端末投資を抑える 店舗が増えたら 安定した端末運用へ 小さく始める 端末そのものを 自社プロダクトへ 深く作り込む 05 -
普通に作ると、成長するたびに作り直す BUSINESS / PROBLEM 提供する形が変わるたび、別の開発プロジェクトが始まります。 iPhoneアプリ Web POS 端末アプリ Tap
to Pay用に開発 S700接続用に開発 Apps on Devices用に開 発 1回目 2回目 3回目 同じ商品・会員・特典・決済を、何度も作り、何度も改善する。 06 -
Capacitorなら、1つの店舗サービスを横に揃えられる CAPACITOR / VALUE 1つの店舗サービス 商品・予約・会員・特典・決済 Web+Reader Tap to Pay
Bluetooth / USB Apps on Devices ブラウザ iPhone Bluetooth:iOS/Android USB:Androidのみ S700 実行環境は違う。プロダクトは一つ。 07 -
Web技術を、モバイルアプリへ CAPACITOR / WHAT いつもの Web技術 Capacitor HTML CSS JavaScript
/ TypeScript 同じWebアプリを Web iPhone Android へ届ける 新しい専用言語を覚える話ではありません。 08 -
端末を後から導入しても、店舗サービスはそのまま CAPACITOR / MIGRATION 設備投資のタイミングと、プロダクト開発を切り離せます。 端末なしで開始 端末を追加 体験を深く Tap to
Pay Web+S700 Apps on Devices 最初に作った画面・業務・顧客体験を継続利用 09 -
店舗アプリと決済を、 3つの役割でつなぐ CAPACITOR / STRUCTURE それぞれが、得意な部分だけを担います。 Capacitor 1つの店舗アプリを Web・iPhone・Androidへ 届ける
Community Plugin アプリと Stripeの 決済機能をつなぐ Stripe SDK 各端末で安全な 決済処理を実行する 環境ごとの違いを吸収 アプリは一つ、決済基盤は Stripe。 10 -
@capacitor-community/stripe-terminal 01 Capacitor公式が案内する Communityエコシステム 02 Stripe公式SDKを利用し、 Stripeの支援を受けて開発 03 Web・Tap to
Pay・Apps on Devicesを継続保守 CAPACITOR / TRUST 11 -
今日、完成させるもの HANDS-ON / GOAL 完成済みの店舗アプリ HTML・CSS・クリックイベントは実装済み Plugin追加 Reader検索 Reader接続 決済成功
npm Simulated Web Receipt やらない: HTML/CSS・バックエンド・ネイティブビルド 14 -
完成品を見てから、手元で起動する 完成品を先に体験 HANDS-ON / SETUP git clone git clone --branch
starter https://stripe-terminaworkshop.netlify.app/ https://github.com/rdlabo-team/ stripe-terminal-workshop.git npm install → npm run dev ZIP:https://github.com/rdlabo-team/stripe-terminal-workshop/ archive/refs/heads/starter.zip 15 -
TODO 1|Community Pluginを追加する HANDS-ON / TODO 1 CapacitorだけではTerminal SDKを呼べません。橋渡しを追加します。 店舗アプリ
画面・操作・APIは すでに完成済み Community Plugin @capacitor-community/ stripe-terminal コメント解除 import connectTypeByMode 最新版を利用 npm install @capacitor-community/stripe-terminal 16 -
TODO 2|Pluginを使うための初期設定 HANDS-ON / TODO 2 「Tokenをどこから取るか」「Simulated Readerを使うか」をPluginへ渡します。 INPUT PLUGIN
COMPLETE tokenProviderEndpoint isTest initialize(...) Promise<void> 初期化完了 Token取得先 Simulated Readerを使 用するか 2つの設定を Pluginへ渡す Loaded event 準備完了を通知 WHY|Connection Tokenの取得先と、 Simulated Readerを使うかを SDKへ設定するため 17 -
Connection TokenをAPIから受け取る理由 HANDS-ON / SECURITY StripeのSecret Keyを、ブラウザやアプリに置かないためです。 PLUGIN → API
API → STRIPE API → PLUGIN POST /connection/token Connection Token を作成 { secret } 短時間だけ有効 Secret Keyはサーバーだけ。 APIを認証し、信頼できるアプリへ Tokenを返す 18 -
TODO 3|Readerを探す HANDS-ON / TODO 3 検索を開始し、DiscoveredReadersイベントで{ readers }を受け取ります。 ACTION
EVENT SELECT discoverReaders DiscoveredReaders readers[0] { type, locationId } { readers } 接続するReader WHY|決済命令を送る対象の Readerを、利用可能な端末から見つけるため 19 -
TODO 4|選んだ Readerへ接続する HANDS-ON / TODO 4 3つの値を同じオブジェクトにまとめて、connectReader()へ渡します。 INPUT 1
INPUT 2 INPUT 3 reader type locationId readers[0] ReaderInterface + Internet Web接続 + Readerを登録した 店舗・拠点のID WHY|選んだ Readerと決済セッションを確立し、以降の操作先を決めるため connectReader({ reader, type, locationId }) 20 -
PaymentIntent|アプリから APIへ HANDS-ON / API REQUEST 画面の金額と通貨を、ホスティング済みAPIへ送ります。 REQUEST HTTP RESPONSE
{ amount: 1250, currency: 'usd' } POST /connection/intent { paymentIntent } client secret amountは最小通貨単位。 $12.50なら1250を送る 21 -
なぜ、端末へ金額を直接渡さないのか HANDS-ON / WHY PAYMENTINTENT PaymentIntentは、金額ではなく「決済取引そのもの」を表します。 STORE APP BACKEND READER
店舗アプリ PaymentIntent カード情報 金額・商品・注文を管理 注文内容を確認して作成 PaymentMethodを 取引へ関連付け Readerは会計システムではなく、カード情報を安全に収集する装置 22 -
PaymentIntentが、一つの取引の状態をつなぐ HANDS-ON / PAYMENT LIFECYCLE 作成・カード収集・決済実行を、同じPaymentIntentで追跡します。 CREATED COLLECT CONFIRM requires_
payment_method requires_ confirmation succeeded requires_capture 支払い方法を待つ カード収集済み 決済実行を待つ 拒否時はrequires_ payment_methodへ戻る 再試行・売上確定・返金も、同じ取引を起点に管理できる 23 -
カードを読む工程と、決済を実行する工程 HANDS-ON / TWO STEPS 意味も失敗条件も違うため、Terminalは2段階に分かれています。 STEP 1 BETWEEN STEP
2 collect PaymentMethod() 決済前の判断 processPayment() カードを待つ PaymentMethodを関連 付け 内容確認・キャンセル 業務ロジック オーソリを送信 承認/拒否を確定 収集後・決済前に、確認やキャンセルを挟める 24 -
TODO 5|client secretでカード情報を集める HANDS-ON / TODO 5 APIから受け取ったclient secretをPluginへ渡します。 INPUT
ACTION SAVE paymentIntent collectPaymentMethod cachedPaymentIntent pi_..._secret_... APIの応答 client secretを Stripe SDKへ Plugin内部に保存 返り値はvoid WHY|Stripe上の決済取引へ、 Readerで集めたカード情報を関連付けるため 25 -
TODO 6|収集したカードで決済を実行する HANDS-ON / TODO 6 保存したPaymentIntentを使い、カード会社へオーソリを送ります。 INPUT PLUGIN RESULT
引数なし confirm PaymentIntent() 承認/拒否 cachedPaymentIntent を使用 内部でprocessPayment オーソリを送信 Confirmed event または決済エラー WHY|カードを読めたことと、カード会社が決済を承認したことは別だから 26 -
HANDS-ON / COMPLETE FLOW 完成した決済フロー|値が一周する 受講者が有効にした6つのTODOを、値の流れで振り返ります。 1 TOKEN POST /connection/token
← { secret } 2 READER discoverReadersを開始 DiscoveredReaders ← { readers } 3 PAYMENT { amount, currency } client secret → collect → confirm connect { reader, type, locationId } Secret Keyはサーバー側。アプリには一時的な secretと Reader情報だけを返す 27 -
「決済に成功しました」が表示されたら完成 HANDS-ON / COMPLETE ワークショップコンソールで処理を確認 01 Readerを発見し、接続できた 02 PaymentIntentを作成できた 03
collect → confirm → disconnectが完了 物理端末なしで、 Terminalの決済フローが動いた 28 -
実装したのは、環境に依存しない決済の中心部分 HANDS-ON / RESULT 今回実装した店舗アプリ 同じJavaScript・同じ決済フロー Web+Simulate d Web+S700 Tap
to Pay Apps on Devices 今日 店舗端末 iPhone S700 今日書いた JavaScriptを捨てずに、別の実行環境へ 29 -
最後に、同じプロジェクトを端末で動かす HANDS-ON / LIVE DEMO 実装は完了。ここからは登壇者の実機デモです。 参加者 登壇者 Web+Simulated コンパイル済みアプリ
ブラウザで実装 同じ画面・同じ決済フローを 実際のTerminal環境で実行 物理端末なし 変わるのは実行環境だけ 30 -
ここから先は、興味に合わせて自宅で HANDS-ON / NEXT github.com/rdlabo-team/stripe-terminal-workshop 01 Capacitorでのビルドと同期: https://capacitorjs.jp/ 02 Tap
to Pay・実機への接続: https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay 03 Apps on Devices向けAPKの作成: https://docs.stripe.com/terminal/features/apps-on-devices/build まずWebで完成させる。必要になったら、そのまま端末へ。 31