この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、クラスメソッドの岡です。
7/30にPayPayが開発者向けツール、PayPay for Developersの提供を開始しました!これは嬉しい!
これで自前のサイトやアプリにPayPayの決済を導入できるようになります。
アカウント作成
まずは開発アカウントを作成しましょう。
Sandboxであれば加盟店の情報は登録しなくても利用することができます。
アカウントを作成すると、ブラウザ上でSandboxのAPIを動作確認できるPayPay Labや、API接続時のエラーハンドリングが可能なPayPay Resolveが使えるようになります。
機能
PayPay APIを使った決済フローは以下の4パターンです。
- Webペイメント
- カスタムのモバイルアプリ/WebサイトからPayPayの決済ページ or PayPayアプリにリダイレクトして決済する
- ネイティブペイメント
- カスタムのモバイルアプリ/Webサイトでワンクリックで決済する
- (※事前にpaypayアカウントとの連携が必要)
- 動的ユーザスキャン
- PayPayで決済可能なQRコードを生成してサイト上に表示する
- アプリコール
- PayPayアプリを呼び出して決済する
ECサイト上での決済でユーザーの操作が一番シンプルになるのはネイティブペイメントのようです。
実際YahooショッピングやPayPayモールではネイティブペイメントが使用されています。
SDK
現在、Python/NodeJS/PHP/Javaの4種類が提供されています。
API環境
- Sandbox環境:
https://stg-api.sandbox.paypay.ne.jp/
- ステージング環境:
https://stg-api.paypay.ne.jp/
- 本番環境:
https://api.paypay.ne.jp/
試してみる
ダッシュボードを見ると、テストユーザーはまだ公開されていないようなのでユーザー情報が必要ない動的ユーザースキャンのパタンでQRコードの生成まで試してみようと思います。
動的ユーザスキャン
以下は動的ユーザスキャンのユースケースの例です。
- タブレットでの決済
- 自動販売機での決済
- テレビ画面での決済
- 請求書にQRコードを印刷する(レアケース?)
動作確認環境
今回はPythonのSDKを使って試してみます。
- python: 3.8.5
- paypayopa-sdk-python: 0.2.0
PythonのSDKをインストール
$ pip install paypayopa
クライアントをビルド
アカウントを作成するとテスト用のAPIキーとシークレットが生成されているので、ダッシュボードから確認してみてください。
import paypayopa
API_KEY = 'xxx'
API_SECRET = 'xxx'
client = paypayopa.Client(auth=(API_KEY, API_SECRET), production_mode=False)
QRコードを生成
シナリオとして、QRコードを生成するタイミングはユーザーが商品を選んで支払い方法でPayPayを選択した後です。
加盟店側でCreate a QRCodeを実行してPayPayアプリで決済可能なQRコードを生成します。
import paypayopa
import time
request = {
"merchantPaymentId": "oka_pay_20200808_01",
"codeType": "ORDER_QR",
"orderDescription": "ごはん代",
"amount": {
"amount": 1,
"currency": "JPY"
},
"requestedAt": round(time.time()),
"redirectUrl": "https://paypay.ne.jp/", # 決済完了後の遷移先
"redirectType": "WEB_LINK",
"orderItems": [
{
"name": "OKA SAMPLE ITEM",
"category": "food",
"quantity": 1,
"productId": "item_0001",
"unitPrice": {
"amount": 1,
"currency": "JPY"
}
}
]
}
response = client.code.create_qr_code(request)
print(response)
APIのドキュメントを見るとorderItemsはオプションのパラメータになっているんですが、orderItemsが不足しているとSDKでKeyErrorが発生しました。
orderItemsを追加するととりあえずエラーは解消しました。
成功すると以下のようにレスポンスが返ってきます。
{
"resultInfo": {
"code": "SUCCESS",
"message": "Success",
"codeId": "08100001"
},
"data": {
"codeId": "04-F94BKekxxxxxxx",
"url": "https://qr-stg.sandbox.paypay.ne.jp/xxxxxxxxx",
"expiryDate": 1596820951,
"merchantPaymentId": "oka_pay_20200808_01",
"amount": { "amount": 1, "currency": "JPY" },
"orderDescription": "ごはん代",
"orderItems": [
{
"name": "OKA SAMPLE ITEM",
"category": "food",
"quantity": 1,
"productId": "item_0001",
"unit_price": { "amount": 1, "currency": "JPY" }
}
],
"codeType": "ORDER_QR",
"requestedAt": 1596820651,
"isAuthorization": False,
"deeplink": "paypay://payment?link_key=https%3A%2F%2Fqr-stg.sandbox.paypay.ne.jp%2Fxxxxxxxxxxx"
}
}
url
を開くと支払いの詳細情報とQRコードが表示されます。
Sandboxで生成したQRコードの場合、Sandbox用のテストユーザーでQRコードを読まないとエラーになります。
※生成されたQRコードは30秒でタイムアウトになります。(08/23訂正 5分でタイムアウトになります。)
決済結果の参照
加盟店側で決済結果を確認するには、get_payment_detailsをポーリングする必要があります。
merchantPaymentIdを引数で渡します。
response = client.code.get_payment_details("oka_pay_20200808_01")
print(response)
QRコード生成後であれば以下のようなレスポンスになります。
{
"resultInfo": {
"code": "SUCCESS",
"message": "Success",
"codeId": "08100001"
},
"data": {
"status": "CREATED",
"acceptedAt": 0,
"requestedAt": 0
}
}
キャンセル
キャンセルは、支払いが行われた翌日のAM00:14:59まで使用できます。
AM00:15以降の場合は、キャンセルではなく返金処理の方を実行してください。
response = client.code.cancel_payment("oka_pay_20200808_01")
print(response)
返金
response = client.code.cancel_payment("<merchantPaymentId>")
print(response)
与信をつける場合
与信を実装するには、client.code.create_qr_codeのリクエストに { "isAuthorization": true }
を追加します。
生成したQRコードをユーザーが読み取った後決済を確定します。
決済確定(v2/payments/capture)
request = {
"merchantPaymentId": "oka_pay_20200808_02",
"merchantCaptureId": "oka_pay_20200808_02_cap",
"requestedAt": 1596820951,
"amount": {
"amount": 1,
"currency": "JPY"
},
"orderDescription": "ごはん代"
}
response = client.code.capture_payment(request)
print(response)
与信中のキャンセル
request = {
"merchantRevertId": "merchant_revert_id"
"paymentId": "paypay_payment_id"
"reason": "reason for refund"
}
response = client.code.revert_payment(request)
print(response)