開発

Stripe Terminalの実装手順:日本の対応リーダーとサーバー主導型APIのコード

Stripe Terminalの実装手順:日本の対応リーダーとサーバー主導型APIのコード

Stripe Terminalは、オンライン決済と同じPaymentIntentを使って、店頭のカードリーダーやiPhoneで対面決済を受け付けるStripeの製品です。日本では2025年9月に提供が始まりましたが、iDやQUICPay、交通系電子マネーは受け付けられません。この記事では、日本で選べるリーダーと費用、接続方式の選び方、店舗登録から模擬リーダーでの決済、Webhookでの確定とエラー処理までをcurlとNode.jsのコードで解説します。仕様と料金は2026年10月時点の公式情報で確認しています。

まとめ|Stripe Terminalを日本で導入する前に決める接続方式とリーダーの要点

日本で使えるリーダーは、据え置き寄りのStripe Reader S700とS710、Bluetoothでつなぐ BBPOS WisePad 3、そしてiPhoneのタッチ決済です。受け付けられるのは国際ブランドのカードと、その非接触決済だけ。電子マネーが売上の柱になっている店舗では、Terminal単体では足りません。

S700を使うなら実装はサーバー主導型です。サーバーがStripe APIでリーダーに決済を送り、結果はterminal.reader.action_succeededのWebhookで受け取ります。リーダーを買う前に、模擬リーダーで決済の流れを通せます。

費用は対面決済1件ごとに3.24%で、リーダー代はS700が46,480円、WisePad 3が10,480円です。日本は公開プレビューの段階にあり、PayPayの店頭決済も限定的なプレビューにとどまります。導入店舗は一気に増やさないでください。

Stripe Terminalの構成と日本で使えるリーダー・決済手段・手数料の現状

最初に、Terminalの仕組みと、日本で使えるものと使えないものを押さえます。

PaymentIntentをカードの提示で確定するStripe Terminalの仕組み

Terminalの決済は、オンラインと同じPaymentIntentで表します。違いは支払い方法の種類がcard_presentになる点です。カード番号を入力フォームで受け取る代わりに、リーダーがカードやスマートフォンを読み取り、暗号化したデータをPaymentIntentに付けて承認を求めます。

部品はPOSのアプリ、Stripe APIを呼ぶ自社のバックエンド、リーダーの3つ。リーダーは必ず「店舗(Location)」に紐付けて登録し、店舗の国で設定や表示言語が決まります。

売上はオンライン決済と同じダッシュボードに集まり、冪等キーの扱いも共通です。Stripe APIでのPaymentIntentの作成と冪等キーの知識がそのまま使えるでしょう。製品群の中での位置付けは親記事のStripeとは?仕組み・手数料・実装パターンで整理しています。

日本で選べるS700・WisePad 3・Tap to Payと使えない決済手段

Stripeは2025年9月3日の発表で、日本を25か国目のTerminal提供市場としました。日本向けのヘルプ記事では、2026年10月時点で日本の提供段階を公開プレビューとしています。

リーダー 種類 通信
Stripe Reader S700 スマートリーダー Wi-Fi
Stripe Reader S710 スマートリーダー セルラーとWi-Fi
BBPOS WisePad 3 モバイルリーダー Bluetooth・USB
iPhoneのタッチ決済 端末内蔵(プレビュー) 端末の回線
Androidのタッチ決済 端末内蔵(プレビュー) 端末の回線

S710は料金ページとヘルプ記事に載る一方、地域別の考慮事項のドキュメントの国別表では日本のスマートリーダーはS700だけです。S710前提なら注文前に営業窓口で確かめてください。

決済手段の制約は、リーダーより先に確認します。同ドキュメントによると、日本で使えるカードはVisa、Mastercard、American Express、JCB、Discover、Diners Clubで、通貨は日本円だけ。非接触は国際規格のみ対応し、iDやQUICPayしか載っていないカードは国際ブランドのロゴがあっても読めません。ヘルプ記事は交通系ICを含むFeliCa系の決済を非対応としています。

PayPayの店頭決済は限定的なプライベートプレビューで、営業への問い合わせが必要です。WeChat Payは地域の制限で日本のTerminalでは使えません。オンラインのPayPayはStripe PayPay決済の実装手順で扱っています。

対面決済3.24%とタッチ決済の追加18円・リーダー代の費用内訳

Stripeの日本向け料金ページでは、2026年10月時点の対面決済の料金を次のように定めています。

項目 料金 発生する単位
対面のカード決済 3.24% 決済の成功ごと
タッチ決済の追加料金 18円 オーソリごと
P2PE(任意) 8円 オーソリごと
BBPOS WisePad 3 10,480円 1台
S700・S710 各46,480円 1台
モバイル通信 月1,580円 リーダー1台

タッチ決済の18円は、成功ではなく承認の要求ごとにかかります。客単価500円なら3.24%の16.2円に18円が乗り、料率は6.8%。少額決済が中心の業態では専用リーダーより割高です。リーダー代は1台3万6千円の差があるため、店舗数と客単価で損益分岐を出してから機種を決めます。

SDKとサーバー主導型の選び方:POSの種類とネットワークで決める接続方式

Terminalには4種類のSDKと、SDKを使わないサーバー主導型があります。選択を誤ると、リーダーを買い替えるか作り直すことになります。

4種類のSDKとサーバー主導型で使える日本のリーダーの対応範囲

統合の設計に関する公式ドキュメントから、日本で使うリーダーとの対応を抜き出しました。

実装方式 S700・S710 WisePad 3 タッチ決済
サーバー主導型 対応 非対応 非対応
JavaScript SDK 対応 非対応 非対応
iOS SDK 対応 Bluetoothのみ iPhone
Android SDK 対応 BluetoothかUSB Android
React Native SDK 対応 BluetoothかUSB iPhone・Android

決め手は、POSがブラウザかネイティブアプリか、モバイルリーダーやタッチ決済を使うか、の2つ。WisePad 3とタッチ決済にはネイティブのSDKかReact Native SDKが必要です。サーバー主導型はオフライン決済に対応しないため、回線が不安定な屋外の催事には向きません。

S700をWebのPOSから動かすならJavaScript SDKでなくサーバー主導型

ブラウザで動くPOSからS700を使う場合、候補はJavaScript SDKとサーバー主導型の2つです。カード支払いの回収に関する公式ドキュメントは、スマートリーダーにはサーバー主導型を推奨しています。

理由はネットワークです。JavaScript SDKでは、POSの端末とリーダーが同じローカルネットワークにあり、有効なローカルDNSが引ける必要があります。Wi-Fiがゲスト用と業務用で分かれた店舗では、ここで接続が止まりがちです。サーバー主導型ならリーダーはインターネット経由でStripeとつながるだけで、同じネットワークに置く必要はありません。

.NETで作られた既存のPOSからも呼べるため、以降の実装はサーバー主導型で進めます。

サーバー主導型で決済を通す手順:日本の店舗登録からシミュレーターでの決済まで

ここからはテスト用の秘密鍵だけで動く手順です。

日本の店舗を漢字かカナの住所項目で登録するLocation作成のcurl

地域別の考慮事項のドキュメントによると、日本の店舗では他の国で使うaddressを設定できません。代わりにaddress_kanjiかaddress_kanaのどちらか、または両方を入れます。店名はdisplay_name、display_name_kanji、display_name_kanaのいずれか1つ以上が必須です。

# 日本の店舗(Location)を作る。住所と店名は漢字表記で登録する例
curl https://api.stripe.com/v1/terminal/locations \
  -u "sk_test_xxx:" \
  -d "display_name_kanji=渋谷本店" \
  -d "address_kanji[postal_code]=150-0002" \
  -d "address_kanji[state]=東京都" \
  -d "address_kanji[city]=渋谷区" \
  -d "address_kanji[town]=渋谷2丁目" \
  -d "address_kanji[line1]=1-2-3" \
  -d "address_kanji[country]=JP"

返るtml_で始まるIDを、リーダーの登録時に渡します。日本向けのtown(町名)を含む項目の定義はLocation作成のAPIリファレンスにあります。店舗とStripeアカウントの国が違うと決済は通らないため、海外法人のアカウントで日本の店舗を動かす構成は取れません。

シミュレーションリーダーをsimulated-wpeの登録コードで作る手順

リーダー登録のAPIリファレンスでは、registration_codeにsimulated-wpeを渡すと、画面を持たない模擬のリーダーが作られます。本物のS700なら、リーダーの設定画面で「ペアリングコードを生成」をタップし、表示されたコードを同じ項目に入れます。

# 模擬リーダーを店舗に登録する(本番機では registration_code にペアリングコードを入れる)
curl https://api.stripe.com/v1/terminal/readers \
  -u "sk_test_xxx:" \
  -d registration_code=simulated-wpe \
  -d label=register-01 \
  -d location=tml_xxx

返るtmr_で始まるIDは、レジ端末ごとの送信先として保存します。device_typeはsimulated_wisepos_eで、日本で販売されていないWisePOS Eの模擬機です。APIの流れはS700と同じでも、日本の店舗での表示の違いは公式に記載が見当たりません。最終確認は物理のS700で行います。

対面用のPaymentIntentを作りリーダーへ送って模擬カードで決済する

決済は、PaymentIntentを作る、リーダーへ送る、カードの提示を待つ、の3段階。テストではカードの提示をpresent_payment_methodで代用します。

# 1. 対面決済のPaymentIntentを作る(日本円は小数点なし。1,500円なら1500)
curl https://api.stripe.com/v1/payment_intents \
  -u "sk_test_xxx:" \
  -d amount=1500 \
  -d currency=jpy \
  -d "payment_method_types[]=card_present" \
  -d capture_method=manual

# 2. リーダーへ送る。応答は即座に返り、action.status は多くの場合 in_progress
curl https://api.stripe.com/v1/terminal/readers/tmr_xxx/process_payment_intent \
  -u "sk_test_xxx:" \
  -d payment_intent=pi_xxx

# 3. テスト環境だけで使える、カードをかざした操作の代用(既定は4242のVisa)
curl -X POST https://api.stripe.com/v1/test_helpers/terminal/readers/tmr_xxx/present_payment_method \
  -u "sk_test_xxx:"

# 4. 手動キャプチャーで売上を確定する
curl -X POST https://api.stripe.com/v1/payment_intents/pi_xxx/capture \
  -u "sk_test_xxx:"

手順2の応答は、リーダーが指示を受け取ったという意味しか持ちません。客がカードを出すまで時間がかかるため、結果はWebhookかポーリングで後から受け取ります。capture_methodをmanualにすると注文と照合してから確定できる半面、手順4を忘れると売上になりません。

Terminalのテストに関する公式ドキュメントでは、物理のテストカードは金額の末尾で結果が変わり、日本円は右端2桁で判定されます。105円ならgeneric_declineで拒否、末尾00なら承認。オンライン用のテストカードはStripeテストカード一覧と使い方にまとめています。

Webhookで決済結果を受けて二重決済と処理待ちを防ぐエラー処理の実装

サーバー主導型では、決済の成否がPOSに同期で返ってきません。結果を受け取る口と、失敗時の振る舞いを先に決めておきます。

Node.jsで決済の開始とaction_succeededでの確定を書く実装例

Stripe公式のNode.jsライブラリは、2026年10月時点でnpmの最新が23.0.0です。Terminalのクイックスタートのサンプルもstripeの23系を依存に指定しています。POSから決済を始めるAPIと、Webhookで結果を受ける処理を1つにまとめた例を示します。

import express from 'express';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const app = express();

// POSの「会計」ボタンから呼ぶ。拒否後の再試行でも同じ注文IDなら同じPaymentIntentが返る
app.post('/terminal/charge', express.json(), async (req, res) => {
  const { amount, readerId, orderId } = req.body;
  const intent = await stripe.paymentIntents.create({
    amount,
    currency: 'jpy',
    payment_method_types: ['card_present'],
    capture_method: 'manual',
    metadata: { order_id: orderId },
  }, { idempotencyKey: `terminal-pi-${orderId}` });

  try {
    const reader = await stripe.terminal.readers.processPaymentIntent(readerId, {
      payment_intent: intent.id,
    });
    res.json({ paymentIntentId: intent.id, status: reader.action.status });
  } catch (err) {
    // terminal_reader_busy・terminal_reader_offline・terminal_reader_timeout などをPOSへ返す
    res.status(409).json({ paymentIntentId: intent.id, code: err.code });
  }
});

// Terminal専用のWebhookエンドポイント
app.post('/terminal/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body, req.headers['stripe-signature'], process.env.STRIPE_TERMINAL_WEBHOOK_SECRET
    );
  } catch {
    return res.status(400).send('invalid signature');
  }

  const reader = event.data.object;
  const piId = reader.action?.process_payment_intent?.payment_intent;
  if (!piId) return res.sendStatus(200);

  if (event.type === 'terminal.reader.action_succeeded') {
    const pi = await stripe.paymentIntents.retrieve(piId);
    // 注文と照合してから売上を確定する。同じイベントの再送に備えて冪等キーを付ける
    if (pi.status === 'requires_capture' && await orderExists(pi.metadata.order_id, pi.amount)) {
      await stripe.paymentIntents.capture(pi.id, {}, { idempotencyKey: `terminal-cap-${pi.id}` });
    }
  } else if (event.type === 'terminal.reader.action_failed') {
    const code = reader.action.failure_code;
    if (code === 'connection_error') {
      // リーダーが応答を受け取れなかっただけで、承認済みの可能性がある
      const pi = await stripe.paymentIntents.retrieve(piId);
      await notifyPos(reader.id, pi.status);
    } else {
      await notifyPos(reader.id, code); // card_declined・customer_canceled など
    }
  }
  res.sendStatus(200);
});

orderExistsとnotifyPosは、注文照合とPOSへの通知を表す仮の関数です。公式ドキュメントが推奨するのは、Terminalのイベント専用のWebhookエンドポイント。購読するのはterminal.reader.action_succeededとterminal.reader.action_failedで、承認前に処理を挟む場合だけterminal.reader.action_updatedを足します。署名検証と冪等な注文確定の考え方は、決済Webhookの署名検証と冪等な注文確定で詳しく扱っています。

カード拒否・タイムアウト・オフライン・処理中の4種の失敗と再試行

サーバー主導型の公式ドキュメントが挙げる失敗のうち、POSの画面設計に影響するのは次の4つです。

  • カード拒否:同じPaymentIntentのままprocess_payment_intentを再度呼び、別のカードを出してもらう。新しく作るなら古い方を必ずキャンセルする
  • terminal_reader_timeout:一時的な通信の問題で、再試行してよい。ただしリーダーは指示を受け取っている場合があり、成功の取り違えに注意する
  • terminal_reader_offline:2分間リーダーからの信号が途絶えた状態。電源と回線を確認するまで再試行しない
  • terminal_reader_busy:リーダーは同時に1件しか処理しない。更新の適用中や設定変更中にも返る

拒否のたびにPaymentIntentを作り直す実装は、二重決済の典型的な原因です。上のコードが注文IDを冪等キーにしているのも、POSの再送で決済を増やさないため。リーダーのソフトウェアが2.42以上なら失敗時にapi_errorが入り、種類がcard_errorならメッセージを客に見せられます。

取り消しはcancel_actionで行いますが、承認の処理中はterminal_reader_busyが返ります。リーダーが途中で回線から外れるとWebhookが届かず、in_progressのまま残ることもあります。POSには「状態を確認」と「リーダーをリセット」のボタンを置いてください。

手動キャプチャーの2日期限と日次照合で未確定の承認を残さない

公式ドキュメントによると、承認から2日以内にキャプチャーしないと承認は失効し、押さえた金額は客に戻ります。Webhookの取りこぼしで売上が消える経路です。

そこで1日の終わりに、PaymentIntentと注文を突き合わせます。requires_captureのまま残ったもののうち、完了済みの注文で現金など別の支払いも受けていないものはキャプチャー、注文に結び付かないものはキャンセル。後者を放置すると客の明細に不要な承認が残り、問い合わせの原因になります。

iPhoneのタッチ決済とWisePad 3で店外の決済を組むときの要件と制約

移動販売や催事など、S700を置けない場面ではネイティブアプリでの実装になり、作る範囲は広がります。

Tap to Payのエンタイトルメント申請とiPhone XS以降・PINの条件

タッチ決済の公式ドキュメントでは、日本のiPhoneのタッチ決済は公開プレビューの扱いです。実装はiOS SDKかReact Native SDKで行い、Appleの審査を通す必要があります。

  1. Apple Developerアカウントで開発用のエンタイトルメントを申請する
  2. エンタイトルメントファイルにcom.apple.developer.proximity-reader.payment.acceptanceをtrueで追加する
  3. Terminal iOS SDKでタッチ決済のリーダーに接続し、決済を実装する
  4. 社内テスト後、配布用のエンタイトルメントを申請して審査に出す

対象はiPhone XS以降で、1年以内のiOSを動かす端末です。一定額を超える非接触決済で求められるPIN入力はiOS 16.4以降で動き、iOSのベータ版では使えません。審査前には、Appleが求める「How to Tap」の操作案内をアプリ内に表示する実装も要ります。

WisePad 3をBluetoothでつなぐ場合のSDK選択とリーダー更新

WisePad 3はPOSのアプリとBluetoothかUSBでつなぐモバイルリーダーで、iOSではBluetoothだけが使えます。リーダーの更新もアプリ経由で流れます。

日本で動かすWisePad 3は、ソフトウェアが4.01.07.00_JP_v14_491001以上である必要があり、S700とS710は2.34.3.0以上が条件です。接続時に必須の更新が走ると終わるまで決済できないため、開店前にアプリを起動して更新を済ませる手順を店舗のマニュアルに入れます。電池残量が少ないと必須の更新が始まらず、接続にも失敗します。

Stripe Terminalを採用する条件と、既存の決済端末やSquareを選ぶ場面

Terminalは、対面決済を自社のシステムに組み込むための部品です。この前提に合うかで採否が決まります。

採用する条件:自社アプリやPOSでオンラインと決済データを統合したい

次の条件が2つ以上そろうなら、Terminalを選ぶ価値があります。

  • オンライン決済でStripeを使っており、店頭の売上も同じダッシュボードで扱いたい
  • 予約アプリや会員アプリの中に決済を組み込みたい
  • 出店者や施術者への売上の分配を、店頭とオンラインで共通にしたい
  • 客の大半が国際ブランドのカードで支払う

分配を伴う場合、Terminalの決済もStripe Connectの資金フローに載せられます。

見送る条件:電子マネー必須の店舗とプレビュー段階を許容できない導入

交通系ICやiD、QUICPayでの支払いが一定の割合を占める店舗では、Terminalを主たる決済手段にしません。客の支払い手段を断ることになるからです。電子マネー対応の決済端末とPOSの組み合わせを選びます。端末の違いは決済端末とは?種類・読み取り方式とPOS連携で、業態別の選び方は飲食店の決済システムとはで整理しています。

もう1つは提供段階です。日本は公開プレビューで、PayPayの店頭決済も限定的なプレビュー。仕様変更のたびに全店のアプリを直す体制が無いなら、まず1店舗で試してください。

POSや基幹システムとの連携を外部に任せる判断と見積もりの範囲

工数が膨らむのは決済そのものより周辺です。注文との照合、日次のキャプチャー処理、リーダーと店舗の管理、POSのエラー画面、会計連携は、どれもStripeの外で作ります。

既存のPOSに対面決済を足す、会員アプリにタッチ決済を組み込む、といった計画なら、リーダーを注文する前に接続方式と照合の設計を固めてください。POSそのものの選び方はPOSシステムとは?仕組み・種類と自社開発の判断で解説しています。一創では決済・サブスクリプションシステム開発として、Stripeを使った対面とオンラインの決済の設計から、POSや基幹システムとの連携までを受託しています。

Stripe Terminalのよくある質問|日本での提供・料金・電子マネー

Stripe Terminalの導入を検討するときに確認されることの多い質問をまとめました。

Stripe Terminalは日本で使えますか?

使えます。Stripeは2025年9月3日に日本での提供を発表し、2026年10月時点のヘルプ記事では公開プレビューの段階です。リーダーはStripe Reader S700とS710、BBPOS WisePad 3、iPhoneとAndroidのタッチ決済が案内されています。Stripeアカウントと店舗の両方が日本にあり、日本円で決済することが条件となります。

Stripe Terminalの手数料とリーダーの価格はいくらですか?

2026年10月時点の日本の料金では、対面のカード決済は成功1件ごとに3.24%です。iPhoneなどのタッチ決済は承認の要求ごとに18円が加わり、任意のP2PEを使うとさらに8円かかります。リーダーはBBPOS WisePad 3が10,480円、Stripe Reader S700とS710が各46,480円です。モバイル通信を使うリーダーは1台につき月1,580円が別にかかります。

Stripe TerminalでiDやQUICPay、交通系電子マネーは使えますか?

使えません。Stripe Terminalが対応する非接触決済は国際規格のものだけで、交通系ICカードやiD、QUICPayなどFeliCa系の決済は非対応です。Apple Payに登録したカードでも、iDやQUICPayとしてしか使えないものは読み取れません。非接触の波形マークが付いたカードは国際規格に対応しているため、Terminalで決済できます。

リーダーを買わずにStripe Terminalの開発とテストはできますか?

可能です。サーバー主導型ではリーダー登録のAPIにsimulated-wpeを渡すと模擬のリーダーが作られ、present_payment_methodでカードをかざした操作を再現できます。各SDKにも模擬リーダーが付属します。QRコード決済とモバイルウォレットはテスト環境の模擬リーダーで試せないため、本番前に物理のリーダーとテストカードで確認してください。

Stripe TerminalとSquareの違いは何ですか?

Squareは自社のPOSアプリと決済端末を一体で提供し、Square Terminal APIの公式ドキュメントでは日本でPayPayと電子マネーにも対応しています。Stripe Terminalは自社のPOSやアプリに組み込む部品で、オンライン決済と同じAPIで扱える点が強みです。比較はSquare APIとは?Stripe・PAY.JPとの選び方を参照してください。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.15 テックブログ リゾートトラスト不正アクセス:会員2.6万件・カハラ横浜3.6万件の対象確認と窓口
  2. 2025.09.03 コラム ストループ効果とは?原典1935年の実測値と年齢別の平均・テストのやり方
  3. 2026.10.16 テックブログ バーガーキング不正アクセスで約1,118万件の情報漏洩|対象確認・案内メールの真偽と運営側のログ点検
  4. 2026.01.20 テックブログ PineDramaとは?TikTokのショートドラマアプリの日本配信・料金・安全性を解説
  5. 2025.09.03 コラム Google AIモードの履歴の消し方と残る理由|いつまで残るか・使い方・オフにする方法【2026年10月】

RELATED POSTS 関連記事

目次