Complete a payment using PayPal
Last updated: Aug 15th, 6:18am
Once PayPal is enrolled as a valid tender in the wallet, completing a payment using it requires a slightly different process than a standard payment. The app must first retrieve the clientMetadataID directly from Braintree and pass the value in the transaction call to secure payment approval.
Note: For iOS devices, the app must also parse the serialized CMID object returned by Braintree to isolate the correlation_id value before submitting with the payment call.

Figure 5: Payment screen flow
As Figure 5 illustrates, the screen flow in the app for a payment made using PayPal is unaffected by the additional processing step. Figure 6 shows the specific points of integration for this flow.

Figure 6: Payment sequence diagram
Submit PayPal payment credentials
Follow your usual transaction flow up to the point when the app user selects PayPal as the tender for the transaction. Then invoke the following process to submit a payment request using PayPal as the tender.
- Retrieve the - clientMetadataIDvalue for use in the payment call by including the following definition in your payment processing fragment:- OS - Command - iOS - NSString *CMID = [PPDataCollector collectPayPalDeviceData];- Android - String clientToken = DataCollector.getPayPalClientMetadataId(getActivity());- Note: The call to the Braintree SDK to obtain the CMID can be invoked at any time. Securing the CMID at the beginning of the transaction (as shown in Figure 6) may benefit performance during the transaction, while waiting until after discovery (as in this procedure) may save obtaining the value unnecessarily should the user not select PayPal as the tender. - iOS ONLY Parse the returned string to extract only the value portion of the - correlation_idelement contained in the string.1NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[CMID_Json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];2NSString *CMID = jsonDict[@"correlation_id"];- Invoke the WLW SDK call to submit the PayPal tender selection with CMID value, any offers to be redeemed, loyalty account info, etc., as appropriate for your device. Also provide success and failure responses.
 - OS - Command - iOS - updateTransaction:(PDUpdateTransactionRequest *)request- Android - updateTransaction(TransactionParameters transactionParameters)- Within each of the parameter objects, the following data must be passed: - Property - Description - checkoutToken- Required String 
 The decoded value of the scanned QRCode, which uniquely identifies the transaction in the platform.- transactionKey- Required String 
 WLW’s unique identifier for the transaction.- executingTransactionFlowRule- Required Enum 
 An enum value that specifies the current step of the transaction. Set the value to- PROCESS_PAYMENTfor this instance.- extendedPaymentInstruments- Object 
 The- PDExtendedPaymentInstrumentinstance that represents the user’s registered PayPal tender in the wallet. This instance MUST include the following- PDExtendedPaymentTenderDatakey-value attribute:
 key = "CLIENT_METADATA_ID"
 value = the previously collected CMID (- correlation_idfor iOS) value.- Note: Do NOT include the - paymentAccountsattribute in the- PDUpdateTransactionRequestinstance when- extendedPaymentInstrumentsattribute is populated. The two attributes are mutually exclusive and if paymentAccounts exists,- extendedPaymentInstrumentsdata will be ignored and the CMID will not be passed, causing the payment to fail.
- Implement the device OS-specific WLW SDK callback to handle the success response. - OS - Command - iOS - updateTransactionCompletionBlock:(PDUpdateTransactionResponse *)response- Android - onUpdateTransactionSuccess (TransactionResponse transactionResponse)- The success response will contain information related to the processing of the payment and the final transaction details, including the relevant payment status information from PayPal, if applicable. 
- Implement the device OS-specific WLW SDK callback to handle the failure response. - OS - Command - iOS - updateTransactionFailureBlock:(PDPaydiantError *transactionError);- Android - onTransactionFlowManagementError (PaydiantException exception)
The failure response returns the status code and message indicating the high-level cause of failure, such as 400 BAD_REQUEST. If applicable, the response will include supplemental error information tailored to the relevant domain, such as 416 – Transaction canceled by POS.
Note: Refer to WLW’s OS-specific SDK guides for complete error information related to this call.
Samples
Sample updateTransaction for iOS
1// Filter payment account display to show only valid tender for the merchant.2if (self.eligiblePaymentAccounts.count > 0) {3 if(response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleProcessPayment || response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleSubmitPaymentTenders) {4 self.currentUpdateTransactionRequest.executingTransactionFlowRule = response.nextExecutingTransactionFlowRule;5 if(response.nextTransactionFlowRuleSpecification.expectsPaymentTenders) {6 [self displayEligiblePaymentAccounts];7 }89 // When PayPal is selected, get the CMID, extract the correlation_id, and populate the10 // extendedPaymentInstrument instance.11 - (void)continueTransactionWithPayPal:(PDPaymentAccount *)payPalAccount {12 NSString *CMID_Json = [PPDataCollector collectPayPalDeviceData];13 NSError *error;14 NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[CMID_Json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];15 NSString *CMID = jsonDict[@"correlation_id"];16 PDExtendedPaymentInstrument *extendedPaymentInstrument = [PDExtendedPaymentInstrument new];17 extendedPaymentInstrument.paymentAccountUri = payPalAccount.accountIdentifier.accountUri;18 PDExtendedPaymentTenderData *extendedPaymentTenderData = [PDExtendedPaymentTenderData new];19 extendedPaymentTenderData.extendedPaymentTenderDataKey = @"CLIENT_METADATA_ID";20 extendedPaymentTenderData.extendedPaymentTenderDataValue = CMID;21 extendedPaymentInstrument.extendedPaymentTenderData = [NSArray arrayWithObject:extendedPaymentTenderData];22 NSArray *paymentInstruments = [NSArray arrayWithObject:extendedPaymentInstrument];23 self.currentUpdateTransactionRequest.extendedPaymentInstruments = paymentInstruments;24 [self updateTransaction];25 }2627 // Complete the transaction and get the receipt details.28 PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];29 [transactionCoordinator updateTransaction:self.currentUpdateTransactionRequest completionBlock:^(PDUpdateTransactionResponse *response) {30 [CommonUtil hideProgressIndicatorOnView:self];31 [self getLastTransactionReceipt];32 self.displayCodeView.hidden = YES;33 self.scanView.hidden = YES;34 self.releaseTokenBTN.hidden = YES;35 }36 }37 }38}
Sample updateTransaction Android
1if (transactionMetaDataResponse.getNextExecutingFlowRule().equals(TransactionFlowRule.PROCESS_PAYMENT)) {2 TransactionParameters transactionParameters = new TransactionParameters();3 for (TransactionFlowRuleSpecification flowRuleSpecification: transactionMetaDataResponse.getTransactionFlowRuleSpecifications()) {4 if (flowRuleSpecification.getTransactionFlowRule().equals(transactionMetaDataResponse.getNextExecutingFlowRule())) {5 // Some offers and loyalty logic omitted.6 if (flowRuleSpecification.isExpectsPaymentTenders()) {7 if (extendedPaymentInstrumentsList != null && extendedPaymentInstrumentsList.size() > 0) {8 final String clientToken = DataCollector.getPayPalClientMetadataId(getActivity());9 List <10 AdditionalData >11 additionalDatas = new ArrayList < >12 ();13 AdditionalData additionalData = new AdditionalData();14 additionalData.setKey("CLIENT_METADATA_ID");15 additionalData.setValue(clientToken);16 additionalDatas.add(additionalData);17 Log.v(TAG, "CLIENT_METADATA_ID: " + clientToken);18 ExtendedPaymentInstrument extendedInstrument = new ExtendedPaymentInstrument();19 extendedInstrument.setExtendedPaymentTenderData(additionalDatas);20 extendedInstrument.setPaymentAccountUri(paymentAccountMap.get(data.getStringExtra("tender")));21 List <22 ExtendedPaymentInstrument >23 extendedInstrumentList = new ArrayList <24 ExtendedPaymentInstrument >25 ();26 extendedInstrumentList.add(extendedInstrument);27 }28 }29 }30 transactionParameters.setExtendedPaymentInstruments(extendedInstrumentList);31 transactionParameters.setCheckoutToken(transactionMetaDataResponse.getCheckoutToken());32 transactionParameters.setTransactionKey(transactionMetaDataResponse.getTransactionKey());33 transactionParameters.setExecutingFlowRule(TransactionFlowRule.PROCESS_PAYMENT);34 transactionParameters.setCustomerConfirmationForPOSRequestedPayments(false);35 transactionFlowManagementService.updateTransaction(transactionParameters);36 }37 // Configure the response callbacks and complete the transaction.38 if (transactionResponse.getTransactionStatus().equals(TransactionStatus.CLOSED)) {39 AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());40 alert.setPositiveButton(getString(R.string.button_label_ok), new DialogInterface.OnClickListener() {41 @Override42 public void onClick(DialogInterface dialog, int which) {43 Intent receiptIntent = new Intent(getActivity(), PaymentReceiptActivity.class);44 Bundle bundle = new Bundle();45 bundle.putString(PaymentReceiptActivity.ARG_REF_ID, transactionResponse.getTransactionKey().getPaydiantReferenceId());46 receiptIntent.putExtras(bundle);47 startActivity(receiptIntent);48 }49 });50 alert.setTitle("Success");51 alert.setMessage("You paid" + transactionResponse.getTransactionDetail().getCurrentPaymentResult().getCurrencyCode() +52 " " + transactionResponse.getTransactionDetail().getCurrentPaymentResult().getPaidOrRefundAmount());53 alert.show();54 } else {55 AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());56 alert.setPositiveButton(getString(R.string.button_label_ok), null);57 alert.setTitle("Error");58 alert.setMessage("payment error");59 alert.show();60 }61}
Payment result handling
When the PayPal tender is used as the payment source for a purchase, PayPal requires merchants issuing email notifications, printed receipts, or e-receipts to include the following information on the receipt for all purchases, returns, and voids:
- Tender Type: PayPal
- Currency in which the transaction is conducted
- PayPal Transaction ID
- Date and Time of the transaction
- Merchant name and address
Adhere to the minimum PayPal receipt requirements. WLW best practice also recommends that you include the unmasked user identifier and the PayPal customer email on all printed receipts, mobile transaction summary screens, and history screens.
POS handling for printed receipts
To obtain the property values returned by PayPal upon payment authorization on a printed receipt:
- Review the - updateTransaction:SUBMIT_TICKETresponse at the completion of the transaction to determine whether PayPal was used as a tender. If any of the- transactionDetails » processedPaymentResults » paymentInstrumentUrivalues include the suffix- #PayPal, the receipt must show the authorization ID.
- In the same - updateTransaction:SUBMIT_TICKETresponse, capture the following custom property values passed in the- transactionDetails » processedPaymentResults » posReceivedMetaData:- EXTERNAL_TRANSACTION_IDis the authorization ID.
- CUSTOMER_PAYER_IDis the PayPal user identifier.
- CUSTOMER_PAYER_EMAILis the PayPal user account.
 

App handling for mobile receipts
To obtain the PayPal details for inclusion on the payment confirmation and history screens for transactions where PayPal is a tender:
- Review the - updateTransaction (PROCESS_PAYMENT)response at the completion of the transaction to determine whether PayPal was used as a tender. If any of the- transactionDetails » paymentResults » paymentInstrument » paymentAccountUrivalues include the suffix- #PayPal, add the approval data to the receipt.
- In the same - updateTransaction (PROCESS_PAYMENT)response, capture the following custom property values passed in the- transactionDetails » paymentResult » receiptMetadata:- EXTERNAL_TRANSACTION_IDis the authorization ID.
- CUSTOMER_PAYER_IDis the PayPal user identifier.
- CUSTOMER_PAYER_EMAILis the PayPal user account.
 
Note: For fuel transactions, these required property values are returned in the transactionMetaDataResponse.transactionDetail.currentPaymentRessult.receiptMetaData object.
