PayPay残高API (1.1)

はじめに

PayPay Open Payment API(OPA)は、様々なシナリオに対応した決済関連操作が設計されており、ユーザーへ快適な決済体験を提供します。 PayPay OPAクライアントとして登録されている場合、決済パートナーは下記の機能が使用可能になります。

  • PayPayユーザーのウォレットから直接支払い金額を引き落とし、決済を完了させる
  • 動的なQRコードを作成し、PayPayアプリで決済を完了させる
  • スムーズな決済を行うため事前にユーザーの認可を取得し、決済フローを確立する
  • PayPayキャッシャーページとWebアプリケーションを統合し、決済を完了させる
  • PayPay OPAが提供する様々なAPIを使用し、独自の決済エクスペリエンスの構築

本書では、PayPay決済パートナー向けに設計したCashback APIに焦点を当てます。

TLSの実装

PayPay Open Payment APIでは、セキュリティ対策としてTLS 1.2以上の使用が必須となっております。TLS1.0およびTLS1.1では接続できませんのでご注意ください。

加盟店を登録する

PayPay OPAの利用を開始するには、事前に定められたプロセスに従ってPayPay加盟店の登録を行なってください。 このプロセスは 情報収集、手動検証、契約確認、およびクレデンシャル情報の発行から構成されます。

PayPayの加盟店として登録された後、以下の項目が設定されます。

  • api key と apiKeySecret
  • webhookの通知先となるエンドポイント
  • クライアントIPのホワイトリスト
  • 加盟店識別子(エージェントクライアントの場合)

これらの設定を管理するには、マーチャントパネルを使用するか、弊社までご連絡ください。

ユーザー認可を取得する

PayPayユーザーのウォレットから決済を回収できるようにするには、ユーザーの認可を明示的に取得する必要があります。

ユーザー認可を取得する方法は2つあり、 こちら のアカウントリンクを用いた方法を推奨しております。

ウェブベースでの認可取得に関しては こちら をご参照下さい。 こちらもサポート対象ですが、主に導入中、導入済み加盟店向けとなります。

また、SCOPEには"cashback"を指定して下さい。

API認証

本ドキュメントに記載されているAPIは、HMAC方式での認証が必要です。

Authenticationオブジェクトに必要なパラメーター

Value Description Example
API Key PayPayから発行されたAPI Key APIKeyGenerated
API Key secret PayPayから発行されたAPI Key secret APIKeySecretGenerated
Request URI リクエストURL /v2/codes
Request method HTTPメソッド POST
Epoch 現在のエポックタイムスタンプ(秒単位),
Note : サーバー時刻との差が2分未満である必要があります。
1579843452
Nonce ランダムに生成された文字列。
Note : 任意の文字列、length 8を推奨。
acd028
Request body リクエストで渡されるbody。

{"sampleRequestBodyKey1":"sampleRequestBodyValue1","sampleRequestBodyKey2":"sampleRequestBodyValue2"}

Request content type リクエストヘッダーで渡されるコンテンツタイプ。 application/json;charset=UTF-8;
hash (MD5(Request body, Request content type)) リクエストの本文とコンテンツタイプのハッシュ。以下に記載されているStep1で生成されます。 1j0FnY4flNp5CtIKa7x9MQ==

これらから生成されるサンプルHMAC Authヘッダーは以下の通りです。

hmac OPA-Auth:APIKeyGenerated:NW1jKIMnzR7tEhMWtcJcaef+nFVBt7jjAGcVuxHhchc=:acd028:1579843452:1j0FnY4flNp5CtIKa7x9MQ==

HMAC authヘッダーの生成ステップ

Step 1: MD5アルゴリズムを使用してbodyとcontent-typeをハッシュ化する

サンプルコード

private String requestBody;
private String contentType;

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(contentType.getBytes(StandardCharsets.UTF_8));
md.update(requestBody.getBytes(StandardCharsets.UTF_8));
String hash = new String(
          Base64.getEncoder().encode(md.digest()),
          StandardCharsets.UTF_8);

Note : HTTP GETメソッドの場合など、リクエストの本文がない場合、MD5を生成する必要はありません。代わりに、hashには"empty"がセットされます。

Step 2: HMAC-SHA256でハッシュ化される文字列を生成します。

リクエストの署名には、以下のパラメーターが必要です。

private String requestUrl; //Only the request URI Example: "/v2/codes/payments/dynamic-qr-test-00002"
private String httpMethod;
private String nonce; //Random string
private String epoch;
private String contentType;
private String hash; //Output of step 1
private static final DELIMITER = "\n";

byte[] hmacData = new StringBuilder()
                    .append(path)
                    .append(DELIMITER)
                    .append(method)
                    .append(DELIMITER)
                    .append(nonce)
                    .append(DELIMITER)
                    .append(timestamp)
                    .append(DELIMITER)
                    .append(contentType)
                    .append(DELIMITER)
                    .append(hash != null ? hash : "")
                    .toString()
                    .getBytes(StandardCharsets.UTF_8);

Note : HTTP GETメソッドの場合など、リクエストの本文がない場合、content-typeおよびhashには"empty"がセットされます。

Step 3 : Step2で生成された値と、Key secretを使用してHMACオブジェクトを生成します。

public final String toBase64HmacString() {
    private String apiKeySecret;
    private byte[] dataToSign; //Output from step 2
    try {
      SecretKeySpec signingKey = new SecretKeySpec(apiKeySecret.getBytes(StandardCharsets.UTF_8),
          "HmacSHA256");
      Mac sha256HMAC = Mac.getInstance("HmacSHA256");
      sha256HMAC.init(signingKey);
      byte[] rawHmac = sha256HMAC.doFinal(dataToSign);
      return java.util.Base64.getEncoder().encodeToString(rawHmac);
    } catch (GeneralSecurityException e) {
      LOGGER.error("Unexpected error while creating hash: " + e.getMessage());
      throw new IllegalArgumentException(e);
    }
  }

Step 4 : ヘッダーオブジェクトを生成します。

String authHeader = "hmac OPA-Auth:" + api-key +
":" + macData + ":" + nonce + ":" + epoch + ":" + hash;

Note: macDataはStep3で生成された値を使用してください。また、nonceとepochは、Step2で使用した値を渡す必要があります。

HTTP GETメソッドの場合などリクエストの本文がない場合、hash値は"empty"となるため、ヘッダーオブジェクトは下記の通りとなります。

String authHeader = "hmac OPA-Auth:" + api-key +
":" + macData + ":" + nonce + ":" + epoch + ":empty";

authHeaderの値を、HttpHeader.AUTHORIZATIONにセットして渡してください。
PayPay側で渡ってきたデータをデコードし、SHA256( "key"、requestParams)を再作成します。 再作成したmacDataとヘッダーで渡ってきた値が一致しているかを検証します。

リクエスト時に加盟店(ブランド)を指定する

エージェントクライアントは複数の加盟店(ブランド)を管理する場合があるため、APIのリクエスト時に加盟店識別子をセットする必要があります。 加盟店識別子をセットするには2つの方法があります。

クエリの中にセットする:

assumeMerchant=shop

ヘッダにセットする:

X-ASSUME-MERCHANT: auction

両方を指定した場合、クエリにセットしたパラメーターが優先されます。

エラーハンドリング

PayPay OPAはhttpレスポンスステータスコードとOPAエラーコードを使用してリクエストの成功または失敗を示します。 これらの情報を使用して、どのようなエラー対応をするかを判断できます。 PayPay OPAは以下のhttpレスポンスステータスコードを返します。

レスポンスコード一覧

各API共通レスポンスコード

Status Code Description
200 SUCCESS 正常終了
202 REQUEST_ACCEPTED リクエストを受け付けました。
400 INVALID_REQUEST_PARAMS リクエストによって提供された情報に
無効なデータが含まれています。
例)サポートされていない通貨がセットされて
いるなど。
400 OP_OUT_OF_SCOPE 対象APIを呼び出す権限がありません。
400 MISSING_REQUEST_PARAMS 設定されたパラメーターが無効です。
401 UNAUTHORIZED 有効なapi keyとsecretがセットされていません。
404 OPA_CLIENT_NOT_FOUND OPAクライアントが見つかりません。
429 RATE_LIMIT 一定期間内に送信したリクエストが多すぎます。
500 SERVICE_ERROR サービスエラーが発生しました。
500 INTERNAL_SERVER_ERROR このコードは問題が発生したことを意味します
が、トランザクションが発生したかどうか
正確にはわかりません。
不明な支払いステータスとして処理する必要が
あります。
503 MAINTENANCE_MODE 申し訳ありませんが、定期メンテナンスのためご利用いただけません。

Give Cashback to User

Status Code Description
400 CANCELED_USER 対象のユーザーが存在しません。
400 VALIDATION_FAILED_EXCEPTION リクエストパラメーターが正しくありません。
400 FAILURE トランザクションが重複しています。
401 USER_STATE_IS_NOT_ACTIVE ユーザーのステータスが非アクティブなので、
リクエストを受け入れることができません。
404 FAILURE 取引が失敗しました。
500 UNAUTHORIZED_ACCESS リソースサーバーへの不正アクセスです。

Check Cashback Details

Status Code Description
400 VALIDATION_FAILED_EXCEPTION リクエストパラメーターが正しくありません。
400 TRANSACTION_NOT_FOUND トランザクションが存在しません。
500 UNAUTHORIZED_ACCESS リソースサーバーへの不正アクセスです。

Reverse a given cashback

Status Code Description
400 VALIDATION_FAILED_EXCEPTION リクエストパラメーターが正しくありません。
400 TRANSACTION_NOT_FOUND トランザクションが存在しません。
500 UNAUTHORIZED_ACCESS リソースサーバーへの不正アクセスです。

Check Cashback Reversal Details

Status Code Description
400 VALIDATION_FAILED_EXCEPTION リクエストパラメーターが正しくありません。
400 TRANSACTION_NOT_FOUND トランザクションが存在しません。
500 UNAUTHORIZED_ACCESS リソースサーバーへの不正アクセスです。

Get user authorization status

Status Code Description
401 INVALID_USER_AUTHORIZATION_ID 指定したuserAuthorizationId(PayPayのユーザー認可ID)が無効です。

Get masked user profile

Status Code Description
401 INVALID_USER_AUTHORIZATION_ID 指定したuserAuthorizationId(PayPayのユーザー認可ID)が無効です。

タイムアウト

推奨タイムアウト値は各APIで指定されています。 決済APIのタイムアウト値は30秒以下であってはいけません。 タイムアウトが発生した場合、それは状態が不明な決済として扱ってください。

状態が不明な決済の処理

この状況に対処する方法は2つあります。

  1. 取引の状況を照会するには、照会APIを使用してください。PayPayにおいて元の取引が失敗になっているか存在しない場合は、同じ取引として新しいトランザクションを開始できます。

  2. キャンセルAPIが提供されている場合は、取引をキャンセルすることもできます。キャンセルが承認された後、同じ取引として新しいトランザクションを開始できます。

OPAに関するその他のFAQについては こちら をご覧ください。

ウォレット

ユーザーのウォレット残高に関して

Give Cashback to User

加盟店からユーザーへCashbackを移動

timeout: 30秒

Request Body schema: application/json

CreateCashback

merchantCashbackId
required
string (MerchantCashbackId) <= 64 characters

加盟店側で発行したCashbackのトランザクションを一意に特定するコード

userAuthorizationId
required
string (UserAuthorizationId) <= 64 characters

PayPay内でユーザーを識別するID。

required
object (MoneyAmount)
requestedAt
required
integer (EpochTime)

エポックタイムスタンプ(秒単位)

orderDescription
string <= 255 characters

注文の説明

walletType
string
Enum: "PREPAID" "CASHBACK"
expiryDate
date (ExpiryDate)

付与されたCashbackの有効期限日 期限日の深夜に無効化されます。

metadata
object

加盟店用の追加情報

Responses

Request samples

Content type
application/json
{
  • "merchantCashbackId": "string",
  • "userAuthorizationId": "string",
  • "amount": {
    },
  • "requestedAt": 0,
  • "orderDescription": "string",
  • "walletType": "PREPAID",
  • "expiryDate": null,
  • "metadata": { }
}

Response samples

Content type
application/json
{
  • "resultInfo": {
    }
}

Check Cashback Details

付与されたCashbackのトランザクションの状態を参照します

timeout: 10秒

Responses

Response samples

Content type
application/json
{
  • "resultInfo": {
    },
  • "data": {
    }
}

Reverse a given cashback

ユーザーに付与されたCashbackをキャンセルします

timeout: 40秒

Request Body schema: application/json

CreateCashbackReversal

merchantCashbackReversalId
required
string (MerchantCashbackReversalId) <= 64 characters

Cashbackをキャンセルする際に、加盟店側で発行したCashbackのトランザクションを一意に特定するコード