PGマルチペイメントサービス トークン決済v2 開発ガイド (1.1.4)

はじめに

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との違い

トークン決済v1(/ext/js/token.js もしくは /ext/api/credit/getToken API)は引き続き利用できますが、2027年4月以降にサポートを終了する予定です。 ただし、新たな脆弱性の登場やPCI DSSの要件が変更になる等の理由によりサポート終了時期が早まる可能性がありますので、より便利になった「トークン決済v2」への移行を推奨します。
どちらの方式で取得したトークンでも、後続のAPI処理のパラメーターに設定できます。

トークン決済v1とトークン決済v2の比較

機能・特徴 トークン決済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]
  • JavaScript版の認証情報
    トークン決済v1のJavaScript版では個別の認証情報を事前に登録する必要はありませんが、トークン決済v2では必要です。
    ただし、MpToken.jsの下位互換メソッドであるinitgetTokenを利用する場合はこれまで通りです。

組み込んでみましょう

GET STARTEDセクションは、開発者の方に向けた技術仕様に関するドキュメントです。 実際にトークン決済v2の組み込み開発をするにあたりお読みください。

組み込み方法

トークン決済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メソッドinitgetTokenをサポートします。

テストアカウント

こちらのテスト環境申し込みページからテストアカウントの即時発行が可能です。 登録が完了すると申し込み時のメールアドレスにショップ管理画面のログイン情報が届きます。 ショップ管理画面にログインできることを確認し、トークン決済v2を利用するための認証情報を登録します。

認証情報

トークン決済v2の認証情報は以下の2つのデータを指します。

データ名 用途
公開鍵 カード情報を暗号化するための公開鍵です。
APIキー トークン化リクエストを当サービスで認証するための情報です。

トークン決済v2の利用にあたり、事前にショップ管理画面にて認証情報を登録する必要があります。 ショップ管理画面の「都度決済」->「クレジットカード」->「設定」ページを開き、「MPクレカトークン認証情報」メニューに進み、「登録」ボタンを押して認証情報を発行します。 登録された「公開鍵」と「APIキー」は、組み込み時に設定します。

環境とFQDN

テスト環境と本番環境を用意しています。 各環境はFQDN(絶対ドメイン名)で区別され、認証情報やトークンのデータは共用されません。 テスト環境での確認を終えて商用利用を開始する際は、以下の対応をお願いします。

  • 本番アカウントの認証情報を管理画面で登録して設定値を更新
  • MpToken.jsを直接読み込んでいる場合は、srcに指定するURLを本番用のURLに更新
  • npmインストールしたパッケージは、初期化時のproductionModetrueに設定
環境 目的 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クレカトークン有効期限」で確認できます。

後続のAPI処理

加盟店様のフロントエンドで受け取ったMPクレカトークンは、加盟店様サーバーサイドでの当サービスAPI呼び出し時に設定します。 対応するAPIは以下の通りです。 詳細については各リファレンスを参照ください。 マルペイDocsの利用方法はこちらのFAQページを参照してください。

接続方式 決済手段 対応するAPI リファレンス
OpenAPIタイプクレカ払い都度支払い
有効性確認
カード登録
カード詳細情報取得*1
OpenAPIタイプ
APIリファレンス
プロトコルタイプ
モジュールタイプ
クレジットカード決済決済実行
カード登録/更新
カード属性照会
マルペイDocs
クレジットカード決済
クレジットカード決済
自動売上
自動売上定義登録マルペイDocs
クレジットカード決済
自動売上関連
多通貨クレジット
カード決済(DCC)
決済実行
カード登録/更新
カード属性照会
マルペイDocs
多通貨クレジット
カード決済(DCC)
不正防止サービス
(ReD Shield)
不正審査マルペイDocs
不正防止サービス
(ReD Shield)

*1:APIでMPクレカトークンを利用してもトークンは無効になりません。

Elements機能

Elements機能とは、弊社が提供するカード情報の入力フォームを利用してトークン化する機能です。
トークン決済v1では、加盟店様が設置した入力フォームを経由してトークン化していました。 どちらも加盟店様のカード情報非保持を実現しますが、Elements機能はiframeを通じて弊社サーバー側でカード情報を受け付けます。
Elements機能に対応している入力フォームは以下の3つです。

  • カード番号
  • 有効期限
  • セキュリティコード

これらのフォームは弊社サーバー上で動作するため、加盟店様が用意するスタイル(CSSファイル、styleタグ)は適用できません。 スタイルを変更する場合は、フォーム生成時のオプションで設定します。

Elements機能に対応している組み込み方法は以下の通りです。

  • ESモジュール MpToken.js
  • React MpToken.js
  • Vue MpToken.js

詳細な組み込み方法についてはElementsによるカード情報入力フォームの生成を参照ください。

テストカード番号

テスト環境で利用可能なカード番号は、マルペイDocsのテストカード一覧ページを参照してください。
マルペイDocsのログイン情報はこちらのFAQページを参照してください。

JavaScriptを読み込む

トークン決済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を内部で読み込みます。
機能
  • クライアント側で利用するカード情報のトークン化を行うためのSDKです。
  • カード情報入力フォームを生成するElements機能を利用してカード情報のトークン化をセキュアに実現できます。
  • 今まで加盟店様が実装していたGoogle Payのトークン取得処理をMpToken.jsから利用できます。

パッケージマネージャーを利用してインストールする

npmパッケージを利用してMpToken.jsをインストールします。

ESモジュール MpToken.jsを利用する場合

インストール
npm install --save @mul-pay/mptoken-js
呼び出す
import { loadMulpay } from '@mul-pay/mptoken-js'

Vue MpToken.jsを利用する場合

インストール
npm install --save @mul-pay/mptoken-vue-js
呼び出す
import VueMultiPayment  from '@mul-pay/mptoken-vue-js';

React MpToken.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";

scriptへ追加

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

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.init(apiKey)

Multipaymentオブジェクトを初期化するメソッドです。
Multipaymentオブジェクトの機能を利用するために必要です。
※npmパッケージを利用する場合は、loadMulpay()を呼び出してください。

引数 説明

apiKey

ショップID

Multipayment.getToken(card, callback)

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の場合セキュリティコード設定ありとされます。

resultオブジェクトサンプル

{
"resultCode": "000",
"tokenObject": {
    "token": "a33c8bec609ffc75726249d8d82286d529bd1deb973119cf497eeb54610ab9d2",
    "toBeExpiredAt": "2016-09-26-17-56-38",
    "maskedCardNo": "411111******1111",
    "isSecurityCodeSet": true
}
}

Multipayment.init(apiKey)

Multipaymentオブジェクトを初期化するメソッドです。
Multipaymentオブジェクトの機能を利用するために必要です。
※npmパッケージを利用する場合は、loadMulpay()を呼び出してください。

引数 説明

apiKey

ショップID

Multipayment.getToken(card, callback)

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の場合セキュリティコード設定ありとされます。

resultオブジェクトサンプル

{
"resultCode": "000",
"tokenObject": {
    "token": "a33c8bec609ffc75726249d8d82286d529bd1deb973119cf497eeb54610ab9d2",
    "toBeExpiredAt": "2016-09-26-17-56-38",
    "maskedCardNo": "411111******1111",
    "isSecurityCodeSet": true
}
}

Elementsによるカード情報入力フォームの生成

Elementsを利用することでカード情報入力フォームを動的に生成できます。
iframeで生成されるため、カード情報の入力をより安全に行えます。
以下のような手順を行うことで、MPクレカトークンを取得できます。

  1. Multipayment.createElements()で初期化
  2. elements.create()でカード情報入力フォームを生成し、入力フォームにしたいdiv要素にmountする
  3. 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>(プロトコルタイプ)決済実行
Element を利用したトークン取得 サンプルコード

htmlサンプルコード

<!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>

JavaScriptサンプルコード(useMpToken.js)

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 サンプルコード

Vue.jsサンプルコード

このセクションでは、Vue.jsを使用してMPクレカトークンを取得するサンプルを提供します。
Vue.jsを使用する場合、mptoken-vue-jsを使用してMPクレカトークンを取得します。また、createElements()ではなく、Elementsコンポーネントを使用してカード情報入力フォームを生成することができるように構成されています。

1.Vueアプリケーションへの登録

main.ts(またはmain.js)でプラグインを登録します。

main.ts

// 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');

2.カスタムフックの設定

usePaymentContext.tsを作成し、以下のようなカスタムフックを実装します。このフックを使用することで、MultiPaymentElementsMultiPaymentオブジェクトを取得できるようにします。

// 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 };
}

3.FormWrapper.vueの作成

FormWrapper.vueコンポーネントは、Elementsコンポーネントを使用してMPクレカトークンの初期化と設定を行います。

FormWrapper.vue

// 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>

4.PaymentCardForm.vueの作成

PaymentCardForm.vueコンポーネントは、実際のカード情報入力フォームを実装します。このコンポーネントでは、mptoken-vue-jsが提供するCardNumberElementCardExpiryElementCardCvcElementを使用してフォームを構築し、トークン取得処理を実装します。

  • CardNumberElement(カード番号コンポーネント)
  • CardExpiryElement(有効期限コンポーネント)
  • CardCvcElement(セキュリティコードコンポーネント)

下記のサンプルコードでは、CardNumberElementCardExpiryElementCardCvcElementを使用したカード情報入力フォームを生成し、ボタンの押下によってgetTokenThroughIframe()を呼び出しています。

PaymentCardForm.vue

// 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 サンプルコード

Reactサンプルコード

このセクションでは、React を使用してMPクレカトークンを取得するサンプルを提供します。
React を使用する場合、mptoken-react-jsを使用してMPクレカトークンを取得します。また、createElements()ではなく、Elementsコンポーネントを使用してカード情報入力フォームを生成することができるように構成されています。

1.Reactでの設定

FormWrapper.tsxElementsコンポーネントを使用した初期化用のコンポーネントを作成します。このコンポーネントは、MPクレカトークンの初期化と設定を行います。

FormWrapper.tsx

// 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>
  );
}

2.入力フォームの作成

Card.tsxを作成し、実際のカード情報入力フォームを実装します。このコンポーネントでは、mptoken-react-jsが提供するCardNumberElementCardExpiryElementCardCvcElementを使用してフォームを構築し、トークン取得処理を実装しています。

// 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;

3.App.tsxの作成

App.tsxFormWrapperコンポーネントを使用して、実際のカード情報入力フォームを表示します。

import "./App.css";
import FormWrapper from "./components/FormWrapper";
 
function App() {
  return (
    <>
      <FormWrapper />
    </>
  );
}
 
export default App;

loadMulpay(apiKey, publicKey, merchantIds, permitToSendFingerprint, productionMode)

loadMulpayはnpmパッケージを利用してMpToken.jsを読み込む際に使用する関数です。

引数 説明

apiKey

required

string

APIキー(認証情報を参照ください)

publicKey

required

string

公開鍵(認証情報を参照ください)

merchantIds

object

Google PayのMerchant情報

permitToSendFingerprint

boolean

ブラウザーフィンガープリントの送信を許可するか
default: true(許可する)

productionMode

boolean

本番の商用環境かテスト環境を使用するか
default: false(テスト環境)

Example

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);

mulpay.createElements()

Multipayment.createElements()は、Elementsオブジェクトを返すメソッドです。
このメソッドを使用することで、Elementsオブジェクトを利用できます。

elements.create(type,options)

指定されたtypeElementsオブジェクトを返すメソッドです。
生成されたElementsオブジェクトは、指定されたdiv要素にmountすることで、カード情報入力フォームを生成します。

引数 説明

type

required

string

cardNumber:カード番号
cardExpiry:有効期限
cardCvC:CVC

options

object

オプション。Elemetnsで生成されたinputフォームのstyledisabledplaceholderを設定できます。
styleでは各状態 (base, complete, empty, invalid, forcus) のCSSが設定できます。

Example

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プロパティ

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 テキストの変形

mulpay.getTokenThroughIframe(element,holdername,options)

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"

Google Payのトークン取得

MpToken.jsでは Google Payトークンを取得できる機能を提供します。 カード情報は当サービスではなく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>(プロトコルタイプ)決済実行
Google Payトークンの取得 サンプルコード

htmlサンプルコード

<!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>

JavaScriptサンプルコード(useMpToken.js)

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ボタンをクリックした時の処理を登録する
});

mulpay.createPaymentRequest(argsForGoogle)

Google Payの支払い情報を作成するメソッドです。

引数 説明

argsForGoogle

object

Google Payのトークンを取得するための引数を設定する

argsForGoogle オブジェクト

mulpay.createPaymentRequest(argsForGoogle)の引数argsForGoogleオブジェクトにはGoogle Payのトークンを取得する引数を指定します。
以下の項目を設定してください。

項目 説明

merchantName

required

string

購入者

currency

required

string

通貨

country

string

total

required

string

金額

mulpay.checkAvailability()

Google Payの利用可否をチェックするメソッドです。
Google Payのトークンを取得をする前に、必ずこのメソッドを実行してGoogle Payの利用可否を確認してください。

返り値

項目 説明

payAvailable

boolean

trueが返却されると利用可能状態です。

mulpay.fetchEncryptedTokenObject(paymentRequestForGoogle);

Google Payのトークンを取得するメソッドです。
mulpay.createPaymentRequest(argsForGoogle)で作成した支払い情報を引数に指定してください。

引数 説明

paymentRequestForGoogle

mulpay.createPaymentRequest(argsForGoogle)の返り値
Google Payの支払い情報

mulpay.createPaymentRequest(argsForGoogle)

Google Payの支払い情報を作成するメソッドです。

引数 説明

argsForGoogle

object

Google Payのトークンを取得するための引数を設定する

argsForGoogle オブジェクト

mulpay.createPaymentRequest(argsForGoogle)の引数argsForGoogleオブジェクトにはGoogle Payのトークンを取得する引数を指定します。
以下の項目を設定してください。

項目 説明

merchantName

required

string

購入者

currency

required

string

通貨

country

string

total

required

string

金額

mulpay.checkAvailability()

Google Payの利用可否をチェックするメソッドです。
Google Payのトークンを取得をする前に、必ずこのメソッドを実行してGoogle Payの利用可否を確認してください。

返り値

項目 説明

payAvailable

boolean

trueが返却されると利用可能状態です。

mulpay.fetchEncryptedTokenObject(paymentRequestForGoogle);

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 処理が混み合っている

トークン決済v2 Web API

Web APIでカード情報をトークン化します。
スマートフォンのネイティブアプリから直接呼ばれることを想定しています。
TLS は1.2 に対応しています。 ATSにつきましては対応していませんので、アプリ側でATSに対応している場合はホワイトリストへのURLの登録をお願いします。

MPクレカトークン発行

カード情報をトークン化します。

Request Body schema: application/json
required
required
object

暗号化情報

type
required
string
Value: "UNIQUE_PK"

暗号化方式
UNIQUE_PKを設定してください。

apiKey
required
string <byte>

APIキー
トークン決済v2の認証情報であるAPIキーを設定します。
テスト環境、本番環境それぞれの管理画面で事前に登録します。

encryptedData
required
string

カード情報オブジェクト
カード情報を作成ガイドの方法で暗号化した値を設定してください。

createCount
string <= 2 characters ^([1-9]|10)$
Default: "1"

MPクレカトークン発行数
発行するトークンの数を1~10の間で設定します。
省略時は"1"です。

Responses

Request samples

Content type
application/json
{
  • "encryptionParameters": {
    },
  • "encryptedData": "xxxxxxxxxxxxxxxxx",
  • "createCount": "1"
}

Response samples

Content type
application/json
{
  • "result": "success",
  • "maskedCardNumber": "411111******1111",
  • "tokenExpiryDate": "2024-05-28T12:34:56+09:00",
  • "isSecurityCodeSet": true,
  • "tokenList": [
    ]
}

カード情報オブジェクト作成ガイド

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"
  }
}

暗号化とBase64エンコード

前述のカード情報データのJSON文字列を管理画面からダウンロードした公開鍵を用いてRSA方式(2048bit)で暗号化します。公開鍵については認証情報を参照ください。 暗号化後の文字列をBase64エンコードした文字列を「カード情報オブジェクト」としてトークン発行リクエストパラメーターに設定します。

サンプルコード

JavaとSwiftのコードスニペットです。変数の保持方法や例外処理は適切に変更してください

Java
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;
}

Swift
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ステータスコードは4xx5xxを返却します。 HTTPレスポンスヘッダー、レスポンスボディはAPI仕様のResponsesを参照してください。 ただし、以下表の「種別」が「アクセスエラー」、「サービス利用不可」は、APIを受け付ける前のエラーであり、上記Responsesには記載していません。

エラー時のHTTPステータスコードとエラー情報

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 処理が混み合っている

よくあるご質問(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