ウェブペイメント (1.1)

Introduction

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

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

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

TLSの実装

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

Web Cashier のフロー

このフローでは、paypay Webページ/PayPay Appを立ち上げるためのコードを作成します。 ユーザーはPayPay Webページ(インストールされている場合はApp)を使用して決済を行います。 加盟店は、APIで支払ステータスの照会や、通知機能を利用し注文の処理を行うことが可能です。

このフローの詳細はこちらを参照してください。

加盟店を登録する

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

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

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

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

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

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 リクエスト時にセットされた情報に無効なデータが含まれています。例)サポートされていない通貨がセットされているなど。
401 OP_OUT_OF_SCOPE 対象APIを呼び出す権限がありません。
400 MISSING_REQUEST_PARAMS 必要なパラメーターが設定されていません。
400 INVALID_PARAMS 設定されたパラメーターが無効です。
401 UNAUTHORIZED 有効なapi keyとsecretがセットされていません。
404 OPA_CLIENT_NOT_FOUND OPAクライアントが見つかりません。
429 RATE_LIMIT 流量制限エラー。
500 SERVICE_ERROR PayPayサービス側で問題が発生しました。
500 INTERNAL_SERVER_ERROR PayPayサービス側で問題が発生しました。
503 MAINTENANCE_MODE メンテナンス中です。

Create a Code

Status Code Description
400 DUPLICATE_DYNAMIC_QR_REQUEST Dynamic QR Codeのリクエストが重複しています。
400 PRE_AUTH_CAPTURE_UNSUPPORTED_MERCHANT この加盟店は PreAuth & Capture をサポートしていません。リクエストパラメータのisAuthorizationにtrueを指定した場合のみ発生する可能性があります。
400 PRE_AUTH_CAPTURE_INVALID_EXPIRY_DATE 有効期限日が最大許容有効期限日の許容限度を超えています。リクエストパラメータのisAuthorizationにtrueを指定した場合のみ発生する可能性があります。
400 DYNAMIC_QR_BAD_REQUEST リクエストヘッダー、クエリパラメータ、またはリクエストボディが不正です。

Delete a Code

Status Code Description
400 DYNAMIC_QR_ALREADY_PAID 指定されたQRコードはすでに使用済みのためリクエストを受け付けることができません。
400 DYNAMIC_QR_BAD_REQUEST リクエストヘッダー、クエリパラメータ、またはリクエストボディが不正です。
404 DYNAMIC_QR_NOT_FOUND 該当のQR codeが見つかりません。

Get payment details

Status Code Description
400 DYNAMIC_QR_PAYMENT_NOT_FOUND 該当の取引が見つかりません。
400 DYNAMIC_QR_BAD_REQUEST リクエストヘッダー、クエリパラメータ、またはリクエストボディが不正です。

Cancel a payment

Status Code Description
400 ORDER_NOT_REVERSIBLE Cancelできない支払いです。

Capture a payment authorization

Status Code Description
202 USER_CONFIRMATION_REQUIRED 増額キャプチャの実施にあたり、ユーザーに通知を送信しています。
400 UNACCEPTABLE_OP トランザクションエラーです。
400 ALREADY_CAPTURED 既に決済完了しています。
400 CANCELED_USER 対象のユーザーが存在しません。
400 ORDER_EXPIRED オーダーの有効期間がすぎています。
400 ORDER_NOT_CAPTURABLE Captureできない支払いです。
400 REAUTHORIZATION_IN_PROGRESS PayPayの処理と競合しています。
400 TOO_CLOSE_TO_EXPIRY リクエストが有効期限に近すぎるため、処理できません。
400 NO_SUFFICIENT_FUND ユーザーの残高が不足しているため決済ができません。
404 RESOURCE_NOT_FOUND オーダーが見つかりません。

Revert a payment authorization

Status Code Description
400 ORDER_NOT_CANCELABLE Revertできない支払いです。
400 UNACCEPTABLE_OP トランザクションエラーです。

Refund a payment

Status Code Description
400 UNACCEPTABLE_OP 返金できません。
400 CANCELED_USER 対象のユーザーが存在しません。
401 USER_STATE_IS_NOT_ACTIVE ユーザーが無効な状態です。
404 RESOURCE_NOT_FOUND オーダーが見つかりません。

Get refund details

Status Code Description
404 NO_SUCH_REFUND_ORDER 対象の返金が存在しません。

タイムアウト

推奨されるタイムアウト設定は、各APIで指定されています。 最も重要なのは、支払いタイムアウトAPIで、読み取りタイムアウト値を30秒以上で設定してください。

タイムアウトが発生した場合、不明な支払いステータスとして扱ってください。

ステータスが不明な決済の処理

ステータスが不明な場合、下記のいずれかの方法で対処してください。

  1. 取引のステータスを照会するため、照会APIを使用してください。 PayPayで取引が失敗になっている、または存在しない場合は、元取引と同様のリクエストを再度行なってください。

  2. キャンセルAPIを使用してください。 キャンセルAPIが提供されている場合は、取引をキャンセルすることもできます。 キャンセルが承認された後、元取引と同様のリクエストを再度行なってください。

画面遷移図

この画面遷移は、決済における表示画面と画面遷移について記載しています。

記載の内容は以下となります。

・決済画面がPC/スマートフォンにおける決済画面遷移フロー

・APIのRequest Parameterと表示画面のマッピング

・リダイレクトについて

このフローの詳細はこちらを参照してください。

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

決済

決済に関して

Create a Code

支払いのためのコードを作成します。作成したコードの有効期限は「expiryDate」に設定されます。

Timeout: 30s

Request Body schema: application/json

Code Creation

merchantPaymentId
required
string (MerchantPaymentId) <= 64 characters

加盟店発番のユニークな決済トランザクションID

required
object (MoneyAmount)
orderDescription
string <= 255 characters
Array of objects (MerchantOrderItem)
metadata
object

加盟店用の追加情報

codeType
required
string

固定文字列「ORDER_QR」をセットしてください

storeInfo
string <= 255 characters

加盟店の店舗情報

storeId
string <= 255 characters

加盟店に紐付く店舗ID

terminalId
string <= 255 characters

店舗に紐付く端末ID

requestedAt
integer (EpochTime)

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

redirectUrl
string

支払い完了後にしダイレクトさせるURL

redirectType
string
Enum: "WEB_LINK" "APP_DEEP_LINK"

リダイレクトの種別

userAgent
string

WEBブラウザのUser agentを設定してください。このパラメーターを設定すると、PayPayアプリが起動し決済完了した後に起動するWEBブラウザを指定することが可能です。 この値は、javascriptのfunction navigator.userAgentを活用することで取得することができます。 このパラメータは、以下のWEBブラウザーをサポートします。(以下のWEBブラウザ以外が設定されると、ユーザのデフォルトブラウザがトランザクション後に起動されます。) ただし、シークレットモードやプライベートブラウズの場合、正しくリダイレクトできません。

  • Android - Chrome, Firefox, UC Browser
  • iOS - Safari, Chrome, Firefox, UC Browser

また、このパラメータを指定しない場合にもユーザのデフォルトブラウザがトランザクション後に起動されます。

isAuthorization
boolean

デフォルトではfalseになります。先にユーザーの残高から決済金額をブロックして、後からキャプチャ(決済)する場合はtrueを設定してください。

authorizationExpiry
integer (EpochTime)

エポックタイムスタンプ(秒単位)。先に決済金額をブロックする場合の有効期限です。加盟店ごとに許可されている有効期間の範囲内で設定してください。

Responses

Request samples

Content type
application/json
{
  • "merchantPaymentId": "string",
  • "amount":
    {
    },
  • "orderDescription": "string",
  • "orderItems":
    [
    ],
  • "metadata": { },
  • "codeType": "string",
  • "storeInfo": "string",
  • "storeId": "string",
  • "terminalId": "string",
  • "requestedAt": 0,
  • "redirectUrl": "string",
  • "redirectType": "WEB_LINK",
  • "userAgent": "string",
  • "isAuthorization": true,
  • "authorizationExpiry": null
}

Response samples

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

Delete a Code

作成したコードを削除します。

Timeout: 15s

Responses

Response samples

Content type
application/json
{
  • "resultInfo":