INTRODUCTIONセクションは、トークン決済v2を初めて扱うシステム担当者の方、開発者の方に向けたドキュメントです。
トークン決済v2の概要、トークン決済v2でできること、利用イメージ、トークン決済v1との比較について説明します。
トークン発行後の決済に関する仕様は、各接続方式(プロトコルタイプ/モジュールタイプ/OpenAPIタイプ)のリファレンスを参照ください。
本リファレンスのサンプルコードについて、実装にあたっては加盟店様にて十分に検証を行ってください。
用語 | 説明 |
---|---|
加盟店様 | PGマルチペイメントサービスを利用する貴社を指します。 |
お客様 | 加盟店様からサービス・物品の提供を受ける、最終利用者を指します。 |
カード情報 | カード会員データ(クレジットカード番号、クレジットカード会員名、有効期限)および機密認証データ(CAV2/CVC2/CVV2/CIDいわゆるセキュリティコード)を指します。 |
MPクレカトークン | 当サービス標準のカード情報トークンを指します。 |
PCI DSS | Payment Card Industry Data Security Standard の略。データセキュリティの国際基準です。 |
トークン決済v1 | 従来の「トークン決済」を指します。 トークン決済v1のリファレンスはこちら トークン決済v1のリファレンスのログイン情報はこちらのFAQページを参照してください。 |
トークン決済v2 | 本リファレンスで説明する新しいトークン決済を指します。 |
クレジットカードでの決済を取り扱う加盟店様は、 PCI DSSに準拠するか、カード情報の「非保持化」が必要です。 カード情報をトークン化すると、加盟店様はお客様のカード情報を通過、処理、保存することなく決済ができ、「非保持化」を実現できます。 また、Google Payで支払いをする際に必要なPayment tokenを簡単に取得できる機能も提供します。
当サービスはお客様のカード情報を直接受け取り、解読不能な文字列「MPクレカトークン」に置き換えます。 加盟店様はMPクレカトークンを受け取り、加盟店様サーバー上で安全に処理ができます。 カード情報を保管し、次回の支払い時に利用したい場合は、当サービスの「カード登録」機能をお使いください。
MPクレカトークンが使える決済手段
MPクレカトークンは、当サービスの以下決済手段で利用可能です。詳細については後続のAPI処理を参照ください。 本リファレンスではMPクレカトークンの仕様のみ扱います。
接続方式 | 決済手段 |
---|---|
OpenAPIタイプ | クレカ払い |
プロトコルタイプ モジュールタイプ |
クレジットカード決済 クレジットカード決済 自動売上 多通貨クレジット カード決済(DCC) 不正防止サービス(ReD Shield) |
トークン決済v2がどのようにカード情報を扱うかを解説します。
お客様のブラウザまたはネイティブアプリから当サービスへ直接カード情報を送信することで加盟店様サーバーはカード情報非保持を実現できます。
MPクレカトークン発行後、決済処理やカード情報の登録を行います。
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8'
}
}
}%%
sequenceDiagram
actor お客様
participant device as ブラウザ<br>ネイティブアプリ
participant 加盟店様サイト
participant 当サービス
お客様->>device: カード情報入力
rect rgba(170, 202, 222, 0.2)
Note over device: カード情報のトークン化
device->>当サービス: 当サービスへカード情報送信
当サービス-->>device: トークン化して返却
device->>加盟店様サイト: MPクレカトークンを送信
end
加盟店様サイト->>当サービス: MPクレカトークンを利用したAPI実行
Note over 当サービス: MPクレカトークンを復号化し処理
トークン決済v1(/ext/js/token.js もしくは /ext/api/credit/getToken API)は引き続き利用できますが、2027年4月以降にサポートを終了する予定です。
ただし、新たな脆弱性の登場やPCI DSSの要件が変更になる等の理由によりサポート終了時期が早まる可能性がありますので、より便利になった「トークン決済v2」への移行を推奨します。
どちらの方式で取得したトークンでも、後続のAPI処理のパラメーターに設定できます。
機能・特徴 | トークン決済v1 | トークン決済v2 |
---|---|---|
JavaScript版のパス | /ext/js/token.js | /payment/js/mp-token.js |
API版のエンドポイント | /ext/api/credit/getToken | /payment/CreateToken.json |
npmパッケージ公開 | ✖ | ✔ |
ESモジュール対応 | ✖ | ✔ |
TypeScript対応 | ✖ | ✔ |
React、Vue.js対応 | ✖ | ✔ |
セキュリティ | ✔ | ✔✔✔ |
フォームのiframe対応 | ✖ | ✔ |
Google Pay対応 | ✖ | ✔ |
API版のJSON対応 | ✖ | ✔ |
iOS、Android SDK対応 | ✖ | ✖ |
トークン決済v2では安全性を高めるために以下の仕様変更がされています。トークン決済v1から移行する際は加盟店様側も合わせて対応をお願いします。
返却するマスク済みカード番号
トークン決済v1では、管理画面にてマスクレベルを変更できましたが、トークン決済v2で返却する値には適用されません。
トークン決済v2で返却するカード番号のマスクレベルは上6桁、下4桁の表示で固定です。
MPクレカトークン利用範囲
トークン決済v2で発行したトークンは、発行時の認証情報のショップIDが属するサイトID内のショップのみが後続のAPI処理で利用できます。
発行したトークンの有効期間はどちらで発行しても変わりません。
以下の図の例では、ショップAの認証情報で発行したトークンはショップA、ショップB、ショップCでは利用できますが、
異なるサイトに属するショップD、ショップEでは利用できません。
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8',
'lineColor': '#6A7FAB'
}
}
}%%
graph TD
A(サイト1)---B[ショップA]
A---C[ショップB]
A---D[ショップC]
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8',
'lineColor': '#6A7FAB'
}
}
}%%
graph TD
A(サイト2)---B[ショップD]
A---C[ショップE]
init
、getToken
を利用する場合はこれまで通りです。トークン決済v2を利用するために、以下のライブラリを提供していますので、加盟店様の環境や用途に応じて選択してください。 それぞれの特徴については以下の通りです。
ライブラリ | インストール | 対応環境 | 互換性*1 | 特徴 |
---|---|---|---|---|
MpToken.js | 直接読み込み | ブラウザ ネイティブアプリ内の WebView |
あり | 当サービスが提供するJavaScriptライブラリです。 加盟店様の画面は自由にデザインできます。 |
ESモジュール MpToken.js | npm@mul-pay/mptoken-js |
ブラウザ ネイティブアプリ内の WebView |
なし | 当サービスが提供するJavaScriptライブラリです。 加盟店様の画面は自由にデザインできます。 型定義に対応しています。 |
React MpToken.js | npm@mul-pay/mptoken-react-js |
ブラウザ ネイティブアプリ内の WebView |
なし | 上記JavaScriptをReact Nativeアプリケーション から利用するためのコンポーネントです。 型定義に対応しています。 |
Vue MpToken.js | npm@mul-pay/mptoken-vue-js |
ブラウザ ネイティブアプリ内の WebView |
なし | 上記JavaScriptをVueアプリケーション から利用するためのコンポーネントです。 型定義に対応しています。 |
Web API | N/A | ネイティブアプリ | N/A | 当サービスが提供するWeb APIです。 テスト環境以外では加盟店様サーバーサイド から利用しないでください。 |
*1:トークン決済v1のJavaScriptメソッドinit
、getToken
をサポートします。
こちらのテスト環境申し込みページからテストアカウントの即時発行が可能です。 登録が完了すると申し込み時のメールアドレスにショップ管理画面のログイン情報が届きます。 ショップ管理画面にログインできることを確認し、トークン決済v2を利用するための認証情報を登録します。
トークン決済v2の認証情報は以下の2つのデータを指します。
データ名 | 用途 |
---|---|
公開鍵 | カード情報を暗号化するための公開鍵です。 |
APIキー | トークン化リクエストを当サービスで認証するための情報です。 |
トークン決済v2の利用にあたり、事前にショップ管理画面にて認証情報を登録する必要があります。 ショップ管理画面の「都度決済」->「クレジットカード」->「設定」ページを開き、「MPクレカトークン認証情報」メニューに進み、「登録」ボタンを押して認証情報を発行します。 登録された「公開鍵」と「APIキー」は、組み込み時に設定します。
テスト環境と本番環境を用意しています。 各環境はFQDN(絶対ドメイン名)で区別され、認証情報やトークンのデータは共用されません。 テスト環境での確認を終えて商用利用を開始する際は、以下の対応をお願いします。
src
に指定するURLを本番用のURLに更新productionMode
をtrue
に設定環境 | 目的 | JavaScriptのFQDN | Web APIのFQDN |
---|---|---|---|
テスト環境 | 接続を確認する | stg.static.mul-pay.jp | stg.token.mul-pay.jp |
本番環境 | 商用の取引を実行する | static.mul-pay.jp | token.mul-pay.jp |
発行されたトークンは有効期限を過ぎるか、後続のAPI処理で利用すると無効になります。 ただし、OpenAPIタイプのカード詳細情報取得API(getCardDetails)で利用しても無効になりません。 有効期限は発行した時点から30分ですが、予告なしに変更される場合があります。 実際の値はトークン発行時のレスポンスパラメーターの「MPクレカトークン有効期限」で確認できます。
加盟店様のフロントエンドで受け取ったMPクレカトークンは、加盟店様サーバーサイドでの当サービスAPI呼び出し時に設定します。 対応するAPIは以下の通りです。 詳細については各リファレンスを参照ください。 マルペイDocsの利用方法はこちらのFAQページを参照してください。
接続方式 | 決済手段 | 対応するAPI | リファレンス |
---|---|---|---|
OpenAPIタイプ | クレカ払い | 都度支払い 有効性確認 カード登録 カード詳細情報取得*1 | OpenAPIタイプ APIリファレンス |
プロトコルタイプ モジュールタイプ | クレジットカード決済 | 決済実行 カード登録/更新 カード属性照会 | マルペイDocs クレジットカード決済 |
クレジットカード決済 自動売上 | 自動売上定義登録 | マルペイDocs クレジットカード決済 自動売上関連 | |
多通貨クレジット カード決済(DCC) | 決済実行 カード登録/更新 カード属性照会 | マルペイDocs 多通貨クレジット カード決済(DCC) | |
不正防止サービス (ReD Shield) | 不正審査 | マルペイDocs 不正防止サービス (ReD Shield) |
*1:APIでMPクレカトークンを利用してもトークンは無効になりません。
Elements機能とは、弊社が提供するカード情報の入力フォームを利用してトークン化する機能です。
トークン決済v1では、加盟店様が設置した入力フォームを経由してトークン化していました。
どちらも加盟店様のカード情報非保持を実現しますが、Elements機能はiframeを通じて弊社サーバー側でカード情報を受け付けます。
Elements機能に対応している入力フォームは以下の3つです。
これらのフォームは弊社サーバー上で動作するため、加盟店様が用意するスタイル(CSSファイル、styleタグ)は適用できません。 スタイルを変更する場合は、フォーム生成時のオプションで設定します。
Elements機能に対応している組み込み方法は以下の通りです。
詳細な組み込み方法についてはElementsによるカード情報入力フォームの生成を参照ください。
テスト環境で利用可能なカード番号は、マルペイDocsのテストカード一覧ページを参照してください。
マルペイDocsのログイン情報はこちらのFAQページを参照してください。
トークン決済v2を利用するための手段として、JavaScriptライブラリMpToken.js
を提供しています。
以下のいずれかの方法でJavaScriptを読み込んでください。
利用 方法 |
スクリプトを読み込む | ESモジュール MpToken.js | Vue MpToken.js | React MpToken.js |
---|---|---|---|---|
概要 | CDNからスクリプトを読み込む方法です。scriptタグをHTMLファイルに追加することで利用できます。 |
npmパッケージを利用してMpToken.js を読み込みます。IDE上での補完機能が利用できます。Vue MpToken.js、React MpToken.jsを利用することでVue.js、Reactと組み合わせて利用できます。 それぞれのSDKはCDN読み込みの MpToken.js を内部で読み込みます。
|
||
機能 |
|
npmパッケージを利用してMpToken.js
をインストールします。
npm install --save @mul-pay/mptoken-js
import { loadMulpay } from '@mul-pay/mptoken-js'
npm install --save @mul-pay/mptoken-vue-js
import VueMultiPayment from '@mul-pay/mptoken-vue-js';
npm install --save @mul-pay/mptoken-react-js
import { Elements } from "@mul-pay/mptoken-react-js";
import { LoadMulpay, MultiPayment } from "@mul-pay/mptoken-js";
HTMLのhead
要素にスクリプトを追加してMpToken.js
を読み込みます。
スクリプトとして追加することでMultiPayment
オブジェクトが使用できます。MpToken.js
は常に当サービスで提供するURLから読み込んでください。
テスト環境と本番環境を用意しています。
テスト環境での確認を終えて商用利用を開始する際は、src
に指定するURLを切り替えてください。
テスト環境
<script src="https://stg.static.mul-pay.jp/payment/js/mp-token.js"></script>
本番環境
<script src="https://static.mul-pay.jp/payment/js/mp-token.js"></script>
MpToken.js
を利用することでJavaScriptで簡単にクレジットカード情報をトークン化できます。Multipayment.init()
で初期化を行い、MPクレカトークンを取得したいタイミングでMultipayment.getToken()
を行ってください。
MpToken.js
を利用しカード情報をトークン化して都度決済を行うシーケンス例%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8'
}
}
}%%
sequenceDiagram
actor お客様
participant お客様ブラウザ
participant 加盟店様サイト
participant 当サービス
お客様ブラウザ->>お客様ブラウザ: Multipayment.init()
お客様->>お客様ブラウザ: カード情報入力
お客様ブラウザ->>当サービス: Multipayment.getToken()
当サービス-->>お客様ブラウザ:
お客様ブラウザ->>加盟店様サイト: MPクレカトークンを送信
加盟店様サイト->>当サービス: (OpenAPIタイプ)クレカ払い 都度払い<br>(プロトコルタイプ)決済実行
Multipayment.init('tshop00000001'); // ショップID
Multipayment.getToken(
{
cardno: '4111111111111111', // カード番号
expire: '201501', // カード有効期限
securitycode: '111', // セキュリティコード
holdername: 'SOME HOLDER', // カード名義人
tokennumber: '5' // MPクレカトークン発行数
}, someCallbackFunction // MPクレカトークン取得後に実行するコールバック関数
);
// MPクレカトークン取得後に呼び出すコールバック関数を定義する
function someCallbackFunction ( result ){
// 処理結果コードが'000'以外の時はエラーのためダイアログを表示する
if( result.resultCode != '000' ){
window.alert('購入処理中にエラーが発生しました')
} else {
// 予め購入フォームに用意したtokenフィールドに値を設定
document.getElementById('token').value = result.tokenObject.token
// フォームをsubmitして購入処理を進める
document.getElementById('purchaseform').submit()
}
}
Multipayment
オブジェクトを初期化するメソッドです。Multipayment
オブジェクトの機能を利用するために必要です。
※npmパッケージを利用する場合は、loadMulpay()を呼び出してください。
引数 | 説明 |
---|---|
apiKey |
ショップID |
MPクレカトークンを取得するメソッドです。
MPクレカトークン取得後にMPクレカトークンを含むresult
オブジェクトを引数callback
に渡してコールバック関数を呼び出します。
result
オブジェクトを参照することでMPクレカトークンを利用できます。
引数 | 説明 |
---|---|
card |
object カード情報を指定します。パラメータは以下を参照ください。 |
callback |
function MPクレカトークン取得後に呼び出したい関数を指定してください。この関数には、MPクレカトークンを受け取るための result 引数が渡されます。※無名関数は使用できません。 ※関数名指定の許可文字種は以下の通りです。 半角英数字(a-zA-Z0-9) アンダースコア(_) ピリオド(.) |
card
オブジェクトMultipayment.getToken(card, callback)
の第一引数card
オブジェクトにはカード情報を指定します。
以下の項目を設定してください。
項目 | 説明 |
---|---|
cardno required |
string カード番号ハイフンなし/半角数字で設定します。 |
expire required |
string 有効期限半角数字で YYMM またはYYYYMM 形式で設定します。 |
securitycode |
string セキュリティコード3または4桁の数字で設定します。 設定しない場合、セキュリティコードを利用せずに決済します。 |
holdername |
string カード名義人設定しない場合、カード名義人を取引に記録しません。 3Dセキュア認証利用時には必ず設定してください。 未設定でもエラーにはなりませんが、変更になる可能性があります。 利用可能記号: “ “ (半角スペース) , (コンマ) . (ピリオド) - (ハイフン)/ (スラッシュ) |
tokennumber |
string MPクレカトークン発行数発行するMPクレカトークンの数を1~10の数値で設定します。 Default: "1" |
result
オブジェクトMultipayment.getToken(card, callback)
でコールバック関数を呼び出す際に、
引数としてresult
オブジェクトを渡します。result
オブジェクトのデータ構造は以下の通りです。
項目 | 説明 | |
---|---|---|
resultCode |
string 処理結果コード複数のエラーが発生した場合、最初の1つが設定されます。 |
|
tokenObject | object |
|
token |
string MPクレカトークン文字列・配列tokennumber を指定した場合、配列になります。
|
|
toBeExpiredAt |
string MPクレカトークン有効期限詳細はトークンの有効期間を参照ください。 yyyy-mm-dd-HH-MM-SS 形式で設定します。
|
|
maskedCardNo |
string マスク済みカード番号 |
|
isSecurityCodeSet |
boolean セキュリティコード設定フラグMPクレカトークン取得時にセキュリティコードが設定された事を表すフラグです。 true の場合セキュリティコード設定ありとされます。
|
{
"resultCode": "000",
"tokenObject": {
"token": "a33c8bec609ffc75726249d8d82286d529bd1deb973119cf497eeb54610ab9d2",
"toBeExpiredAt": "2016-09-26-17-56-38",
"maskedCardNo": "411111******1111",
"isSecurityCodeSet": true
}
}
Multipayment
オブジェクトを初期化するメソッドです。Multipayment
オブジェクトの機能を利用するために必要です。
※npmパッケージを利用する場合は、loadMulpay()を呼び出してください。
引数 | 説明 |
---|---|
apiKey |
ショップID |
MPクレカトークンを取得するメソッドです。
MPクレカトークン取得後にMPクレカトークンを含むresult
オブジェクトを引数callback
に渡してコールバック関数を呼び出します。
result
オブジェクトを参照することでMPクレカトークンを利用できます。
引数 | 説明 |
---|---|
card |
object カード情報を指定します。パラメータは以下を参照ください。 |
callback |
function MPクレカトークン取得後に呼び出したい関数を指定してください。この関数には、MPクレカトークンを受け取るための result 引数が渡されます。※無名関数は使用できません。 ※関数名指定の許可文字種は以下の通りです。 半角英数字(a-zA-Z0-9) アンダースコア(_) ピリオド(.) |
card
オブジェクトMultipayment.getToken(card, callback)
の第一引数card
オブジェクトにはカード情報を指定します。
以下の項目を設定してください。
項目 | 説明 |
---|---|
cardno required |
string カード番号ハイフンなし/半角数字で設定します。 |
expire required |
string 有効期限半角数字で YYMM またはYYYYMM 形式で設定します。 |
securitycode |
string セキュリティコード3または4桁の数字で設定します。 設定しない場合、セキュリティコードを利用せずに決済します。 |
holdername |
string カード名義人設定しない場合、カード名義人を取引に記録しません。 3Dセキュア認証利用時には必ず設定してください。 未設定でもエラーにはなりませんが、変更になる可能性があります。 利用可能記号: “ “ (半角スペース) , (コンマ) . (ピリオド) - (ハイフン)/ (スラッシュ) |
tokennumber |
string MPクレカトークン発行数発行するMPクレカトークンの数を1~10の数値で設定します。 Default: "1" |
result
オブジェクトMultipayment.getToken(card, callback)
でコールバック関数を呼び出す際に、
引数としてresult
オブジェクトを渡します。result
オブジェクトのデータ構造は以下の通りです。
項目 | 説明 | |
---|---|---|
resultCode |
string 処理結果コード複数のエラーが発生した場合、最初の1つが設定されます。 |
|
tokenObject | object |
|
token |
string MPクレカトークン文字列・配列tokennumber を指定した場合、配列になります。
|
|
toBeExpiredAt |
string MPクレカトークン有効期限詳細はトークンの有効期間を参照ください。 yyyy-mm-dd-HH-MM-SS 形式で設定します。
|
|
maskedCardNo |
string マスク済みカード番号 |
|
isSecurityCodeSet |
boolean セキュリティコード設定フラグMPクレカトークン取得時にセキュリティコードが設定された事を表すフラグです。 true の場合セキュリティコード設定ありとされます。
|
{
"resultCode": "000",
"tokenObject": {
"token": "a33c8bec609ffc75726249d8d82286d529bd1deb973119cf497eeb54610ab9d2",
"toBeExpiredAt": "2016-09-26-17-56-38",
"maskedCardNo": "411111******1111",
"isSecurityCodeSet": true
}
}
Elements
を利用することでカード情報入力フォームを動的に生成できます。
iframeで生成されるため、カード情報の入力をより安全に行えます。
以下のような手順を行うことで、MPクレカトークンを取得できます。
Multipayment.createElements()
で初期化elements.create()
でカード情報入力フォームを生成し、入力フォームにしたいdiv要素にmountするmulpay.getTokenThroughIframe()
でMPクレカトークンを取得Vue.jsを使用する場合は、mptoken-vue-js
を使用してMPクレカトークンを取得します。
Vue.js サンプルコードを参照してください。
Reactを使用する場合は、mptoken-react-js
を使用してMPクレカトークンを取得します。
React サンプルコードを参照してください。
Elements
を利用しカード情報をトークン化して都度決済を行うシーケンス例%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8'
}
}
}%%
sequenceDiagram
actor お客様
participant お客様ブラウザ
participant 加盟店様サイト
participant 当サービス
お客様ブラウザ->>お客様ブラウザ: mulpay.createElements()で初期化
お客様ブラウザ->>お客様ブラウザ: elements.create()でカード情報入力フォームを生成
お客様ブラウザ->>お客様ブラウザ: elements.create()の返り値を入力フォームにしたいdiv要素にmountする
お客様->>お客様ブラウザ: カード情報入力
お客様ブラウザ->>当サービス: mulpay.getTokenThroughIframe()でMPクレカトークンを発行
当サービス-->>お客様ブラウザ:
お客様ブラウザ->>加盟店様サイト: MPクレカトークンを送信
加盟店様サイト->>当サービス: (OpenAPIタイプ)クレカ払い 都度払い<br>(プロトコルタイプ)決済実行
<!doctype html>
<html>
<head>
<title>MPクレカトークン生成フォーム(iframe)</title>
<script src="./useMpToken.js"></script>
</head>
<body>
<h1>MPクレカトークン生成フォーム(iframe)</h1>
<form action="#" method="post">
<label for="cardNumber">カード番号:</label>
<div id="any-wrapper-id1"></div>
<br /><br />
<label for="expiry">有効期限:</label>
<div id="any-wrapper-id2"></div>
<br /><br />
<label for="cvc">セキュリティコード:</label>
<div id="any-wrapper-id3"></div>
<br /><br />
<label for="name">名義人:</label>
<input type="text" id="name-input-id" />
<br />
<br />
<input type="button" id="submit-button" value="決済する" />
</form>
<div id="result"></div>
</body>
</html>
import { loadMulpay } from "@mul-pay/mptoken-js";
window.addEventListener("load", async () => {
const apiKey = "API_KEY"
const publicKey = "PUB_KEY"
const merchantIds = {
googlePayMerchantId: "01234567890123456789"
}
// Multipaymentオブジェクトを初期化する
const mulpay = await loadMulpay(apiKey, publicKey, merchantIds, true, false);
// カード情報入力フォーム(カード番号)のスタイルを設定する
const cardInputStyle = {
base: {
fontFamily: "'Noto Sans Japanese', sans-serif",
"::placeholder": {
color: "rgba(0, 0, 0, 0.54)",
},
caretColor: "#198FCC",
lineHeight: "28px",
},
invalid: {
color: "#9e2146",
},
};
// カード情報入力フォーム(有効期限)のスタイルを設定する
const expiryInputStyle = {
base: {
fontFamily: "'Noto Sans Japanese', sans-serif",
"::placeholder": {
color: "rgba(0, 0, 0, 0.54)",
},
caretColor: "#198FCC",
lineHeight: "28px",
},
invalid: {
color: "#9e2146",
},
};
// カード情報入力フォーム(セキュリティコード)のスタイルを設定する
const cvcInputStyle = {
base: {
fontFamily: "'Noto Sans Japanese', sans-serif",
"::placeholder": {
color: "rgba(0, 0, 0, 0.54)",
},
caretColor: "#198FCC",
lineHeight: "28px",
},
invalid: {
color: "#9e2146",
},
};
// カード情報入力フォームのタイプを設定する
const cardElementType = {
type: "cardNumber",
options: { style: cardInputStyle, placeholder: "hogehoge" },
};
const expiryInputType = {
type: "cardExpiry",
options: { style: expiryInputStyle },
};
const cvcInputType = {
type: "cardCvc",
options: { style: cvcInputStyle },
};
// カード情報入力フォームのラッパー要素を取得する
const elements = mulpay.createElements();
// カード情報入力フォームを作成する
const cardNumberInputElement = elements.create('cardNumber', { style: cardInputStyle, placeholder: 'hogehoge'} );
const expiryInputElement = elements.create('cardExpiry',{ style: expiryInputStyle });
const cvcInputElement = elements.create('cardCvc', { style: cvcInputStyle });
// カード情報入力フォームのラッパー要素を取得する
const cardNumberWrapperElement = document.getElementById('any-wrapper-id1');
const cardExpiryWrapperElement = document.getElementById('any-wrapper-id2');
const cardCvcWrapperElement = document.getElementById('any-wrapper-id3');
// カード情報入力フォームをラッパー要素にマウントする
cardNumberInputElement.mount(cardNumberWrapperElement);
expiryInputElement.mount(cardExpiryWrapperElement);
cvcInputElement.mount(cardCvcWrapperElement);
// カード情報入力フォームのラッパー要素を配列に格納する
const mulPayFormElements = [
cardNumberInputElement,
expiryInputElement,
cvcInputElement,
];
// 名義人入力フォームを取得する
const nameInputElement = document.getElementById("name-input-id");
const btn = document.getElementById("submit-button");
// 決済ボタンをクリックした時の処理を定義する
btn.addEventListener("click", (e) => {
// buttonを非活性にする
btn.setAttribute("disabled", "true");
const options = {
tokenNumber: 2,
};
// mulpayオブジェクトのgetTokenThroughIframeメソッドを呼び出します。
// このメソッドは、第一引数にフォーム要素、第二引数に名前の入力要素の値、第三引数にオプションを取ります。
mulpay
.getTokenThroughIframe(
mulPayFormElements[0],
nameInputElement.value,
options
)
// getTokenThroughIframeメソッドはPromiseを返すため、thenメソッドを使用して非同期処理の結果を取得します。
.then((response) => {
const resultElement = document.getElementById("result");
resultElement.innerHTML = JSON.stringify(response);
btn.setAttribute("disabled", "false");
cleanup();
});
});
const cleanup = () => {
mulPayFormElements.forEach(function (element) {
// カード情報入力フォームをアンマウントする
element.clear();
});
};
});
このセクションでは、Vue.jsを使用してMPクレカトークンを取得するサンプルを提供します。
Vue.jsを使用する場合、mptoken-vue-js
を使用してMPクレカトークンを取得します。また、createElements()
ではなく、Elements
コンポーネントを使用してカード情報入力フォームを生成することができるように構成されています。
main.ts
(またはmain.js
)でプラグインを登録します。
// main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import VueMultiPayment from '@mul-pay/mptoken-vue-js';
const app = createApp(App)
app.use(VueMultiPayment);
app.mount('#app');
usePaymentContext.ts
を作成し、以下のようなカスタムフックを実装します。このフックを使用することで、MultiPaymentElements
とMultiPayment
オブジェクトを取得できるようにします。
// usePaymentContext.ts
import { MultiPaymentElements, MultiPayment } from "@mul-pay/mptoken-js";
import { getCurrentInstance } from "vue";
export const usePaymentContext = (): { elements: MultiPaymentElements | undefined, multiPayment: MultiPayment | undefined } => {
const instance = getCurrentInstance();
const elements = instance?.appContext.config.globalProperties.$useElements();
const multiPayment = instance?.appContext.config.globalProperties.$useMultiPayment();
return { elements, multiPayment };
}
FormWrapper.vue
コンポーネントは、Elements
コンポーネントを使用してMPクレカトークンの初期化と設定を行います。
// FormWrapper.vue
<template>
<Elements :multiPayment="multiPayment">
<PaymentCardForm />
</Elements>
</template>
<script lang="ts" setup>
import { loadMulpay, MultiPayment } from "@mul-pay/mptoken-js";
import PaymentCardForm from "./PaymentCardForm.vue";
import { ref } from "vue";
let multiPayment = ref<MultiPayment | null>(null);
// VITE_MULPAY_API_KEY(MPクレカトークンのAPIキー), VITE_MULPAY_PUB_KEY(MPクレカトークンの公開鍵)を.envファイルに設定してください
const apiKey = import.meta.env.VITE_MULPAY_API_KEY || '';
const pubKey = import.meta.env.VITE_MULPAY_PUB_KEY || '';
const mulpayPromise = await loadMulpay(apiKey, pubKey);
if (mulpayPromise) {
multiPayment.value = mulpayPromise;
}
</script>
PaymentCardForm.vue
コンポーネントは、実際のカード情報入力フォームを実装します。このコンポーネントでは、mptoken-vue-js
が提供するCardNumberElement
、CardExpiryElement
、CardCvcElement
を使用してフォームを構築し、トークン取得処理を実装します。
CardNumberElement
(カード番号コンポーネント)CardExpiryElement
(有効期限コンポーネント)CardCvcElement
(セキュリティコードコンポーネント)下記のサンプルコードでは、CardNumberElement
、CardExpiryElement
、CardCvcElement
を使用したカード情報入力フォームを生成し、ボタンの押下によってgetTokenThroughIframe()
を呼び出しています。
// PaymentCardForm.vue
<template>
<div class="top">
<h1>MpToken.js Vueのサンプルコード</h1>
</div>
<div class="payment-container">
<div class="card-form">
<h2>カード情報</h2>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<label for="cardNumber">カード番号</label>
<div id="cardNumber" class="input-wrapper">
<CardNumberElement
:onBlur="() => logEvent('blur')"
:onChange="() => logEvent('change')"
:onFocus="() => logEvent('focus')"
:onReady="() => logEvent('ready')"
:options="{ style: styleObject }"
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="cardExpiry">有効期限</label>
<div id="cardExpiry" class="input-wrapper">
<CardExpiryElement
:onBlur="() => logEvent('blur')"
:onChange="() => logEvent('change')"
:onFocus="() => logEvent('focus')"
:onReady="() => logEvent('ready')"
:options="{ style: styleObject }"
/>
</div>
</div>
<div class="form-group">
<label for="cardCvc">セキュリティコード</label>
<div id="cardCvc" class="input-wrapper">
<CardCvcElement
:onBlur="() => logEvent('blur')"
:onChange="() => logEvent('change')"
:onFocus="() => logEvent('focus')"
:onReady="() => logEvent('ready')"
:options="{ style: cvcInputStyle, placeholder: '123' }"
/>
</div>
</div>
</div>
<div class="form-group">
<!-- カード名義人はElementsで提供しないため自前で設定する -->
<label for="cardholderName">カード名義人</label>
<div class="input-wrapper">
<input
id="cardholderName"
v-model="cardholderName"
type="text"
placeholder="カード名義人を入力してください"
/>
</div>
</div>
<button class="button-class" type="submit">トークンを取得する</button>
</form>
</div>
<div class="transaction-history">
<h3>トークン取得履歴</h3>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th class="timestamp">日時</th>
<th class="status">結果</th>
<th class="details">詳細</th>
</tr>
</thead>
<tbody>
<tr v-for="(transaction, index) in transactions" :key="index">
<td class="timestamp">{{ transaction.timestamp }}</td>
<td class="status" :class="transaction.status">{{ transaction.status }}</td>
<td class="details">
<div class="details-content">{{ transaction.details }}</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { usePaymentContext } from "../utils/usePaymentContext";
import { ErrorResponse, TokenObj, } from "@mul-pay/mptoken-js";
/**
* mptoken-jsのiframe部分のスタイルを設定するオブジェクト
*/
const styleObject = {
base: {
fontFamily: "'Noto Sans Japanese', sans-serif",
"::placeholder": {
color: "rgba(0, 0, 0, 0.54)",
},
caretColor: "#198FCC",
lineHeight: "28px",
},
invalid: {
color: "rgba(0, 0, 0, 0.87)",
},
};
const cvcInputStyle = {
base: {
fontFamily: '\'Noto Sans Japanese\', sans-serif',
'::placeholder': {
color: 'rgba(0, 0, 0, 0.54)',
},
color:'#660',
caretColor: '#FF8FCC',
},
invalid: {
color: 'rgba(0, 0, 0, 0.87)',
}
};
// トークン発行時のオプション
// tokenNumber: トークンの発行数を1~10の範囲で指定
const cardOptions = ref({
tokenNumber: "1",
});
// usePaymentContextからelementsとmultiPaymentを取得
const { elements, multiPayment } = usePaymentContext();
const result = ref<TokenObj | null>(null);
const errorMessage = ref<ErrorResponse | null>(null);
const transactions = ref<Array<{ timestamp: string; status: string; details: string }>>([]);
const cardholderName = ref("");
const logEvent = (name: string) => (event: Event) => {
console.log(`[${name}]`, event);
};
/**
* トークン発行処理を実行する
* @param event
*/
const handleSubmit = async (event: Event) => {
event.preventDefault();
if (!multiPayment || !elements) {
return;
}
const cardNumberElement = elements.getElement("cardNumber");
if (cardNumberElement === null) return;
const tokenResponse = await multiPayment.getTokenThroughIframe(
cardNumberElement,
cardholderName.value, // カード名義人の値を渡す
cardOptions.value
);
const timestamp = new Date().toLocaleString();
if (tokenResponse.result === "success") {
result.value = (tokenResponse as TokenObj);
errorMessage.value = null;
transactions.value.unshift({
timestamp,
status: "success",
details: `カード名義人: ${cardholderName.value}, ${JSON.stringify(tokenResponse as TokenObj)}`
});
} else {
errorMessage.value = (tokenResponse as ErrorResponse);
transactions.value.unshift({
timestamp,
status: "error",
details: JSON.stringify(tokenResponse as ErrorResponse)
});
}
};
</script>
<style scoped>
h1 {
font-size: 2rem;
font-weight: bold;
margin-bottom: 2rem;
color: #333;
}
.top{
max-width: 1600px;
margin: 2rem auto;
margin-left: 6rem;
text-align: left;
}
.payment-container {
max-width: 1600px;
margin: 2rem auto;
margin-left: 6rem;
gap: 2rem;
}
.card-form {
max-width: 400px;
max-height: 600px;
margin-bottom: 3rem;
flex: 1 1 300px;
padding: 2rem;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.transaction-history {
flex: 1 1 300px;
padding: 2rem;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h2, h3 {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 1.5rem;
color: #333;
}
.form-group {
margin-bottom: 1rem;
}
.form-row {
display: flex;
gap: 1rem;
}
.form-row .form-group {
flex: 1;
}
label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.875rem;
color: #555;
}
.input-wrapper {
height: 1rem;
min-height: 1rem;
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.3s ease;
}
input[type="text"] {
z-index: 5;
position: relative;
width: 100%;
height: auto;
width: 100%;
border: none;
outline: none;
font-family: inherit;
font-size: inherit;
}
.button-class {
z-index: 10;
position: relative;
}
.input-wrapper:focus-within {
border-color: #4a90e2;
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2);
}
button {
z-index: 5;
display: block;
width: 100%;
padding: 0.75rem;
margin-top: 1.5rem;
background-color: #4a90e2;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #3a7bc8;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 0.5rem;
text-align: left;
border-bottom: 1px solid #eee;
vertical-align: top;
}
th {
background-color: #f8f8f8;
font-weight: bold;
}
.timestamp {
width: 25%;
}
.status {
width: 15%;
}
.details {
width: 60%;
}
.details-content {
white-space: pre-wrap;
word-break: break-word;
}
.success {
color: #2e7d32;
}
.error {
color: #d32f2f;
}
</style>
このセクションでは、React を使用してMPクレカトークンを取得するサンプルを提供します。
React を使用する場合、mptoken-react-js
を使用してMPクレカトークンを取得します。また、createElements()
ではなく、Elements
コンポーネントを使用してカード情報入力フォームを生成することができるように構成されています。
FormWrapper.tsx
でElements
コンポーネントを使用した初期化用のコンポーネントを作成します。このコンポーネントは、MPクレカトークンの初期化と設定を行います。
// FormWrapper.tsx
import { useEffect, useState } from 'react';
import { Elements } from '@mul-pay/mptoken-react-js';
import { MultiPayment } from '@mul-pay/mptoken-js';
import Card from './card';
const apiKey = import.meta.env.VITE_MULPAY_API_KEY || '';
const pubKey = import.meta.env.VITE_MULPAY_PUB_KEY || '';
const merchantIds = {
googlePayMerchantId: '01234567890123456789',
};
export default function FormWrapper() {
const [mulpayPromise, setMulpayPromise] = useState<Promise<MultiPayment | null> | null>(null);
useEffect(() => {
let isMounted = true;
const loadMulpayModule = async () => {
try {
const { loadMulpay } = await import('@mul-pay/mptoken-js');
if (isMounted) {
const promise = loadMulpay(apiKey, pubKey, merchantIds, true, false);
setMulpayPromise(promise);
}
} catch (error) {
console.error('Failed to load mulpay module', error);
}
};
loadMulpayModule();
return () => {
isMounted = false;
};
}, []);
return (
<Elements multiPayment={mulpayPromise}>
<Card />
</Elements>
);
}
Card.tsx
を作成し、実際のカード情報入力フォームを実装します。このコンポーネントでは、mptoken-react-js
が提供するCardNumberElement
、CardExpiryElement
、CardCvcElement
を使用してフォームを構築し、トークン取得処理を実装しています。
// Card.tsx
import { useState } from "react";
import {
CardNumberElement,
CardCvcElement,
CardExpiryElement,
useElements,
useMultiPayment,
} from "@mul-pay/mptoken-react-js";
import {
ErrorResponse,
MultiPaymentEventType,
TokenObj,
TokenResponse,
} from "@mul-pay/mptoken-js";
const styleObject = {
style: {
base: {
fontSize: "16px",
color: "#32325d",
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: "antialiased",
"::placeholder": {
color: "#aab7c4",
},
padding: "12px",
},
invalid: {
color: "#fa755a",
},
},
};
const styles = `
.container {
width: 1024px;
min-height: 100vh;
background-color: #f3f4f6;
padding: 2rem 1rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.card-wrapper {
width: 100%;
max-width: 480px;
margin: 0 auto;
padding: 0 1rem;
box-sizing: border-box;
}
.card {
background-color: white;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
width: 100%;
box-sizing: border-box;
}
.form-container {
width: 100%;
}
.form-section {
width: 100%;
}
.form {
display: flex;
flex-direction: column;
gap: 1.5rem;
width: 100%;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
width: 100%;
}
@media (max-width: 480px) {
.form-row {
grid-template-columns: 1fr;
}
}
.label {
display: block;
font-size: 0.875rem;
font-weight: 500;
color: #374151;
margin-bottom: 0.25rem;
}
.input-wrapper {
width: 100%;
margin-top: 0.25rem;
}
.input-field {
width: 100%;
padding: 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background-color: white;
box-sizing: border-box;
}
.input-field:focus-within {
border-color: #6366f1;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
}
.text-input {
width: 100%;
padding: 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
font-size: 0.875rem;
line-height: 1.25rem;
box-sizing: border-box;
}
.text-input:focus {
outline: none;
border-color: #6366f1;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
}
.error-message {
width: 100%;
margin-top: 1rem;
padding: 1rem;
border-radius: 0.375rem;
background-color: #fef2f2;
box-sizing: border-box;
}
.error-text {
font-size: 0.875rem;
color: #dc2626;
word-break: break-all;
}
.submit-button {
width: 100%;
display: flex;
justify-content: center;
padding: 0.875rem 1.5rem;
border: none;
border-radius: 0.375rem;
background-color: #4f46e5;
color: white;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
}
.submit-button:hover:not(:disabled) {
background-color: #4338ca;
}
.submit-button:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.5);
}
.submit-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.token-display {
margin-top: 1.5rem;
padding: 1rem;
background-color: #f9fafb;
border-radius: 0.375rem;
width: 100%;
box-sizing: border-box;
}
.token-text {
font-size: 0.75rem;
overflow: auto;
white-space: pre-wrap;
word-break: break-all;
}
* {
box-sizing: border-box;
}
`;
const Card = () => {
const elements = useElements();
const mulpay = useMultiPayment();
const [cardHolderName, setCardHolderName] = useState<string>("");
const [tokenObject, setTokenObject] = useState<TokenObj | null>(null);
const [errorResponse, setErrorResponse] = useState<ErrorResponse | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [cardNumberError, setCardNumberError] = useState<boolean>(false);
const [expiryError, setExpiryError] = useState<boolean>(false);
const [cvcError, setCvcError] = useState<boolean>(false);
const handleSubmit = () => {
if (!mulpay || !elements) return;
const cardElement = elements.getElement("cardNumber");
if (cardElement === null) return;
setLoading(true);
const options = { tokenNumber: "2" };
mulpay
.getTokenThroughIframe(cardElement, cardHolderName, options)
.then((tokenResponse: TokenResponse) => {
if (tokenResponse.result === "success") {
setErrorResponse(null)
setTokenObject(tokenResponse as TokenObj);
} else {
setErrorResponse(tokenResponse as ErrorResponse);
}
})
.finally(() => {
setLoading(false);
});
};
interface PaymentEvent {
elementType: 'cardNumber' | 'cardExpiry' | 'cardCvc';
invalid?: boolean;
}
const logEvent = (name: MultiPaymentEventType) => (event: PaymentEvent) => {
console.log(`[${name}]`, JSON.stringify(event, null, 2));
if (name !== "change") return;
const errorHandlers = {
cardNumber: setCardNumberError,
cardExpiry: setExpiryError,
cardCvc: setCvcError,
};
const setError = errorHandlers[event.elementType];
if (setError) {
setError(event.invalid ?? false);
}
};
return (
<>
<style>{styles}</style>
<div className="container">
<div className="card-wrapper">
<div className="card">
<div className="form-container">
<div className="form-section">
<form className="form">
<div className="form-group">
<label className="label" htmlFor="cardNumber">
カード番号
</label>
<div className="input-wrapper">
<div className="input-field">
<CardNumberElement
id="cardNumber"
onBlur={logEvent("blur")}
onChange={logEvent("change")}
onFocus={logEvent("focus")}
options={styleObject}
/>
</div>
</div>
</div>
<div className="form-row">
<div className="form-group">
<label className="label" htmlFor="expiry">
有効期限
</label>
<div className="input-wrapper">
<div className="input-field">
<CardExpiryElement
id="expiry"
onBlur={logEvent("blur")}
onChange={logEvent("change")}
onFocus={logEvent("focus")}
onReady={logEvent("ready")}
options={styleObject}
/>
</div>
</div>
</div>
<div className="form-group">
<label className="label" htmlFor="cvc">
セキュリティコード
</label>
<div className="input-wrapper">
<div className="input-field">
<CardCvcElement
id="cvc"
onBlur={logEvent("blur")}
onChange={logEvent("change")}
onFocus={logEvent("focus")}
onReady={logEvent("ready")}
options={styleObject}
/>
</div>
</div>
</div>
</div>
<div className="form-group">
<label className="label" htmlFor="cardHolderName">
カード名義
</label>
<input
id="cardHolderName"
required
placeholder="TARO YAMADA"
value={cardHolderName}
onChange={(e) => setCardHolderName(e.target.value)}
className="text-input"
/>
</div>
{errorResponse && (
<div className="error-message">
<div className="error-text">
{JSON.stringify(errorResponse, null, 2)}
</div>
</div>
)}
<button
type="button"
onClick={handleSubmit}
disabled={!mulpay || loading}
className="submit-button"
>
{loading ? "処理中..." : "支払う"}
</button>
{/* setCardNumberErrorである場合はメッセージを表示する */}
{cardNumberError && (
<div className="error-message">
<div className="error-text">
カード番号が正しくありません
</div>
</div>
)}
{/* setExpiryErrorである場合はメッセージを表示する */}
{expiryError && (
<div className="error-message">
<div className="error-text">
有効期限が正しくありません
</div>
</div>
)}
{/* setCvcErrorである場合はメッセージを表示する */}
{cvcError && (
<div className="error-message">
<div className="error-text">
セキュリティコードが正しくありません
</div>
</div>
)}
</form>
</div>
</div>
{tokenObject && (
<div className="token-display">
<pre className="token-text">
{JSON.stringify(tokenObject, null, 2)}
</pre>
</div>
)}
</div>
</div>
</div>
</>
);
};
export default Card;
App.tsx
でFormWrapper
コンポーネントを使用して、実際のカード情報入力フォームを表示します。
import "./App.css";
import FormWrapper from "./components/FormWrapper";
function App() {
return (
<>
<FormWrapper />
</>
);
}
export default App;
loadMulpayはnpmパッケージを利用してMpToken.js
を読み込む際に使用する関数です。
引数 | 説明 |
---|---|
apiKey required |
string APIキー(認証情報を参照ください) |
publicKey required |
string 公開鍵(認証情報を参照ください) |
merchantIds |
object Google PayのMerchant情報 |
permitToSendFingerprint |
boolean ブラウザーフィンガープリントの送信を許可するかdefault: true(許可する) |
productionMode |
boolean 本番の商用環境かテスト環境を使用するかdefault: false(テスト環境) |
import { loadMulpay } from "@mul-pay/mptoken-js";
const apiKey = "API_KEY"
const publicKey = "PUB_KEY"
const merchantIds = {
googlePayMerchantId: "01234567890123456789"
}
const mulpay = await loadMulpay(apiKey, publicKey, merchantIds, true, false);
Multipayment.createElements()
は、Elements
オブジェクトを返すメソッドです。
このメソッドを使用することで、Elements
オブジェクトを利用できます。
指定されたtype
のElements
オブジェクトを返すメソッドです。
生成されたElements
オブジェクトは、指定されたdiv
要素にmount
することで、カード情報入力フォームを生成します。
引数 | 説明 |
---|---|
type required |
string ・cardNumber :カード番号 ・ cardExpiry :有効期限 ・ cardCvC :CVC |
options |
object オプション。Elemetns で生成されたinputフォームのstyle 、disabled 、placeholder を設定できます。style では各状態 (base, complete, empty, invalid, forcus) のCSSが設定できます。 |
const cardInputStyle = {
base: {
fontFamily: "'Noto Sans Japanese', sans-serif",
caretColor: "#198FCC",
lineHeight: "28px",
"::placeholder": {
color: "rgba(0, 0, 0, 0.54)",
},
},
invalid: {
color: "#9e2146",
},
};
const cardNumberInputElement = elements.create('cardNumber', { style: cardInputStyle, placeholder: 'hogehoge'} );
const cardNumberWrapperElement = document.getElementById('any-wrapper-id1');
cardNumberInputElement.mount(cardNumberWrapperElement);
options
の指定方法についてoptions
はCSSプロパティのマッピングを指定するオブジェクトで、style
プロパティにはCSSプロパティに加えて、Elements
でサポートする状態や疑似クラス・疑似要素を指定できます。
状態には、base
, complete
, empty
, invalid
, focus
の状態を指定できます。
疑似クラス・疑似要素は:hover
, :focus
, ::placeholder
, ::selection
, :-webkit-autofill
, :disabled
, ::-ms-clear
を指定できます。
上記のExampleを参考にしてください。
CSSプロパティ | 型 | 説明 |
---|---|---|
backgroundColor | string | 背景色 |
color | string | テキスト色 |
caretColor | string | キャレット色 |
fontFamily | string | フォントファミリー 利用可能なフォントは、お客様のデバイスにインストールされているフォントに依存します。Webフォントは使えません。 |
fontSize | string | フォントサイズ |
fontSmoothing | string | フォントのスムージング |
fontStyle | string | フォントスタイル |
fontVariant | string | フォントバリアント |
fontWeight | string or number | フォントの太さ |
iconColor | string | アイコンの色 |
lineHeight | string | 行の高さ |
letterSpacing | string | 文字間隔 |
textAlign | string | テキストの配置 |
padding | string | パディング |
textDecoration | string | テキストの装飾 |
textShadow | string | テキストの影 |
textTransform | string | テキストの変形 |
elments.create
で生成したフォーム要素を指定して、MPクレカトークンを取得するメソッドです。Multipayment.getToken(card, callback)
とは異なり、elements.create
で生成したフォームに入力された情報を利用してMPクレカトークンを取得します。
引数 | 説明 | |
---|---|---|
element |
object elements.create(type,options) の返り値を指定する
|
|
cardholderName |
string カード名義人設定しない場合、カード名義人を取引に記録しません。 3Dセキュア認証利用時には必ず設定してください。 未設定でもエラーにはなりませんが、変更になる可能性があります。 |
|
options |
object オプションtokenNumber を設定できます。
|
|
tokenNumber |
string MPクレカトークン発行数発行するトークンの数を1~10の間で設定します。 default: "1"
|
MpToken.js
では Google Payトークンを取得できる機能を提供します。
カード情報は当サービスではなくGoogle Payによってトークン化されます。
作成したトークンを当サービスに送信することで決済ができます。
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#f0f2f5',
'primaryTextColor': '#001C40',
'noteBkgColor': '#d9f4fc',
'noteTextColor': '#001C40',
'noteBorderColor': '#54C5E8'
}
}
}%%
sequenceDiagram
actor お客様
participant お客様ブラウザ
participant 加盟店様サイト
participant 当サービス
お客様ブラウザ->>お客様ブラウザ: mulpay.createPaymentRequest(Object)
お客様ブラウザ->>お客様ブラウザ: mulpay.checkAvailability()
お客様->>お客様ブラウザ: Google Payボタンをクリックして<br>支払いシートで支払いを行う
お客様ブラウザ->>お客様ブラウザ: mulpay.fetchEncryptedTokenObject(mulpay.createPaymentRequestの返り値)
お客様ブラウザ->>加盟店様サイト: Google Payのトークンを送信
加盟店様サイト->>当サービス: (OpenAPIタイプ)クレカ払い 都度払い<br>(プロトコルタイプ)決済実行
<!doctype html>
<html>
<head>
<title>Google Pay の利用サンプル</title>
<script async src="https://pay.google.com/gp/p/js/pay.js"></script>
<script type="module" src='./useMpToken.js'></script>
</head>
<body>
<h1>Google Pay</h1>
<!-- Google Payボタンを表示するためのラッパー要素 -->
<div id="google-pay-button-wrapper" style="display: none">
<!-- Google Payボタン -->
<button id="google-pay-btn">Let's get token</button>
</div>
<!-- トークン取得結果を表示するための要素 -->
<div id="result"></div>
</body>
</html>
import { loadMulpay } from "@mul-pay/mptoken-js"; // Multipaymentオブジェクトを初期化するためのメソッドをインポートする
// Google Payのトークンを取得するための引数を設定する
const argsForGoogle = {
merchantName: "merchant name", // 購入者を設定する
currency: "JPY", // 通貨を設定する
country: "JP", // 国を設定する
total: "1000", // 金額を設定する
};
window.addEventListener("load", async () => {
const apiKey = "ec9946c42bbbef17658f0bea238f8dacac8d91ab15071fdf4d7b8cce70ce1ed4"; // apiKeyを設定する
const publicKey = "pub_key"; // 公開鍵を設定する
const ids = {
googlePayMerchantId: "google_merchant_id",
}; // Google PayのmerchantIdを設定する
const mulpay = await loadMulpay(apiKey, publicKey, ids); // Multipaymentオブジェクトを初期化する
// Google Payの支払い情報を作成する
const paymentRequestForGoogle = mulpay.createPaymentRequest(argsForGoogle);
// Google Payが利用可能かどうかをチェックする
const { googlePayAvailable } = await mulpay.checkAvailability();
// Google Payが利用可能な場合、Google Payボタンを表示する
const togglePayButton = (googlePayAvailable) => {
if (googlePayAvailable) {
document.getElementById("google-pay-button-wrapper").style.display =
"block";
}
};
togglePayButton(googlePayAvailable);
/**
* Google Payボタンをクリックした時の処理
* Google Payのトークンを取得する
*/
const onClickForGoogle = async (e) => {
const encryptedTokenObject = await mulpay.fetchEncryptedTokenObject(
paymentRequestForGoogle
); // Google Payのトークンを取得する
};
const btn = document.getElementById("google-pay-btn"); // Google Payボタンを取得する
btn.addEventListener("click", onClickForGoogle); // Google Payボタンをクリックした時の処理を登録する
});
Google Payの支払い情報を作成するメソッドです。
引数 | 説明 |
---|---|
argsForGoogle |
object Google Payのトークンを取得するための引数を設定する |
argsForGoogle
オブジェクトmulpay.createPaymentRequest(argsForGoogle)
の引数argsForGoogle
オブジェクトにはGoogle Payのトークンを取得する引数を指定します。
以下の項目を設定してください。
項目 | 説明 |
---|---|
merchantName required |
string 購入者 |
currency required |
string 通貨 |
country |
string 国 |
total required |
string 金額 |
Google Payの利用可否をチェックするメソッドです。
Google Payのトークンを取得をする前に、必ずこのメソッドを実行してGoogle Payの利用可否を確認してください。
項目 | 説明 |
---|---|
payAvailable |
boolean true が返却されると利用可能状態です。 |
Google Payのトークンを取得するメソッドです。mulpay.createPaymentRequest(argsForGoogle)
で作成した支払い情報を引数に指定してください。
引数 | 説明 |
---|---|
paymentRequestForGoogle |
mulpay.createPaymentRequest(argsForGoogle) の返り値Google Payの支払い情報 |
Google Payの支払い情報を作成するメソッドです。
引数 | 説明 |
---|---|
argsForGoogle |
object Google Payのトークンを取得するための引数を設定する |
argsForGoogle
オブジェクトmulpay.createPaymentRequest(argsForGoogle)
の引数argsForGoogle
オブジェクトにはGoogle Payのトークンを取得する引数を指定します。
以下の項目を設定してください。
項目 | 説明 |
---|---|
merchantName required |
string 購入者 |
currency required |
string 通貨 |
country |
string 国 |
total required |
string 金額 |
Google Payの利用可否をチェックするメソッドです。
Google Payのトークンを取得をする前に、必ずこのメソッドを実行してGoogle Payの利用可否を確認してください。
項目 | 説明 |
---|---|
payAvailable |
boolean true が返却されると利用可能状態です。 |
Google Payのトークンを取得するメソッドです。mulpay.createPaymentRequest(argsForGoogle)
で作成した支払い情報を引数に指定してください。
引数 | 説明 |
---|---|
paymentRequestForGoogle |
mulpay.createPaymentRequest(argsForGoogle) の返り値Google Payの支払い情報 |
MpToken.jsでエラーが発生した場合は、result
オブジェクトのresultCode
に以下の処理結果コードを返します。
500
番以下のエラーは、パラメーター不正です。処理結果コードに従って、お客様に再入力を促し、リトライ可能です。
500
番以上のエラーは、原則サーバー側もしくは当社設定の異常ですので、お問い合わせください。
処理結果コード | 説明 |
---|---|
000 |
MPクレカトークン取得正常終了 |
100 |
カード番号必須チェックエラー |
101 |
カード番号フォーマットエラー(数字以外を含む) |
102 |
カード番号フォーマットエラー(10-16桁の範囲外) |
110 |
有効期限必須チェックエラー |
111 |
有効期限フォーマットエラー(数字以外を含む) |
112 |
有効期限フォーマットエラー(6または4桁以外) |
113 |
有効期限フォーマットエラー(月が13以上) |
121 |
セキュリティコードフォーマットエラー(数字以外を含む) |
122 |
セキュリティコード桁数エラー |
131 |
カード名義人フォーマットエラー(半角英数字、一部の記号以外を含む) |
132 |
カード名義人フォーマットエラー(51桁以上) |
141 |
MPクレカトークン発行数フォーマットエラー(数字以外を含む) |
142 |
MPクレカトークン発行数フォーマットエラー(1-10の範囲外) |
150 |
カード情報を暗号化した情報必須チェックエラー |
160 |
ショップID必須チェックエラー |
161 |
ショップIDフォーマットエラー(14 桁以上) |
180 |
ショップIDまたは公開鍵ハッシュ値がマスターに存在しない |
190 |
カード情報(Encrypted)が復号できない |
191 |
カード情報(Encrypted)復号化後フォーマットエラー |
200 |
callback必須チェックエラー |
201 |
callbackフォーマットエラー(半角英数字、アンダースコア、ピリオド以外を含む) |
701 |
MPクレカトークン用パラメーター(cardObject)が存在しない |
901 |
当サービス内部のシステムエラー |
902 |
処理が混み合っている |
Web APIでカード情報をトークン化します。
スマートフォンのネイティブアプリから直接呼ばれることを想定しています。
TLS は1.2 に対応しています。
ATSにつきましては対応していませんので、アプリ側でATSに対応している場合はホワイトリストへのURLの登録をお願いします。
カード情報をトークン化します。
required | object 暗号化情報 | ||||
| |||||
encryptedData required | string カード情報オブジェクト | ||||
createCount | string <= 2 characters ^([1-9]|10)$ Default: "1" MPクレカトークン発行数 |
{- "encryptionParameters": {
- "type": "UNIQUE_PK",
- "apiKey": "xxxxxxxxxxxxxxxxx"
}, - "encryptedData": "xxxxxxxxxxxxxxxxx",
- "createCount": "1"
}
{- "result": "success",
- "maskedCardNumber": "411111******1111",
- "tokenExpiryDate": "2024-05-28T12:34:56+09:00",
- "isSecurityCodeSet": true,
- "tokenList": [
- "edf3dd725dcc9999f54bb61bc6b5db9001b48d93ceb8b7efdd546116f80af46e"
]
}
Web APIで利用するパラメーターencryptedData
はカード情報を暗号化した文字列です。
作成の手順を説明します。
お客様が入力した値からネイティブアプリ内で以下のカード情報データをJSON形式で用意します。
項目 | 説明 | |
---|---|---|
card required |
object | |
cardNumber required |
string ^[0-9]{12,16}$ カード番号 ハイフンは含めず半角数字のみで設定します。 |
|
cardholderName |
string ^[0-9a-zA-Z\s\x2c-\x2f]{0,50}$ カード名義人 設定しない場合、カード名義人を取引に記録しません。 3Dセキュア認証利用時には必ず設定してください。 未設定でもエラーにはなりませんが、変更になる可能性があります。 |
|
expiryMonth required |
string ^[0-9]{2}$ 有効期限(月) 半角数字でMM形式で設定します。 |
|
expiryYear required |
string ^([0-9]{2}|[0-9]{4})$ 有効期限(年) 半角数字でYYまたはYYYY形式で設定します。 |
|
securityCode |
string ^(|[0-9]{3,4})$ セキュリティコード 3または4桁の数字で設定します。 |
以下はカード情報データのサンプルです。
{
"card": {
"cardNumber":"4111111111111111",
"cardholderName":"HOLDER NAME",
"expiryMonth":"05",
"expiryYear":"24",
"securityCode":"123"
}
}
前述のカード情報データのJSON文字列を管理画面からダウンロードした公開鍵を用いてRSA方式(2048bit)で暗号化します。公開鍵については認証情報を参照ください。 暗号化後の文字列をBase64エンコードした文字列を「カード情報オブジェクト」としてトークン発行リクエストパラメーターに設定します。
JavaとSwiftのコードスニペットです。変数の保持方法や例外処理は適切に変更してください
public String createEncryptedData() throws Exception {
// 管理画面からダウンロードした公開鍵
String publicKeyString = "MIIBIjA...";
// カード情報データのJSON文字列
String cardInfoJson = "{\"card\":{\"cardNumber\":\"4111111111111111\",\"cardholderName\":\"HOLDERNAME\",\"expiryMonth\":\"05\",\"expiryYear\":\"24\",\"securityCode\":\"123\"}}";
// 公開鍵から公開鍵オブジェクトを作成
byte[] decodedPublicKey = Base64.getDecoder().decode(publicKeyString.getBytes(StandardCharsets.UTF_8));
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decodedPublicKey));
// カード情報データを暗号化
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedByte = cipher.doFinal(cardInfoJson.getBytes());
// Base64エンコード
String encryptedData = Base64.getEncoder().encodeToString(encryptedByte);
return encryptedData;
}
func makeCardInfoData() -> String? {
do{
let publicKeyString = "MIIBIjA..."
let cardInfoJson = "{\"card\":{\"cardNumber\":\"4111111111111111\",\"cardholderName\":\"HOLDERNAME\",\"expiryMonth\":\"05\",\"expiryYear\":\"24\",\"securityCode\":\"123\"}}"
// 公開鍵から公開鍵オブジェクトを作成
let data:Data = Data(base64Encoded: publicKeyString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
let keyDict:[NSObject:NSObject] = [kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: NSNumber(value: 2048),
kSecReturnPersistentRef: true as NSObject
]
let publicKey = SecKeyCreateWithData(data as CFData, keyDict as CFDictionary, nil)
// カード情報データを暗号化
let plainBuffer = [UInt8](cardInfoJson.utf8)
var cipherBufferSize : Int = Int(SecKeyGetBlockSize(publicKey!))
var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))
let status = SecKeyEncrypt(publicKey!, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
if (status != errSecSuccess) {
// 失敗時の処理
}
// Base64エンコード
let mudata = NSData(bytes: &cipherBuffer, length: cipherBufferSize)
let encryption = mudata.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters)
return encryption
} catch {
return nil
}
}
APIリクエストがエラーになると、HTTPステータスコードは4xx
、5xx
を返却します。
HTTPレスポンスヘッダー、レスポンスボディはAPI仕様のResponsesを参照してください。
ただし、以下表の「種別」が「アクセスエラー」、「サービス利用不可」は、APIを受け付ける前のエラーであり、上記Responsesには記載していません。
HTTP ステータス コード |
種別 | 説明 |
---|---|---|
400 |
リクエストパラメーターエラー | パラメーターの内容が正しくない、 またはカード情報オブジェクトが正しく 暗号化できていないため、リクエストは処理できません。 |
404 |
アクセスエラー | APIエンドポイントが無効であるため、 リクエストは受け付けられません。 |
405 |
アクセスエラー | HTTPメソッドがPOST ではないため、リクエストは受け付けられません。 |
415 |
アクセスエラー | Content-Type ヘッダーが正しくないため、リクエストは受け付けられません。 application/json のみに対応しています。 |
429 |
アクセスエラー | 同時処理数が規定値を超えているため、 リクエストは受け付けられません。 |
500 |
当サービス内部のシステムエラー | 当サービスのサーバーで問題が発生したため、 リクエストを処理できませんでした。 |
503 |
サービス利用不可 | 当サービスがメンテナンス中のため、 リクエストは受け付けられません。 このコードを返すメンテナンス情報は、 6ヶ月前に加盟店様に通知します。 |
処理結果コードlegacyCode
パラメーターの一覧は以下の通りです。
コード | 意味 |
---|---|
000 |
MPクレカトークン取得正常終了 |
100 |
カード番号必須チェックエラー |
101 |
カード番号フォーマットエラー(数字以外を含む) |
102 |
カード番号フォーマットエラー(10-16桁の範囲外) |
110 |
有効期限必須チェックエラー |
111 |
有効期限フォーマットエラー(数字以外を含む) |
112 |
有効期限フォーマットエラー(6または4桁以外) |
113 |
有効期限フォーマットエラー(月が13以上) |
121 |
セキュリティコードフォーマットエラー(数字以外を含む) |
122 |
セキュリティコード桁数エラー |
131 |
カード名義人フォーマットエラー(半角英数字、一部の記号以外を含む) |
132 |
カード名義人フォーマットエラー(51桁以上) |
141 |
MPクレカトークン発行数フォーマットエラー(数字以外を含む) |
142 |
MPクレカトークン発行数フォーマットエラー(1-10の範囲外) |
150 |
カード情報オブジェクト必須チェックエラー |
160 |
APIキー必須チェックエラー |
161 |
APIキーフォーマットエラー |
180 |
APIキーが無効 |
190 |
カード情報オブジェクトが復号できない |
191 |
カード情報オブジェクトフォーマットエラー |
901 |
当サービス内部のシステムエラー |
902 |
処理が混み合っている |
PGマルチペイメントサービス 加盟店用 FAQサイトを参照ください。
日付 | 変更の内容 | バージョン |
---|---|---|
2024/11/25 |
・mulpay.checkAvailability() について、必ずチェックを行う必要がある旨の注意書きを追加 |
1.1.4 |
2024/10/28 |
・mptoken-react-js を使用したReactのサンプルコードを追加・ loadMulpay のサンプルコードの引数に誤りがあったため修正
|
1.1.3 |
2024/8/28 |
・mptoken-vue-js を使用したVue.jsのサンプルコードを追加 |
1.1.2 |
2024/5/27 |
・分かりやすい表現、名称に変更 ・トークン決済の名称について、従来の方式を「トークン決済v1」、新しい方式を「トークン決済v2」に変更 ・テストカード番号の説明を追加 ・「カード名義人」の設定に関する説明を追加 |
1.1.1 |
2024/4/15 |
・説明を全体的に追加 ・MpToken.jsのElements機能を追加 ・トークン決済v2 Web APIの仕様を追加 |
1.1.0 |
2023/12/20 | 初版 | 1.0.0 |