Engineering
fincodeの構築方法~トークン決済編~
fincode開発チームです!
fincodeを使って決済実行してみた 第二弾・トークン決済編をご紹介します!
今回は、fincodeが提供している決済フローのうち、トークンJSを使って構築してみました。
(第一弾・決済JS編はこちら)
トークンJSを使った決済フローは以下になります。
■決済登録API + トークンJS + 決済実行APIのフロー
まず決済登録APIを呼び出し、オーダーIDや取引IDを取得します。
次にフロント側でトークンJSを実行し、カード情報(カード番号・有効期限など)のトークン化を行います。
最後に決済実行APIを呼び出し、オーソリを実行します。
今回もフロントはVue.js、バックエンドはnode.js(+ Express)で実装しました。
実装メモ:
■フロント
・axiosでバックエンドのAPIを呼び出し、決済登録API・決済実行APIのレスポンスを受け取っている
・カード情報を引数に設定してトークンJSを呼び出す
・トークンJSでエラーの場合はエラーコードがリスト形式で複数返る
・APIキーはパブリックキーを使う
Vue.js
<script src="https://js.fincode.jp/v1/fincode.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let fincode = Fincode('p_prod_XXXXXXXXXXXXXXXX');
const app = new Vue({
el: '#app',
data() {
return {
card: {
card_no: '',
expire: '',
holder_name: '',
security_code: ''
},
expire_mm: '',
expire_yy: '',
amount: "500",
id: '',
access_id: '',
}
},
methods: {
submit() {
this.card.expire = this.expire_yy + this.expire_mm;
//axiosでリクエストデータ送信(①fincode決済登録呼び出しAPI)
axios.post("http://localhost:3000/payment", {
amount: this.amount
})
.then((res) => {
console.log(res);
//決済登録APIのレスポンスを設定
this.id = res.data.id;;
this.access_id = res.data.access_id;
//トークンJS実行
fincode.tokens(this.card,
(status, response) => {
if (200 === status) {
// トークンJS リクエスト正常時の処理
console.log(response);
// 決済実行APIのリクエストパラメータを設定
const transaction = {
id: this.id,
access_id: this.access_id,
token: response.list[0].token, //トークンJSで取得した値
};
//axiosでリクエストデータ送信(②fincode決済実行呼び出しAPI)
axios.post("http://localhost:3000/execute", {
data: transaction
}).then((res) => {
// リクエスト正常時の処理
console.log(res);
alert("決済が完了しました");
})
.catch((err) => {
console.log(err);
});
} else {
// トークンJS リクエストエラー時の処理
console.log(response);
response.errors.forEach(error => {
alert(error.error_message + "(" + error.error_code + ")");
});
}
},
() => {
// トークンJS 通信エラー処理。
alert("通信エラーが発生しました。しばらく経ってから再度お試しください。");
}
);
})
.catch((err) => {
console.log(err);
});
},
}
});
</script>
■バックエンド
2つのAPIを作成し、fincodeのAPIを呼び出す。
①決済登録呼び出しAPI
・requestモジュールでfincode(決済登録API)にPOST通信
・決済登録APIのレスポンスをフロントに渡す
②決済実行呼び出しAPI
・requestモジュールでfincode(決済実行API)にPUT通信
・決済実行APIのレスポンスをフロントに渡す
※①②とも、fincodeと通信する際のAPIキーはシークレットキーを使う。
node.js(①決済登録呼び出しAPI)
var express = require('express');
var router = express.Router();
/* ①fincode決済登録呼び出しAPI
* http://localhost:3000/payment にPOSTを投げると、
* 決済登録APIのレスポンスをJSON形式で返す。
*/
router.post('/', function (req, res, next) {
"use strict";
const console = require("console");
const request = require("request");
const API_KEY = "Bearer m_prod_XXXXXXXXXXXXXXXX";
const BASE_URL = "https://api.fincode.jp";
const endpoint = "/v1/payments";
const DATA = {
pay_type: "Card",
job_code: "CAPTURE",
amount: req.body.amount,
};
const options = {
url: BASE_URL + endpoint,
proxy: PROXY_URL,
headers: {
"Content-Type": "application/json; charset=utf-8",
Authorization: API_KEY,
},
json: DATA,
}
main();
function main() {
request.post(options, (error, response, body) => {
if (200 != response.statusCode) {
console.log("ERROR");
console.log(body);
} else {
console.log("SUCCESS");
console.log(body);
res.header('Content-Type', 'application/json; charset=utf-8')
res.send(body);
}
}
);
}
});
module.exports = router;
node.js(②決済実行呼び出しAPI)
var express = require('express');
var router = express.Router();
/* ②fincode決済実行呼び出しAPI
* http://localhost:3000/execute にPOSTを投げると、
* 決済実行APIのレスポンスをJSON形式で返す。
*/
router.post('/', function (req, res, next) {
"use strict";
const console = require("console");
const request = require("request");
const API_KEY = "Bearer m_prod_XXXXXXXXXXXXXXXX";
const BASE_URL = "https://api.fincode.jp";
const ID = req.body.data.id;
const DATA = {
pay_type: "Card",
access_id: req.body.data.access_id,
token: req.body.data.token,
method: "1",
};
console.log(DATA);
main();
function main() {
var endpoint = "/v1/payments/{id}".replace("{id}", ID);
request.put(
{
url: BASE_URL + endpoint,
proxy: PROXY_URL,
headers: {
"Content-Type": "application/json; charset=utf-8",
Authorization: API_KEY,
},
json: DATA,
},
(error, response, body) => {
if (200 != response.statusCode) {
console.log("ERROR");
console.log(body);
} else {
console.log("SUCCESS");
console.log(body);
res.header('Content-Type', 'application/json; charset=utf-8');
res.send(body);
}
}
);
}
});
module.exports = router;
上記を実行した結果、ダッシュボードから決済成功したことを確認できました。
(参考)決済実行APIからのレスポンス
SUCCESS
{
acs: '0',
shop_id: 's_21121014979',
id: 'o_0TiOWd3DT5uWD-0nCOiZ4g',
pay_type: 'Card',
status: 'CAPTURED',
access_id: 'a_Jou6XFKoT6KUjHNpG6XXKw',
process_date: '2022/04/25 10:16:23.681',
job_code: 'CAPTURE',
item_code: '0000990',
amount: 500,
tax: 0,
total_amount: 500,
customer_group_id: null,
customer_id: null,
card_no: '************1234',
card_id: null,
expire: '2411',
holder_name: 'Test',
card_no_hash: '0e4802a01114169feded374beed5f7d810be72c4aed0118285169b2b57fd55ec',
method: '1',
pay_times: null,
forward: '15250',
issuer: '9999999',
transaction_id: '2204251016602250501600919723',
approve: ' 067736',
auth_max_date: null,
client_field_1: null,
client_field_2: null,
client_field_3: null,
tds_type: '0',
tds2_type: null,
tds2_ret_url: null,
tds2_status: null,
merchant_name: null,
send_url: null,
subscription_id: null,
error_code: null,
created: '2022/04/25 10:16:22.771',
updated: '2022/04/25 10:16:23.681'
}
2022.07.13開発チーム