iPhoneアプリでの事前承認支払い(Future Payments)

ここでは、PayPalアカウントを使用してFuture Paymentsを行うためにユーザーの同意を得る方法を説明します。
まだ実行していない場合は、プロジェクトにSDKを追加するための基本的な概要と手順のREADMEを参照してください。

概要

ご使用のアプリは、モバイルSDKを使って異なるタイミングで2つの情報を取得します。
最初に、PayPalアカウントからの支払いを行うため、お客さまの同意を得る必要があります。これは以下のように実行されます。
PayPal iOS SDKは

  • ユーザーがPayPal アカウントの使用を承認するためのUI を表示します。
  • Future PaymentsでPayPal を使用するためのOAuth アクセストークンスコープに対する同意をユーザーに求めます。
  • アプリに、OAuth2 の認可コードを返します。

アプリは

  • SDKからOAuth2の認可コードを受け取ります。
  • サーバーに認可コードを送ります。サーバーはコードをOAuth2のアクセストークンおよびリフレッシュトークンと交換します。


後に、事前承認された支払いの開始時に、Client Metadata IDを取得する必要があります。これは以下のように実行されます。

PayPal iOS SDKは
  • Client Metadata IDを提供します。


アプリは
  • Client Metadata IDと取引情報をサーバーに送ります。
  • サーバーは、OAuth2のトークン、Client Metadata ID、および取引情報を使用して支払いを作成します。

お客さまの同意を得る

1.SDKを初期化し、クライアントIDを入力します。この操作は通常、AppDelegateのdidFinishLaunchingWithOptions:メソッドで行います。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // ...
  [PayPalMobile initializeWithClientIdsForEnvironments:@{PayPalEnvironmentProduction : @"YOUR_CLIENT_ID_FOR_PRODUCTION",
                                                         PayPalEnvironmentSandbox : @"YOUR_CLIENT_ID_FOR_SANDBOX"}];
  // ...
  return YES;
}
                            

※本番環境からクライアントIDを取得していない場合は、PayPalEnvironmentProductionの項目を省略できます。

2.PayPalFuturePaymentDelegateの下位のクラス(UIViewControllerのサブクラスとしてなど)を作成します。

// SomeViewController.h
#import "PayPalMobile.h" 
@interface SomeViewController : UIViewController<PayPalFuturePaymentDelegate>
// ...
@end
                            


3.PayPalConfigurationオブジェクトを作成します。このオブジェクトにより、SDKのさまざまな側面を設定できます。

// SomeViewController.m 
@interface SomeViewController ()
// ...
@property (nonatomic, strong, readwrite) PayPalConfiguration *payPalConfiguration;
// ...
@end
 @implementation SomeViewController
 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  self = [super initWithCoder:aDecoder];
  if (self) {
    _payPalConfiguration = [[PayPalConfiguration alloc] init];
     // 値の詳細とデフォルト値はPayPalConfiguration.hを参照してください。
     // 最低限3つのマーチャント情報プロパティを設定する必要があります。
    // これらは、アプリを登録した際にPayPalに提供した値と同じである必要があります。
    _payPalConfiguration.merchantName = @"Ultramagnetic Omega Supreme";
    _payPalConfiguration.merchantPrivacyPolicyURL = [NSURL URLWithString:@"https://www.omega.supreme.example/privacy"];
    _payPalConfiguration.merchantUserAgreementURL = [NSURL URLWithString:@"https://www.omega.supreme.example/user_agreement"];

   }  
return self;
}                            


4.環境を確立し、PayPalのサーバーに事前接続します。
ユーザーが支払いを開始する可能性のあるビューコントローラーを最初に表示する際に行うことをおすすめします(接続時間は制限されているため、コントローラーの表示よりもかなり前に事前接続することはしないでください)。

// SomeViewController.m
 
- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
 
  // モック環境で作業を開始してください。準備完了後、PayPalEnvironmentProductionに切り替えます。
  [PayPalMobile preconnectWithEnvironment:PayPalEnvironmentNoNetwork];
}
                            

5.設定を使用してPayPalFuturePaymentViewControllerを作成および表示します。

// SomeViewController.m
 
- (IBAction)obtainConsent {
 
  PayPalFuturePaymentViewController *fpViewController;
  fpViewController = [[PayPalFuturePaymentViewController alloc] initWithConfiguration:self.payPalConfiguration
                                                                             delegate:self];
 
  //PayPalFuturePaymentViewControllerを表示します。
  [self presentViewController:fpViewController animated:YES completion:nil];
}
 
                            

6.PayPalFuturePaymentDelegateデリゲートメソッドを実装し、成功時の認可応答やユーザーによるキャンセルの通知を受信します。 実装により、モーダルビューコントローラーを破棄する必要があります。

  // SomeViewController.m
 
  #pragma mark - PayPalFuturePaymentDelegateメソッド
 
  - (void)payPalFuturePaymentDidCancel:(PayPalFuturePaymentViewController *)futurePaymentViewController {
    // ユーザーがログインをキャンセルしました。PayPalLoginViewControllerを破棄します。
    [self dismissViewControllerAnimated:YES completion:nil];
  }
 
  - (void)payPalFuturePaymentViewController:(PayPalFuturePaymentViewController *)futurePaymentViewController
                  didAuthorizeFuturePayment:(NSDictionary *)futurePaymentAuthorization {
    // ユーザーは、問題なくPayPalにログインし、Future Paymentsに同意しました。
 
    // ここでコードはサーバーに認可応答を送信する必要があります。
    [self sendAuthorizationToServer:futurePaymentAuthorization];
 
    // 必ずPayPalLoginViewControllerを破棄してください。
    [self dismissViewControllerAnimated:YES completion:nil];
}
                            

7.プロセスを完了するため、サーバーに認可応答を送信します。

// SomeViewController.m
 
- (void)sendAuthorizationToServer:(NSDictionary *)authorization {
  // 認可応答全体を送信します
  NSData *consentJSONData = [NSJSONSerialization dataWithJSONObject:authorization
                                                        options:0
                                                          error:nil];
 
  // (ここにネットワークコードを記述します)
  //
  // 認可応答をサーバーに送信すると
  // 認可コードをOAuthのアクセストークンおよびリフレッシュトークンと交換できます。
  //
    // サーバーはこれらのトークンを保管するので、サーバーコードは、今後このユーザーの
    // 支払いを実行できます。
}
                            

Client Metadata IDの取得

モバイル端末から事前承認された支払い(「Future Payments」)を開始する場合、モバイルアプリは、Client Metadata IDをモバイルSDKから取得し、サーバーに渡す必要があります。サーバーは、PayPalに送信する支払いリクエストにこのClient Metadata IDを含める必要があります。
PayPalは、このClient Metadata IDを使用して、ユーザーが同意した有効な端末およびアプリから支払いが行われていることを認証します。これは、不正取引や拒否を減らすことに役立ちます。PayPalは、適切にClient Metadata IDを提供しない取引での損失についてはいっさい保護しません。
この値をキャッシュまたは格納しないでください。

例:

- (IBAction)paymentButtonTapped:(UIButton *)sender {
 
    // アクティビティインジケーターを表示します。
 
    NSString *metadataID = [PayPalMobile clientMetadataID];
 
    // PayPalでの処理のため、相関IDと取引の詳細をサーバーに送信します。
}
                        

サーバーは、PayPalへの支払いリクエストを作成する際、HTTPヘッダーPayPal-Client-Metadata-Idに、SDKから取得したこのClient Metadata IDの値を含める必要があります。

事前承認に基く支払い

ユーザーが、自分のPayPalアカウントの使用をアプリに承認すると、この承認を使用して、そのユーザーからのFuture Paymentsを作成するトークンを取得できます。
このドキュメントには以下の方法が記載されています。

  1. OAuth2のトークンを取得する
  2. 取得したトークンを使用して支払いを作成する

ユーザーに、アプリでFuture Paymentsを承認し、同意してもらうには、Future Paymentsを参照してください。

OAuth2のトークンを取得する

  1. 認可コードを取得する
  2. 認可コードとリフレッシュ/アクセストークンを交換する

認可コードを取得する
モバイルSDKは、Future Paymentsについてユーザーの承認を得るためのAPIを提供しています。アプリにSDKを統合し、それを使ってユーザーを認証し、ユーザーの同意を得ます。SDKは、PayPal認証サーバーで認証および承認を処理し、OAuth2の認可コードをアプリに返します。
この認可応答はJSONオブジェクトです。
例:

{
    "response_type": "authorization_code",
    "response": {
        "code": "EBYhRW3ncivudQn8UopLp4A28xIlqPDpAoqd7biDLpeGCPvORHjP1Fh4CbFPgKMGCHejdDwe9w1uDWnjPCp1lkaFBjVmjvjpFtnr6z1YeBbmfZYqa9faQT_71dmgZhMIFVkbi4yO7hk0LBHXt_wtdsw",
    },
    "client": {
        "environment": "live",
        "paypal_sdk_version": "2.0.0",
        "platform": "iOS",
        "product_name": "PayPal iOS SDK"
    }
}
                            

アプリは、この認可応答をサーバーに送信する必要があります。サーバーは、次のセクションで説明するように、認可コードと、リフレッシュトークンおよびアクセストークンを交換する必要があります。

認可コードとリフレッシュ/アクセストークンを交換する
サーバーが認可コードを取得すると、これを使用して、有効期限の長いリフレッシュトークンと有効期限の短いアクセストークンを取得できるようになります。サーバーとPayPal APIの通信は、標準的なOAuth2の認可コードグラントアクセスリクエストです。
認可コードには、非常に短い有効期限が設定されています。ただちに認可コードをリフレッシュトークンとアクセストークンに交換する必要があります。
リフレッシュトークンの有効期限は長く、現在のところ10年です。安全に保管する必要があります。
返されるコードやトークンの値はすべて可変長として扱ってください。今後さらに長くなる可能性がありますので、最大長が固定されているものとして扱わないでください。
サンプルリクエスト

    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "Authorization: Basic QWZV...==" \
    -d 'grant_type=authorization_code&response_type=token&redirect_uri=urn:ietf:wg:oauth:2.0:oob&code=EBYhRW3ncivudQn8UopLp4A28...'
                            

  • grant_type: トークンのグラントタイプです。値はauthorization_codeに設定する必要があります。
  • redirect_uri: リダイレクトURLです。値はurn:ietf:wg:oauth:2.0:oobに設定する必要があります。

応答

{
    "access_token": "6oyryV79E.KtpAvPudpI8VIko.ntdPikU9HCDfg0tO0",
    "expires_in": 900,
    "refresh_token": "MFYQJTPW3zlCAjznPs2D0VQlQXwiEfTesR-dRiU_qhbUngzxR3NmeBxqKELcmGtSI739R-awwvOyGVO1LJbowy7n8Ul3vsf5HQDTCzUlDylqBvW0",
    "
                            

  • access_token: 認可サーバーによって発行されたアクセストークンです。
  • expires_in: アクセストークンの秒単位での有効期限です。アクセストークンの期限切れ後、refresh_tokenを使用してアクセストークンを更新します。
  • refresh_token: リフレッシュトークン。OAuth2.0 RFC6749 - セクション6で説明されているように、これにより、同じ認可グラントを使用する新しいアクセストークンを取得することができます。
  • scope: このリフレッシュトークンに関連するスコープ値をスペースで区切ったリストです。
  • token_type: OAuth2.0 RFC6749 - セクション7.1で説明されているタイプの発行済みトークンです。値は、大文字と小文字が区別されます。

支払いの作成

同意したユーザーが後で支払いを開始した場合、サーバーコードで以下を実行する必要があります。

  • ユーザーのリフレッシュトークンを検索し、そのトークンを使用して新しいアクセストークンを取得する
  • 有効なアクセストークンを使用して支払いを作成する

アクセストークンの更新
前述したように、アクセストークンには有効期限があります。アクセストークンの期限が切れた場合は、リフレッシュトークンを使用して新しいアクセストークンを取得する必要があります。
サンプルリクエスト

    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "Authorization: Basic QWZVa...==" \
    -d 'grant_type=refresh_token&refresh_token=MFYQ...'
                            

  • grant_type: トークンのグラントタイプです。値はrefresh_tokenに設定する必要があります。必須です。
  • refresh_token: 更新されるアクセストークンとともに以前に受信したリフレッシュトークンです。必須です。

応答

{
    "access_token": "WfXdnxmyJtdF4q59ofxuQuAAk6eEV-Njm6puht3Nk3w",
    "app_id": "APP-3TS46380HB829954H",
    "expires_in": 900,
    "token_type": "Bearer"
}
                            

有効なアクセストークンを使用した支払いの作成
次のように、アクセストークンをHTTPのAuthorizationヘッダーの値として使用して支払いを完了します。

Authorization: Bearer YOUR_ACCESS_TOKEN

支払いの作成時に、直接の販売や後日支払いを回収する承認を行うことができます。
ヒント:

  • 詳細は支払いの作成を参照してください。
  • モバイル端末から支払いが開始された場合、すべての決済APIリクエストに、[モバイルSDK]を使用して取得されたPayPal-Client-Metadata-Idヘッダー値(future_payments_mobile.md#obtain-an-application-correlation-id)が含まれる必要があります。
  • 1回払いの実例を示す標準的なREST APIのドキュメントとは異なり、Future Paymentsでは、最初にユーザーの同意を得た後は、そのつど支払いの承認を得る必要はありません。支払いは、ユーザーによって事前承認されています。

例: 承認と回収
たとえば、最初に支払いを承認するには、次のようなリクエストを使用します。
サンプルリクエスト

    -H "Content-Type: application/json" \
    -H "PayPal-Client-Metadata-Id: c2edbd6e97b14ff2b19ddb8eec9d264c" \
    -H "Authorization: Bearer WfXdnxmyJtdF4q59ofxuQuAAk6eEV-Njm6puht3Nk3w" \
    -d '{
           "intent":"authorize",
           "payer":{
              "payment_method":"paypal"
           },
           "transactions":[
              {
                 "amount":{
                    "currency":"USD",
                    "total":"1.88"
                 },
                 "description":"future of sauces"
              }
           ]
        }'
                        

応答

{
    "create_time": "2013-10-01T00:43:25Z",
    "id": "PAY-2C433581AX997613HKJFBVLI",
    "intent": "authorize",
    "links": [
        {
            "method": "GET",
            "rel": "self"
        }
    ],
    "payer": {
        "payer_info": {
            "email": "tnm10@paypal.com",
            "first_name": "George",
            "last_name": "Martin",
            "payer_id": "QLR7PGAJCMCA8"
        },
        "payment_method": "paypal"
    },
    "state": "approved",
    "transactions": [
        {
            "amount": {
                "currency": "USD",
                "details": {
                    "subtotal": "1.88"
                },
                "total": "1.88"
            },
            "description": "future of sauces",
            "related_resources": [
                {
                    "authorization": {
                        "amount": {
                            "currency": "USD",
                            "details": {
                                "subtotal": "1.88"
                            },
                            "total": "1.88"
                        },
                        "create_time": "2013-10-01T00:43:25Z",
                        "id": "4TD55050SV609544L",
                        "links": [
                            {
                                "href": "https://api.paypal.com/v1/payments/authorization/4TD55050SV609544L",
                                "method": "GET",
                                "rel": "self"
                            },
                            {
                                "href": "https://api.paypal.com/v1/payments/authorization/4TD55050SV609544L/capture",
                                "method": "POST",
                                "rel": "capture"
                            },
                            {
                                "href": "https://api.paypal.com/v1/payments/authorization/4TD55050SV609544L/void",
                                "method": "POST",
                                "rel": "void"
                            },
                            {
                                "href": "https://api.paypal.com/v1/payments/authorization/4TD55050SV609544L/reauthorize",
                                "method": "POST",
                                "rel": "reauthorize"
                            },
                            {
                                "href": "https://api.paypal.com/v1/payments/payment/PAY-2C433581AX997613HKJFBVLI",
                                "method": "GET",
                                "rel": "parent_payment"
                            }
                        ],
                        "parent_payment": "PAY-2C433581AX997613HKJFBVLI",
                        "state": "authorized",
                        "update_time": "2013-10-01T00:43:28Z",
                        "valid_until": "2013-10-30T00:43:25Z"
                    }
                }
            ]
        }
    ],
    "update_time": "2013-10-01T00:43:28Z"
}
                            

サービスの完了または商品の提供後、支払いを回収します。
サンプルリクエスト

\
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer WfXdnxmyJtdF4q59ofxuQuAAk6eEV-Njm6puht3Nk3w" \
    -d '{
           "amount":{
              "currency":"USD",
              "total":"1.50"
           },
           "is_final_capture":true
        }'
                        

応答

{
    "amount": {
        "currency": "USD",
        "total": "1.50"
    },
    "create_time": "2013-10-01T00:43:28Z",
    "id": "9BS66645698646420",
    "is_final_capture": true,
    "links": [
        {
            "method": "GET",
            "rel": "self"
        },
        {
            "method": "POST",
            "rel": "refund"
        },
        {
            "method": "GET",
            "rel": "authorization"
        },
        {
            "method": "GET",
            "rel": "parent_payment"
        }
    ],
    "parent_payment": "PAY-2C433581AX997613HKJFBVLI",
    "state": "completed",
    "update_time": "2013-10-01T00:43:30Z"
}
                            

stateがcompletedと表示されると、販売は完了です。