1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PAY.JP を使ってサクッとつくってみた

Videotogif (5).gif

"チケットメンター" という名前のサイトを作ってみました。

実際に決済することはできませんが、PAY.JP のテストモードで本番の決済を想定した処理をつくることができました。


最初の一歩

アカウントを作成しましょう。

本番環境を使うには会社情報の入力や「EMV 3-Dセキュア導入」が義務付けられていますが、テストモードに関してはそういった準備は不要です。

image.png

必要な準備は主に2つです。

1. API キー

API 設定からテスト用のキーが手に入ります。
image.png

2. クレジットカード情報

こちらからテスト用のクレジットカード情報が使えます。

各種ブランドが使えます
image.png

「決済が上手くいかないクレジットカード」も用意されているので様々なシーンでの挙動を確認できます。


サイトを構築し決済対応機能をつくる

ここからはゴリゴリつくっていきますが、大事なのは引数と入力の UI の部分なので、この記事ではそちらを説明します。

コード全体が気になる方は GitHub リポジトリを参考にしてください。

リスクエストパラメーター

以下のような UI で取得した内容を渡します。よくあるカードの情報入力画面ですね。ちなみに、カードブランドは実際には引数として使いません。

image.png

エンドポイント: POST https://api.pay.jp/v1/charges

以下のcardのパラメータが重要です。

パラメータ 必須 説明
amount integer 必須 決済金額(円)
currency string 必須 通貨コード(jpy
card string 必須 カードトークン(tok_xxxxx
description string - 決済の説明
metadata[order_id] string - 注文ID(メタデータ)
metadata[user_id] string - ユーザーID(メタデータ)
metadata[sku] string - 商品SKU(メタデータ)
const body = new URLSearchParams({
  amount: String(plan.price_jpy),
  currency: "jpy",
  card: token,
  description: `Ticket purchase: ${sku}`,
  "metadata[order_id]": orderId,
  "metadata[user_id]": userId,
  "metadata[sku]": sku,
});

const response = await fetch("https://api.pay.jp/v1/charges", {
  method: "POST",
  headers: { ...payjpAuthHeader(), "Content-Type": "application/x-www-form-urlencoded" },
  body,
});

カードトークンとは、カード情報をもとに生成させるトークンです。こちらにクレジットカードの情報を使っています。

const result = await payjp.createToken({
  card: {
    number: "4242424242424242",
    exp_month: "12",
    exp_year: "30",
    cvc: "123"
  }
});

なお、決済金額はここから取ります。

image.png

PAY.JP のダッシュボードに売り上げとして管理されます。

image.png

3Dセキュア

購入ボタンを押した後に、テストモードではこのように画面が立ち上がります。よくあるクレジットカードでの購入時の認証画面を再現しています。

image.png

3Dセキュアを開始するには、通常の支払いのパラメータにthree_d_secure=trueを追加すればOKです。

3Dセキュアで開始した支払いは保留状態となり、認証完了後にtds_finishというエンドポイントを呼び出します。

エンドポイント: POST https://api.pay.jp/v1/charges/{charge_id}/tds_finish

const response = await fetch(`https://api.pay.jp/v1/charges/${chargeId}/tds_finish`, {
  method: "POST",
  headers: payjpAuthHeader(),
});

const result = await response.json();
if (!response.ok && result.error?.code === 'three_d_secure_incompleted') {
}

なお、PAY.JPのダッシュボードでは未認証扱いで当然売り上げ計上されません。

image.png

3Dセキュア認証における追加項目として

  • カード名義
  • メールアドレスまたは電話番号
    が必要です。

これらを踏まえて実装

フロントエンド(payjs v2 Elements API)

  • 初期化
<script src="https://js.pay.jp/v2/pay.js"></script>

const payjp = Payjp(publicKey);
const elements = payjp.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
  • トークン化
// カード情報をトークン化
const result = await payjp.createToken(cardElement);

if (result.error) {
  console.error("トークン化エラー:", result.error);
} else {
  const token = result.id; // tok_xxxxx
  // サーバーに送信
}
  • 3Dセキュア認証(有効な場合)
// 3Dセキュア認証を開始(charge IDを渡す)
payjp.openThreeDSecureIframe(chargeId)
  .then((result) => {
    if (result.error) {
      console.error("3Dセキュアエラー:", result.error);
    } else {
    }
  })
  .catch((error) => {
    console.error("3Dセキュア例外:", error);
  });

初の決済機能

テストモードの実装を通して、EMV 3-Dセキュア導入などの必要な準備や、有効期限切れや与信枠超過の時などクレジットカードの決済に関する必要なレスポンスについても学ぶことができました。
ササっと実装できることもこういった仕組みを理解できることも大事ですね!

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?