Complete a payment using PayPal

Once PayPal is enrolled as a valid tender in the wallet, completing a payment using it requires a slightly different call sequence than a standard payment in that the app must retrieve the PayPalClientMetadataId and pass it with the transaction call to secure payment approval.

Payment screen flow

Figure 5: Payment screen flow

As Figure 5 illustrates, the screen flow in the app for a payment made using PayPal as the tender is identical to that of a payment using any other form of tender. The only difference is that the app must obtain the payPalClientMetadataId (CMID) directly from the Braintree service (external to the Paydiant SDK) and pass the returned value as an extended attribute of the payment tender during the transaction. Figure 6 shows the specific points of integration for this flow.

Payment sequence diagram

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 obtain the PayPal Client Metadata ID (CMID) from Braintree and pass it as an extendedPaymentTenderData key/value property of the extendedPaymentInstrument object representing PayPal as the transaction payment tender.

  1. Retrieve the PayPal Client Metadata ID value for use in the payment call by including the following definition in your payment processing fragment:

    OS Command
    iOS NSString *CMID = [BTDataCollector payPalClientMetadataId];
    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 unneccessarily should the user not select PayPal as the tender.

  2. Invoke the Paydiant 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
    Paydiant’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_PAYMENT for this instance.
    extendedPaymentInstruments Object
    The PDExtendedPaymentInstrument instance that represents the user’s registered PayPal tender in the wallet. This instance MUST include the PayPal CMID as a key/value instance in the PDExtendedPaymentTenderData attribute.

    Note: Do NOT include the paymentAccounts attribute in the PDUpdateTransactionRequest instance when the extendedPaymentInstruments attribute is populated. The two attributes are mutually exclusive and if paymentAccounts exists, extendedPaymentInstruments data will be ignored and the CMID will not be passed and the payment will fail.

  3. Implement the device OS-specific Paydiant 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.

  4. Implement the device OS-specific Paydiant 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 Paydiant’s OS-specific SDK guides for complete error information related to this call.


Sample updateTransaction for iOS

// Filter payment account display to show only valid tender for the merchant.
if (self.eligiblePaymentAccounts.count > 0) {
    if(response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleProcessPayment || response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleSubmitPaymentTenders) {
        self.currentUpdateTransactionRequest.executingTransactionFlowRule = response.nextExecutingTransactionFlowRule;
        if(response.nextTransactionFlowRuleSpecification.expectsPaymentTenders) {
            [self displayEligiblePaymentAccounts];

        // When PayPal is selected, get the CMID and populate the
        // extendedPaymentInstrument instance.
        - (void)continueTransactionWithPayPal:(PDPaymentAccount *)payPalAccount {
            NSString *CMID = [BTDataCollector payPalClientMetadataId];
            PDExtendedPaymentInstrument *extendedPaymentInstrument = [PDExtendedPaymentInstrument new];
            extendedPaymentInstrument.paymentAccountUri = payPalAccount.accountIdentifier.accountUri;
            PDExtendedPaymentTenderData *extendedPaymentTenderData = [PDExtendedPaymentTenderData new];
            extendedPaymentTenderData.extendedPaymentTenderDataKey = @"CLIENT_METADATA_ID";
            extendedPaymentTenderData.extendedPaymentTenderDataValue = CMID;
            extendedPaymentInstrument.extendedPaymentTenderData = [NSArray arrayWithObject:extendedPaymentTenderData];
            NSArray *paymentInstruments = [NSArray arrayWithObject:extendedPaymentInstrument];
            self.currentUpdateTransactionRequest.extendedPaymentInstruments = paymentInstruments;
            [self updateTransaction];

        // Complete the transaction and get the receipt details.
        PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];
        [transactionCoordinator updateTransaction:self.currentUpdateTransactionRequest completionBlock:^(PDUpdateTransactionResponse *response) {
                [CommonUtil hideProgressIndicatorOnView:self];
                [self getLastTransactionReceipt];
                self.displayCodeView.hidden = YES;
                self.scanView.hidden = YES;
                self.releaseTokenBTN.hidden = YES;

Sample updateTransaction Android

if (transactionMetaDataResponse.getNextExecutingFlowRule().equals(TransactionFlowRule.PROCESS_PAYMENT)) {
    TransactionParameters transactionParameters = new TransactionParameters();
    for (TransactionFlowRuleSpecification flowRuleSpecification: transactionMetaDataResponse.getTransactionFlowRuleSpecifications()) {
        if (flowRuleSpecification.getTransactionFlowRule().equals(transactionMetaDataResponse.getNextExecutingFlowRule())) {
            // Some offers and loyalty logic omitted. See full sample app for
            // complete fragment.
            if (flowRuleSpecification.isExpectsPaymentTenders()) {
                if (extendedPaymentInstrumentsList != null && extendedPaymentInstrumentsList.size() & gt; 0) {
                    final String clientToken = DataCollector.getPayPalClientMetadataId(getActivity());
                    List & lt;
                    AdditionalData & gt;
                    additionalDatas = new ArrayList & lt; & gt;
                    AdditionalData additionalData = new AdditionalData();
                    Log.v(TAG, "CLIENT_METADATA_ID: " + clientToken);
                    ExtendedPaymentInstrument extendedInstrument = new ExtendedPaymentInstrument();
                    List & lt;
                    ExtendedPaymentInstrument & gt;
                    extendedInstrumentList = new ArrayList & lt;
                    ExtendedPaymentInstrument & gt;
    // Configure the response callbacks and complete the transaction.
    if (transactionResponse.getTransactionStatus().equals(TransactionStatus.CLOSED)) {
        AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
        alert.setPositiveButton(getString(R.string.button_label_ok), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                Intent receiptIntent = new Intent(getActivity(), PaymentReceiptActivity.class);
                Bundle bundle = new Bundle();
                bundle.putString(PaymentReceiptActivity.ARG_REF_ID, transactionResponse.getTransactionKey().getPaydiantReferenceId());
        alert.setMessage("You paid" + transactionResponse.getTransactionDetail().getCurrentPaymentResult().getCurrencyCode() +
            " " + transactionResponse.getTransactionDetail().getCurrentPaymentResult().getPaidOrRefundAmount());;
    } else {
        AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
        alert.setPositiveButton(getString(R.string.button_label_ok), null);
        alert.setMessage("payment error");;

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

In addition to compliance with the minimum PayPal receipt requirements, Paydiant considers it a best practice to also include the unmasked user identifier and the PayPal customer email on all printed receipts and mobile transaction summary and history screens.

POS handling for printed receipts

To obtain the property values returned by PayPal upon payment authorization on a printed receipt:

  1. Review the updateTransaction:SUBMIT_TICKET response at the completion of the transaction to determine whether PayPal was used as a tender. If any of the transactionDetails » processedPaymentResults » paymentInstrumentUri values include the suffix #PayPal, the receipt must show the authorization ID.

  2. In the same updateTransaction:SUBMIT_TICKET response, capture the following custom property values passed in the transactionDetails » processedPaymentResults » posReceivedMetaData:

    • EXTERNAL_TRANSACTION_ID is the authorization ID.
    • CUSTOMER_PAYER_ID is the PayPal user identifier.
    • CUSTOMER_PAYER_EMAIL is 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:

  1. 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 » paymentAccountUri values include the suffix #PayPal, add the approval data to the receipt.

  2. In the same updateTransaction (PROCESS_PAYMENT) response, capture the following custom property values passed in the transactionDetails » paymentResult » receiptMetadata:

    • EXTERNAL_TRANSACTION_ID is the authorization ID.
    • CUSTOMER_PAYER_ID is the PayPal user identifier.
    • CUSTOMER_PAYER_EMAIL is the PayPal user account.