都度課金(出荷売上) (1.0)

はじめに

本書では、主にオンデマンドサービスやeコマースWebサイト向けの事前にユーザーのウォレットから決済金額をブロックする機能について説明します。 加盟店が注文を作成する際に、ユーザーのウォレットから必要な金額をブロックし、注文が確定した際にユーザーから決済金額を回収することができます。

TLSの実装

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

加盟店を登録する

PayPay OPAの利用を開始するには、事前に定義されたプロセスに従って、PayPay加盟店として登録をしなければなりません。 このプロセスは 情報収集、手動検証、契約確認、およびクレデンシャル情報の発行から構成されます。 このプロセスが完了すると、加盟店はPayPayプラットフォームに登録され、 QRコードスキャンとPOS統合によってPayPayユーザーからオフラインでの決済を回収する準備が整います。 オンライン決済統合の場合、加盟店用にOPAクライアントが作成され、以下の項目が設定されます。

  • api keyとsecret
  • 許可された認可コールバックドメイン
  • ユーザー認可有効期間
  • Webhookエンドポイント
  • クライアントIPホワイトリスト

これらの設定はすべて、登録プロセス中に作成された加盟店ログインアカウントで管理されます。

ユーザーからのPayPayアプリ、PayPayWeb画面への日本国外からのアクセスは制限されています。詳細については個別にご相談ください。

ユーザー認可を取得する

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

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

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

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

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 Success
400 INVALID_REQUEST_PARAMS The infomation provide by the request contains invalid data. E.g. unsupported currency
400 OP_OUT_OF_SCOPE The operation is not permitted
400 MISSING_REQUEST_PARAMS
401 UNAUTHORIZED No valid api key and secret provided
404 OPA_CLIENT_NOT_FOUND OPA Client not found
429 RATE_LIMIT Too many requests.
500 SERVICE_ERROR
500 INTERNAL_SERVER_ERROR This code means that something goes wrong, but we don't konw exactly if the transaction has happened or not. It should be treatd as unknown payment status
503 MAINTENANCE_MODE Sorry, we are down for scheduled maintenance.

Create a payment authorization

Status Code Description
400 CANCELED_USER Canceled user
400 INVALID_PARAMS Invalid parameters received
400 NO_SUFFICIENT_FUND The user's balance is insufficient to make payment.
400 UNSUPPORTED_PAYMENT_METHOD Payment method is not supported
400 PRE_AUTH_CAPTURE_UNSUPPORTED_MERCHANT Merchant do not support Pre-Auth-Capture
400 PRE_AUTH_CAPTURE_INVALID_EXPIRY_DATE Provided Expiry Date is above the allowed limit of Max allowed expiry days
400 NO_SUFFICIENT_FUND No sufficient fund
400 SUSPECTED_DUPLICATE_ORDER

If a merchant tries collect same amount money from same user again within 5 minutes, the request would be rejected with this very error code. This design is mainly to prevent the duplicated payments which are usually caused by design flaws in client code.

However, sometimes, the merchant would intentionally collect mutiple same amount payments from a single user. In such case, the client need to send a specific parameter in order to bypass the duplication check. This is detailed in the payment creation api spec.

400 UNACCEPTABLE_OP The requested operation is not able to be processed due to the current condition. E.g. the transaction limit exceeded
401 USER_STATE_IS_NOT_ACTIVE Inactive user
401 INVALID_USER_AUTHORIZATION_ID If the user authorization id is expired or revoked by the use. The client need to go through the authorization flow again to get the user authorization id
401 EXPIRED_USER_AUTHORIZATION_ID The user authorization ID expired
404 NO_VALID_PAYMENT_METHOD No available payment method
404 PAYMENT_METHOD_NOT_FOUND Payment method not found
500 TRANSACTION_FAILED This code means the transaciton is failed in PayPay side. You can create new transaction for the same purpose with reasonable backoff time

Cancel a payment authorization

Status Code Description
400 ORDER_NOT_REVERSIBLE This code will be returned if the status of the target order is other than "AUTHORIZED". Revert cannot be performed because the status is not "AUTHORIZED".

Capture a payment authorization

Status Code Description
202 USER_CONFIRMATION_REQUIRED User confirmation required as requested amount is above allowed limit
400 CANCELED_USER Canceled user
400 ORDER_NOT_CAPTURABLE Order is not capturable.
400 INVALID_PARAMS Invalid parameters received
400 NO_SUFFICIENT_FUND The user's balance is insufficient to make payment.
400 ORDER_EXPIRED Order cannot be captured or updated as it has already expired.
400 REAUTHORIZATION_IN_PROGRESS Order is being reauthorized
400 ALREADY_CAPTURED Cannot capture already captured acquiring order.
400 TOO_CLOSE_TO_EXPIRY Order cannot be reauthorized as request is too close to expiry time
400 NO_SUFFICIENT_FUND No sufficient fund
400 UNACCEPTABLE_OP The requested operation is not able to be processed due to the current condition. E.g. the transaction limit exceeded
401 USER_STATE_IS_NOT_ACTIVE Inactive user
404 RESOURCE_NOT_FOUND Order not found
500 BACKEND_TIMEOUT Timeout occurred while accessing external service

Revert a payment authorization

Status Code Description
400 INVALID_PARAMS Invalid parameters received
400 ORDER_NOT_CANCELABLE Order is not cancelable.
404 RESOURCE_NOT_FOUND Order not found

Refund a payment

Status Code Description
400 INVALID_PARAMS Invalid parameters received
400 UNACCEPTABLE_OP Order cannot be refunded
400 CANCELED_USER Target user does not exist.
401 USER_STATE_IS_NOT_ACTIVE The request cannot be accepted because the user status is Inactive.
404 NO_SUCH_REFUND_ORDER The specified refund payment could not be found.
404 RESOURCE_NOT_FOUND Order not found

Get refund details

Status Code Description
404 NO_SUCH_REFUND_ORDER Refund not found

Create a topup QR Code

Status Code Description
400 DUPLICATE_TOPUP_QR_REQUEST Topup QR with same merchantTopUpId exists.

Get topup status

Status Code Description
404 TOPUP_DETAILS_NOT_FOUND Invalid merchantTopUpId.

Delete QR code

Status Code Description
404 TOPUP_QR_CODE_NOT_FOUND Invalid QR codeId.
400 TOPUP_ALREADY_DONE The topup has been done for given qrCodeId.
Status Code Description
401 INVALID_USER_AUTHORIZATION_ID 指定したuserAuthorizationId(PayPayのユーザー認可ID)が無効です。

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)が無効です。

Check user wallet balance

Status Code Description
400 CANCELED_USER Canceled user

Timeout

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

状態が不明な決済の処理

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

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

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

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

画面遷移図

この画面遷移図は購入操作後のアプリの表示について記載しています。

APIのRequest Parameterと表示画面のマッピングはこちらを参照してください。

購入操作後のアプリの表示はこちらを参照してください。

決済

決済・取消に関して

Create a payment authorization

決済金額をブロックするための支払いAuthorizationを作成する

Timeout: 30s

query Parameters
agreeSimilarTransaction
string

(オプション)パラメータが「true」に設定されている場合、決済重複チェックはバイパスされます。

Request Body schema: application/json

Payment

merchantPaymentId
required
string (MerchantPaymentId) <= 64 characters

加盟店発番のユニークな決済取引ID

userAuthorizationId
required
string (UserAuthorizationId) <= 64 characters

ユーザー認可フローによって返却されたPayPayユーザー認可ID

required
object (MoneyAmount)
requestedAt
required
integer (EpochTime)

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

expiresAt
integer (EpochTime)

エポックタイムスタンプ(秒単位)。加盟店ごとに許可されている有効期間の範囲内で設定してください。

storeId
string <= 255 characters

加盟店に紐付く店舗ID

terminalId
string <= 255 characters

店舗に紐付く端末ID

orderReceiptNumber
string <= 255 characters

加盟店発番の注文番号

orderDescription
string <= 255 characters

取引の説明

Array of objects (MerchantOrderItem)
metadata
object

加盟店用の追加情報

Responses

Request samples

Content type
application/json
{
  • "merchantPaymentId": "string",
  • "userAuthorizationId": "string",
  • "amount":
    {
    },
  • "requestedAt": 0,
  • "expiresAt": null,
  • "storeId": "string",
  • "terminalId": "string",
  • "orderReceiptNumber": "string",
  • "orderDescription": "string",
  • "orderItems":
    [
    ],
  • "metadata": { }
}

Response samples

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