ごく基本的なPAY.JPの使い方(Ruby編)

PAY.JPはREST APIを使ってクレジットカード決済ができるサービスです。

f:id:goofmint:20171108144034p:plain

PAY.JP - クレジットカード決済サービス

多数のプログラミング言語(Ruby/Java/PHP/Python/Perl/Go/Swift/Node.js)などに対してSDKを提供しています。

そんなPAY.JPのごくごく基本的なコードをRubyで書いてみます。

インストール

まずSDKをインストールします。 gem コマンドまたはGemfileを使います。ライブラリはGitHubにて公開されています(ライセンスはMIT Licenseです)。

$ gem install payjp

インストールが終わったらRubyスクリプト(今回は test.rb としています)で読み込みます。

require 'payjp'

APIキーの取得

PAY.JPでユーザ登録して、ダッシュボードに入ると設定の中にAPIキー情報があります。

f:id:goofmint:20171108144053p:plain

今回はデモなのでテスト秘密鍵を使います。これを api_key として使います。

api_key = 'YOUR_API_KEY'

初期化

APIキーを使ってPayjpクラスを初期化します。

Payjp.api_key = api_key

カードトークンの取得

ここで処理の流れを紹介します。PAY.JPではクレジットカード番号を一旦トークン化し、そのトークンを使って決済処理を行います。通常、このトークンはテンポラリトークン(一回しか使えない有効期限付きトークン)ですが、顧客と紐付けを行うことで繰り返し使えるようになります。

このトークンの仕組みでは、クレジットカード番号自体、サービスサイト側で触らないようにするJavaScriptの仕組みを用意しております。トークンだけがサーバに送られるようになります。シーケンス図にすると次のようになります。

f:id:goofmint:20171108144122p:plain

本記事ではこちらを使った実装を紹介します。カード番号はテストカード | PAY.JPよりピックアップしています。CVC(セキュリティコード)や有効期限は適当です。

まずHTMLのフォームに対して script タグを追加します。 YOUR_PUBLIC_KEY には公開鍵を指定してください。

<form action="/pay" method="post">
  <!-- 注文情報などの情報ここから -->
    :
  <!-- 注文情報などの情報ここまで -->
  <script src="https://checkout.pay.jp/" class="payjp-button" data-key="YOUR_PUBLIC_KEY"></script>
</form>

そしてボタンを押すとクレジットカード番号を入力するモーダルウィンドウが表示されます。

入力を完了すると、元々のフォームの送信先である /pay に対して payjp-token という名前でテンポラリトークンが送信されます。

決済処理の実行

続いてこの取得したトークンを使って決済処理を行います。これは簡単で、金額とトークンを渡すだけです。

charge = Payjp::Charge.create(
  :amount => 3500,
  :card => payjp_token, // 先ほど送られてきたテンポラリトークン
  :currency => 'jpy',
)

結果は次のように返ってきます。

{
  "id": "ch_feb4b38692995e28859c5d0c21004",
  "amount": 5000,
  "amount_refunded": 0,
  "captured": true,
  "captured_at": 1508198383,
  "card":   { /*(トークン取得時のカード情報と同じ) */ },
  "created": 1508198383,
  "currency": "jpy",
  "customer": null,
  "description": null,
  "expired_at": null,
  "failure_code": null,
  "failure_message": null,
  "livemode": false,
  "metadata": {},
  "object": "charge",
  "paid": true,
  "refund_reason": null,
  "refunded": false,
  "subscription": null
}

このレスポンスの id を使うとダッシュボードで該当する取引を探せます。

f:id:goofmint:20171108144137p:plain


こんな感じでごく簡単に実装できます。なお、PAY.JPではクレジットカード情報をサーバから送信してトークン化することもできますが、その方式では経産省が2018年3月までにPCIDSSへ対応しなければならないと決定しており、PAY.JPでも非推奨の実装方法としております(via カード情報非保持化対応のお願い - PAY.JP Announcement)。これから実装される場合にはJavaScriptでトークンを生成する方法を採用いただくようご留意ください。

PAY.JPのオンライン決済にPAY IDを組み込む

PAY.JPはオンライン決済を提供しています。クレジットカード決済に加え、あらかじめクレジットカードを登録しておくことでカード番号の入力をしなくて済むPAY IDも提供しています。これはオンライン決済の他、リアル店舗や個人間決済でも使えます。

すでにPAY.JPのオンライン決済を導入している場合、すぐにPAY ID決済を組み込めます。

決済画面を表示する

PAY.JPのCheckoutを使った場合、元々の決済フォームは次のようになっているかと思います。 YOUR_PUBLIC_KEY はPAY.JPの管理画面で取得できる公開鍵です。

<form action="/pay" method="post">
    :
  <script class="payjp-button"
    src="https://checkout.pay.jp/"
    data-key="YOUR_PUBLIC_KEY">
  </script>
</form>

そのscriptタグに要素を一つ追加します。それが data-payjp です(取得方法はこれから説明します)。

<form action="/pay" method="post">
  <script class="payjp-button"
    src="https://checkout.pay.jp/"
    data-key="YOUR_PUBLIC_KEY"
    data-payjp="YOUR_CLIENT_ID"> <!-- これを追加 -->
  </script>
</form>

OAuthクライアントを作る

管理画面の設定に移動すると、OAuth クライアントという項目があります。このOAuthクライアントを追加します。

f:id:goofmint:20171106165457p:plain

Redirect URIは今回の場合は http://localhost/ で構いません。作成した後、OAuthクライアント一覧の中から詳細ボタンを押すとClient IDという項目が確認できます。

f:id:goofmint:20171106165509p:plain

これをHTMLフォームのYOUR_CLIENT_IDを書き換えてください。

<form action="/pay" method="post">
  <script class="payjp-button"
    src="https://checkout.pay.jp/"
    data-key="YOUR_PUBLIC_KEY"
    data-payjp="YOUR_CLIENT_ID"> <!-- これを書き換えます -->
  </script>
</form>

これで準備完了です。

PAY.JPでの処理

そしてボタンを押すとモーダルでPAY.JPの決済フォームが表示されます。テストで行う場合にはテストカード | PAY.JPからテスト用のクレジットカード番号を選んでください。テストの場合、有効期限やCVC、名前は適当で問題ありません。

f:id:goofmint:20171106165522p:plain

クレジットカードの他にPAY ID決済が選択できるようになります。なお、テストモードの場合はどんなメールアドレスとパスワードの組み合わせでもログインできます(ただしバリデーションは行われます)。ログインするとあからじめ一枚のクレジットカードと紐付いているのでそのまま決済ができます。

f:id:goofmint:20171106165535p:plain

そして処理が完了すると、フォームの送信イベントがすぐに呼ばれます。

サーバでの処理

PAY.JPでクレジットカード番号からトークンに変換されると、その情報は payjp-token という名前でPOSTされてきます。そのまま使うこともできますし、今後繰り返し使っていくのであれば顧客情報と結びつけることもできます。

以下は顧客情報と結びつける場合です(Rubyの場合)。

customer = Payjp::Customer.create(
  :email => 'example@pay.jp',
  :card  => params['payjp-token']
)

レスポンスであるcustomer.idを自社のデータベースに保存しておきます。こうするとトークンが繰り返し使えるようになります。

実際の決済処理は次のようになります。トークンではなく、customer.id を指定しているのが特徴です。

amount = 1000
Payjp::Charge.create(
    :amount => amount,
    :currency => 'jpy',
    :customer => customer.id,
    :description => '決済に関する説明'
)

例えばECコマースのユーザ情報と結びつけることで、二度目以降はクレジットカード番号の入力を不要にできます。


仕組みの違いはHTMLタグの要素追加だけなので、ユーザにとってはカード番号を入力しないで済むという利点が活かせます。すでにPAY.JPでCheckoutを導入されている方はぜひ追加してみてください。

顧客のデフォルトカード以外で支払いを作成できるようになりました

PAY.JPでは日々機能の追加を行なっています。今回はたくさんご要望をいただいていた「顧客のデフォルトカード以外を使っての支払い作成」ができるようになりましたのでお知らせします。

今まで顧客に対して複数のカードを登録している状態でデフォルトカード以外で支払いを行うには、まず最初に顧客のデフォルトカードを変更していただき、その後に支払いを作成するという2つのステップが必要でした。 これからはCharge APIを利用する際にcustomerに顧客ID、cardに顧客に登録されているカードIDを同時に指定することで、デフォルトカードの変更をせずに支払いに使うカードを指定できます。

例えば顧客ID cus_paykun に登録されているデフォルトカードとは別のカード car_paykun_2nd_card で支払いを作成する場合は、下記のようなリクエストを行います。

curl https://api.pay.jp/v1/charges \
-u sk_test_c62fade9d045b54cd76d7036: \
-d customer=cus_paykun \
-d card=car_paykun_2nd_card \
-d amount=100 \
-d currency=jpy

ライブラリを利用する場合も同様にCharge作成時にcustomercardのパラメータを同時に指定してください。

payjp-go をご利用いただいている場合のみ、この形式のリクエストを行うためのアップデートがありますので、必要に応じてライブラリのアップデートをお願いいたします。

サンプルを使ってPAY.JPのオンライン決済を学ぶ

PAY.JPではJavaScriptを使ってクレジットカード番号の一時的トークンを生成して決済する仕組みがあります。シーケンス図で表すと次のようになります。

f:id:goofmint:20171108144326p:plain

この仕組みを使った利点としては、サービス事業者(ECサイトを運営している企業など)がクレジットカード番号を知らずにオンライン決済を提供できることです。クレジットカード番号が事業者のサーバを通過する仕組みを提供する場合、2018年3月までにPCI DSSの対応が必要になります。これはセキュリティ基準としてハードルが非常に高いです。

PAY.JPのチェックアウトを使う場合、クレジットカード番号が事業者のサーバを通過せずに済むので、PCI DSSの対応が求められず、安全かつ簡単に決済を導入することができます。今回はRuby/Sinatraを使ったサンプルを基に、実装方法を紹介します。

決済画面を表示する

まず最初に決済を行う画面を表示します。この時必要になるのはPAY.JPの公開キーです。これは設定画面のAPIキーの中で確認できます。これを下記HTMLの YOUR_PUBLIC_KEY と書き換えます(コード1)。

<form action="/pay" method="post">
  <article>
    <label>1000円のお支払い</label>
  </article>
  
  <script class="payjp-button"
    src="https://checkout.pay.jp/"
    data-key="YOUR_PUBLIC_KEY">
  </script>
</form>

コード1

f:id:goofmint:20171108144507p:plain

なお、formタグの /pay は自社のWebサイトの決済処理用のURLになります。

この状態でWebページを表示すると カードで支払う ボタンが表示されます。

f:id:goofmint:20171108144526p:plain

PAY.JPでの処理

そしてボタンを押すとモーダルでPAY.JPの決済フォームが表示されます。テストで行う場合にはテストカード | PAY.JPからテスト用のクレジットカード番号を選んでください。テストの場合、有効期限やCVC、名前は適当で問題ありません。

f:id:goofmint:20171108144539p:plain

そして処理が完了すると、フォームのイベントである POST /pay がすぐに呼ばれます。

サーバでの処理

PAY.JPでクレジットカード番号からトークンに変換されると、その情報は payjp-token という名前でPOSTされてきます。そのまま使うこともできますし、今後繰り返し使っていくのであれば顧客情報と結びつけることもできます。

以下は顧客情報と結びつける場合です。

customer = Payjp::Customer.create(
  :email => 'example@pay.jp',
  :card  => params['payjp-token']
)

レスポンスであるcustomer.idを自社のデータベースに保存しておきます。こうするとトークンが繰り返し使えるようになります。

実際の決済処理は次のようになります。トークンではなく、customer.id を指定しているのが特徴です。

amount = 1000
Payjp::Charge.create(
    :amount => amount,
    :currency => 'jpy',
    :customer => customer.id,
    :description => '決済に関する説明'
)

例えばECコマースのユーザ情報と結びつけることで、二度目以降はクレジットカード番号の入力を不要にできます。

なお、このSinatraのサンプルコードはpayjp/payjp-exampleにアップロードされています。実装時の参考にしてください。

入金関連の機能を追加しました

PAY.JPでは日々機能の追加を行なっています。

今回お問い合わせに寄せられたご要望にお応えして入金関連の機能を2つ追加いたしました。

  1. テストモードで入金オブジェクトを作成するようにしました

    今まで入金オブジェクトは入金が発生しないテストモードでは作成していなかったのですが、テストモードでも確認したいとの要望があり作成することにしました。

    テストモードの入金オブジェクトはプランの締め日に応じて月1,2回入金準備中もしくは入金繰越しステータスで作成されます。 テストモードでは実際に入金されることはありません。

  2. 入金の内訳CSVに項目を追加しました

    入金の内訳CSVで顧客のデータや手数料を把握したいとの要望があり以下の項目を追加しました。

    • fee_rate : 手数料率
    • fee : 手数料
    • customer[email] : 顧客のメールアドレス
    • customer[description] : 顧客の概要

PAY.JPでは今後も機能を拡張していきます。 何かご要望がありましたらお問い合わせからご連絡をいただけると幸いです。

PAY.JP で Google Chrome の Payment Request API を使って決済する

こんにちは @wozozo です花金です。

Android の Google Chrome 53 以降、デスクトップ版の Chrome 60 以降では Payment Request API に対応しています。これに対応しているブラウザであれば、毎回クレジットカード情報の入力をすることなく Google Chrome に保存されているカード情報を使って簡単に決済を行うことが可能です。

f:id:payjp:20170609145950p:plain

まず前提として、Payment Request API が提供する機能は決済に必要なカード情報の受け渡しであり、カード情報を受け取ったにあとに実際に決済を行うためには PAY.JP のような決済ゲートウェイを別途利用する必要があります。

ECサイトによって必要な機能の違いはあると思いますが、クライアント側の実装は基本的に以下のコードだけで済みます。 (Google Developers のサイトにサンプルコードが掲載されているのをほぼそのまま貼り付けました)

<script type="text/javascript" src="https://js.pay.jp/"></script>
<script>
// payjpjs のセットアップ
Payjp.setPublicKey("pk_test_0383a1b8f91e8a6e3ea0e2a9");

function onBuyClicked() {
  if (!window.PaymentRequest) {
    // PaymentRequest API is not available. Forwarding to
    // legacy form based experience.
    location.href = '/checkout';
    return;
  }

  // Supported payment methods
  var supportedInstruments = [{
      supportedMethods: ['basic-card'],
      data: {
        supportedNetworks: [
          'visa', 'mastercard', 'amex', 'discover',
          'diners', 'jcb', 'unionpay'
        ]
      }
  }];

  // Checkout details
  var details = {
    displayItems: [{
      label: 'ダンベル40kg + 20kgサービス',
      amount: { currency: 'JPY', value: '10800' }
    }, {
      label: '送料',
      amount: { currency: 'JPY', value: '20000' }
    }],
    total: {
      label: '合計',
      amount: { currency: 'JPY', value : '30800' }
    }
  };

  // 1. Create a `PaymentRequest` instance
  // 1. `PaymentRequest` インスタンスを生成する
  var request = new PaymentRequest(supportedInstruments, details);

  // 2. Show the native UI with `.show()`
  // 2. `.show()` を呼び出して、ネイティブ UI を表示する
  request.show()
  // 3. Process the payment
  // 3. 決済処理をおこなう
  .then(result => {
    // POST the payment information to the server

    const card = {
        number: result.details.cardNumber,
        exp_month: result.details.expiryMonth,
        exp_year: result.details.expiryYear,
        cvc: result.details.cardSecurityCode,
    };

    Payjp.createToken(card, function(status, response) {
      if (status == 200) {
        document.getElementById('result').innerText = `PAY.JP Token: ${response.id}`;
        return result.complete('success');
      } else {
        // handle error like displaying error message.
        return result.complete('fail');
      };
    });

  });
}

document.querySelector('#start').addEventListener('click', onBuyClicked);
</script>

コード自体の説明は元のページで解説されているのでご覧ください。

実際に決済をする場合、生のカード番号・有効期限・CVC等を載せて PAY.JP にリクエストを送る必要がありますが、それらの情報はコード中2番の request.show() を呼び出した後、3番の then に PaymentResponse という形で入ってきます。

f:id:payjp:20170609150612p:plain

生カード番号をサーバー側で一時的にも受け取らなくていいように、ここでは payjp.js SDK を使用しています。これを使うと、iframe 上で PAY.JP ドメインと https で通信をしてカード番号をトークン化したものが返却されます。このトークンを使用することで、ECサイト側などではカード情報に一切触れずに決済処理を行うことが可能です。

ここまではクライアント側だけで済ませられますので、このトークンを使用し、通常の PAY.JP 決済と同様にサーバー側で charge を作成すると決済が完了します。(カード番号やCVCは決して保存しないでください。)

サーバー側のサンプルコードは下のようになります。

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const payjp = require('payjp')('sk_test_c62fade9d045b54cd76d7036');

app.use(express.static(__dirname + '/views'));
app.use(bodyParser.json());

app.get('/', function (req, res) {
  res.render('index');
})

app.post('/pay-with-token', function (req, res) {
  const query = {
    amount: 30800, // 本来はリクエストの中身から取得,
    currency: 'jpy',
    card: req.body.token // tok_xxx の PAY.JP Token を取得
  };
  payjp.charges.create(query).then((result) => {
    // サーバー側での決済成功時に必要な処理 etc
    res.json({success: true});
  }).catch((err) => {
     console.error(err);
     res.json({success: false});
  });
})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
})

デスクトップ版の Chrome であれば OS を選ばずに使用できます。

f:id:payjp:20170609151208p:plain

モバイル、デスクトップ版いずれの場合も決済ダイアログの「お支払い」ボタンを押した際に CVC の入力が求められますが、ユーザーにはそれ以外の入力は求められません。

https://i.gyazo.com/530c8cbb212653fab6e0d14415fee88b.gif

Payment Request API が使えるブラウザの種類はまだ多くないですが、決済手段の選択肢として必要十分な機能が提供されており、実装もごく少量のコードでできるため、Google Chrome のシェアが多いサイトでは現実的な選択肢の一つとして候補に挙げられると思います。 また、日本ではまだ開始されていないため今回は紹介しませんでしたが、 Android Pay と統合することもでき、Android Pay にクレジットカードが登録されていれば Payment Request API のダイアログ上の選択肢として Visa・Mastercard などの並びに表示されます。

PAY.JP で Payment Request API をぜひお試しください。

記事中に掲載したコードは GitHub にも公開しています。

github.com

参考

年次の定期課金、はじめました

こんにちは、Takumaです。

今までは月に一度課金を実行する月次プランの定期課金のみがサポート対象でしたが、年に一度課金を実行できる年次プランのサポートを本日開始しました。

年次プランとその定期課金の作成

年次プランを作成するには、期間(interval) にyearを指定します。以下が年次プラン作成リクエストのサンプルです。

リクエスト:

curl https://api.pay.jp/v1/plans \
-u sk_test_c62fade9d045b54cd76d7036: \
-d amount=775 \
-d currency=jpy \
-d interval=year \
-XPOST

以下のようなレスポンスが返れば、年次プランの作成は成功です。

レスポンス:

{
  "amount": 775,
  "billing_day": null,
  "created": 1484278427,
  "currency": "jpy",
  "id": "pln_72eb1066416083d0a70d67531751",
  "interval": "year",
  "livemode": false,
  "metadata": {},
  "name": null,
  "object": "plan",
  "trial_days": 0
}

上のプランidを定期課金作成APIで指定すれば、年次の定期課金を作成することができます。以下がサンプルリクエストです。

リクエスト:

curl https://api.pay.jp/v1/subscriptions \
-u sk_test_c62fade9d045b54cd76d7036: \
-d plan=pln_72eb1066416083d0a70d67531751 \
-d customer=cus_5de245838f5c36462b328534b9b4 \
-XPOST

年次定期課金の作成に成功すると以下のようなレスポンスが返ります。

レスポンス:

{
  "canceled_at": null,
  "created": 1484279234,
  "current_period_end": 1515815234,
  "current_period_start": 1484279234,
  "customer": "cus_5de245838f5c36462b328534b9b4",
  "id": "sub_a95d445900798b36b10c72d6b8d6",
  "livemode": false,
  "metadata": {},
  "object": "subscription",
  "paused_at": null,
  "plan": {
    "amount": 775,
    "billing_day": null,
    "created": 1484278427,
    "currency": "jpy",
    "id": "pln_72eb1066416083d0a70d67531751",
    "interval": "year",
    "livemode": false,
    "metadata": {},
    "name": null,
    "object": "plan",
    "trial_days": 0
  },
  "prorate": false,
  "resumed_at": null,
  "start": 1484279234,
  "status": "active",
  "trial_end": null,
  "trial_start": null
}

この時点で、初回分の課金は実行済みです。次回の課金実行日時(current_period_end)は作成日時からちょうど1年後です(上の例だと2018年1月13日 3:47am UTC)。

年次プランについて

年次プランは期間(interval)がyearのプランです。このプランを購読してる定期課金は更新周期が一年になります。

トライアル日数(trial_days)を設定することは可能ですが、課金日(billing_day)を設定することはできません。

プラン変更について

定期課金のプラン変更は、変更前と変更後のプランの期間(interval)が異なる場合でも可能です。

プラン変更時に、課金周期が更新されるのは、以下のいずれかが当てはまるケースです。

  • 日割り課金設定が無効
  • 更新前と更新後のプラン期間が異なる
  • 更新前と更新後のプラン課金日が異なる
  • 変更時にトライアル(trial_end)が付与される

トライアルが付与された場合を除き、プラン変更時には課金が実行されます。 課金金額の計算式等に関して、詳しくはこちらの記事を参照ください。

月次と年次プランを組み合わせて利用することにより、PAY.JPをご利用しているサービスの有料オプションに幅を持たせる事ができます。ぜひご利用ください。