STEP 3 Enroll payment methods

DOCS

Last updated: Aug 15th, 6:07am

Once a user has an active wallet account and login credentials set up, the next necessary component is at least one method of payment. One of the strongest aspects of WLW's security is the fact that a user's payment information is not stored on the phone and is not passed to the POS during a transaction. WLW facilitates payment authorization through a secure, tokenized transmission directly from WLW's platform to the processor's server. WLW can interface with virtually any payment processor, so whether the tender is based on a credit card, debit card, store credit, gift card, loyalty reward, PayPal account, or other type of payment, WLW's mobile wallet can support it.

The payment account enrollment steps are:

  1. Get Issuer tender types
  2. Evaluate supported tender types
  3. Submit enrollment request

1. Get Issuer tender types

While WLW supports virtually any type of payment method, each mobile wallet issuer can specify which payment types it will support. Some issuers may only allow gift cards, while others may support major credit cards and their own private label card.

Additionally, each different instrument of payment can have a distinct set of data that is required to both authenticate it for use in the wallet and use it as the source of payment in a transaction. For example, many credit cards require the billing zip code and security code for verification and use, while a gift card may only require the card number.

Consequently, it is important to retrieve the set of supported tenders so the app can prevent users from enrolling payment methods that are prohibited and collect the right data for each form of payment the user wishes to enroll.

IMPLEMENTATION STEPS

  1. Define Payment Account Manager (PAM) service connection.
  2. Set the service listeners to handle callbacks.
  3. Invoke retrieveAllTenderTypes.
  4. Disconnect the service connection and remove the listeners.
  5. Bind the service connection.
    1private final ServiceConnection paymentAccountManagementServiceConnection = new ServiceConnection()
    2{
    3 @Override
    4 @SuppressWarnings("unchecked")
    5 public void onServiceConnected(final ComponentName arg0, final IBinder binder) {
    6 paymentAccountManagementService = ((LocalBinder <PaymentAccountManagementService> ) binder).getService();
    7 paymentAccountManagementService.setPaymentAccountRetrieveListener(paymentListenerAdapter);
    8 paymentAccountManagementService.retrieveAllTenderTypes();
    9 progressBar.setVisibility(View.VISIBLE);
    10 }
    11 @Override
    12 public void onServiceDisconnected(final ComponentName arg0)
    13 {
    14 paymentAccountManagementService = null;
    15 paymentAccountManagementService.removeListener();
    16 }
    17};
    18Intent paymentAccountMgmtIntent = new Intent(this, PaymentAccountManagementService.class);
    19bindService(paymentAccountMgmtIntent, paymentAccountManagementServiceConnection, BIND_AUTO_CREATE);
    20}

    2. Evaluate supported tender types

    The retrieval of supported tender types returns a set of tender type objects, each of which defines the set of data properties that are required or relevant for that particular tender type.

    Before allowing a user to enroll a payment account of a particular type, first evaluate the attributes of that tender type in order to:

    • present only supported tenders to the user for election
    • invoke the appropriate enrollment process
    • collect the right data from the user

    Add,Tender,Flow

    Once the user elects to add a payment account of a particular supported type, evaluate the attributes of the tenderType instance corresponding to the user's selection to determine which process to invoke. For example, if the value of the supportsMultiStepEnrollment attribute is YES, only processes initiated by startPaymentAccountEnrollment are valid. If multi-step is not supported, check to see whether provisioning is supported, etc., and proceed accordingly with either the addPaymentAccount or provisionAccount calls, as appropriate.

    Create a PaymentAccountData Instance

    The PaymentAccountData instance is the repository for the relevant payment account properties you will populate with the user's input and submit with the appropriate enrollment method.

      1PaymentAccountData paymentAccountData = new PaymentAccountData();
      2paymentAccountData.setAdditionalData(getAdditionalDataList());
      3if (selectedTender != null)
      4{
      5 paymentAccountData.setPaymentAccountNetworkTypeUri(selectedTender.getNetworkType().getPaymentAccountNetworkTypeUri());
      6 paymentAccountData.setPaymentAccountTypeUri(selectedTender.getAccountType().getPaymentAccountTypeUri());
      7}

      Compile the Relevant Data

        1List <PaymentAccountMetaData> currentPaymentAccountMetaData = selectedTender.getMetaData();
        2for (PaymentAccountMetaData paymentAccountMetaData: currentPaymentAccountMetaData)
        3{
        4 AdditionalData additionalData = new AdditionalData();
        5 currentViewText = null;
        6 if (paymentAccountMetaData.getDataGroup().equalsIgnoreCase(getResources().getResourceEntryName(R.id.ISSUER_PROVIDED)))
        7 {
        8 additionalData.setKey(paymentAccountMetaData.getKey());
        9 additionalData.setValue(paymentAccountMetaData.getDefaultValue());
        10 additionalDataList.add(additionalData);
        11 continue;
        12 }
        13 if (paymentAccountMetaData.getDataGroup().equalsIgnoreCase(getResources().getResourceEntryName(R.id.PAYDIANT_GENERATED)))
        14 {
        15 continue;
        16 }
        17 key = paymentAccountMetaData.getKey();
        18 if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.STATE)))
        19 {
        20 additionalData.setKey(key);
        21 additionalData.setValue(AppConstants.STATE);
        22 additionalDataList.add(additionalData);
        23 }
        24 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.COUNTRY)))
        25 {
        26 additionalData.setKey(key);
        27 additionalData.setValue(AppConstants.COUNTRY);
        28 additionalDataList.add(additionalData);
        29 }
        30 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.EXPIRY_DATE)))
        31 {
        32 additionalData.setKey(key);
        33 additionalData.setValue("12-" + (Calendar.getInstance().get(Calendar.YEAR) + 1));
        34 additionalDataList.add(additionalData);
        35 }
        36 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.CARD_NUMBER)))
        37 {
        38 additionalData.setKey(key);
        39 additionalData.setValue(AppConstants.VISA_CREDIT_CARD_NO);
        40 additionalDataList.add(additionalData);
        41 }
        42 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.NICK_NAME)))
        43 {
        44 additionalData.setKey(key);
        45 additionalData.setValue(AppConstants.NICK_NAME);
        46 additionalDataList.add(additionalData);
        47 }
        48 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.HOLDER_NAME)))
        49 {
        50 additionalData.setKey(key);
        51 additionalData.setValue(AppConstants.USER_FIRST_NAME + " " + AppConstants.USER_LAST_NAME);
        52 additionalDataList.add(additionalData);
        53 }
        54 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ADDRESS_LINE1)))
        55 {
        56 additionalData.setKey(key);
        57 additionalData.setValue(AppConstants.ADDRESS1);
        58 additionalDataList.add(additionalData);
        59 }
        60 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ADDRESS_LINE2)))
        61 {
        62 additionalData.setKey(key);
        63 additionalData.setValue(AppConstants.ADDRESS2);
        64 additionalDataList.add(additionalData);
        65 }
        66 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ZIP_CODE)))
        67 {
        68 additionalData.setKey(key);
        69 additionalData.setValue(AppConstants.ZIP_CODE);
        70 additionalDataList.add(additionalData);
        71 }
        72 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.EMAIL)))
        73 {
        74 additionalData.setKey(key);
        75 additionalData.setValue(AppConstants.EMAIL);
        76 additionalDataList.add(additionalData);
        77 }
        78 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.SECURITY_CODE)))
        79 {
        80 additionalData.setKey(key);
        81 additionalData.setValue(AppConstants.CVV);
        82 additionalDataList.add(additionalData);
        83 }
        84 else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.CITY)))
        85 {
        86 additionalData.setKey(key);
        87 additionalData.setValue(AppConstants.CITY);
        88 additionalDataList.add(additionalData);
        89 }
        90}

        3. Submit enrollment request

        Based on the requirements of the specific tender being added, configure the corresponding enrollment method and submit the compiled data instance.

        startPaymentAccountEnrollment

        This call is used to initiate a payment tender enrollment process that may take one or more steps to complete. Some external authorizing entities need to evaluate the first set of passed data in order to determine whether more information is required. If so, the call returns an enrollmentState of MORE_INFO and typically includes additional data related to the requirements. Otherwise, the call returns an enrollmentState of END and the enrollment is complete.

        The PayPal tender is one such tender that requires multiple steps, and is therefore used as the code sample for multi-step tender enrollment.

        1. Call the startPaymentAccountEnrollment, passing the data relevant to the PayPal tender.

            1StartPaymentAccountEnrollment startPaymentAccountEnrollment = new
            2StartPaymentAccountEnrollment();
            3startPaymentAccountEnrollment.setEnrollmentType(EnrollmentType.PROVISION);
            4startPaymentAccountEnrollment.setPaymentAccountNetworkTypeUri(paypalTender.getNetworkType().getPaymentAccountNetworkTypeUri());
            5startPaymentAccountEnrollment.setPaymentAccountTypeUri(paypalTender.getAccountType().getPaymentAccountTypeUri());
            6com.paydiant.android.core.domain.transactionflow.AdditionalData additionalData = new
            7com.paydiant.android.core.domain.transactionflow.AdditionalData();
            8additionalData.setKey("NICK_NAME");
            9additionalData.setValue("PayPal");
            10List <com.paydiant.android.core.domain.transactionflow.AdditionalData> additionalDataList = new ArrayList <> ();
            11additionalDataList.add(additionalData);
            12startPaymentAccountEnrollment.setAdditionalData(additionalDataList);
            13paymentAccountManagementService.startPaymentAccountEnrollment(startPaymentAccountEnrollment);
          1. If the success callback indicates an enrollmentState of MORE_INFO, configure the app to provide the additionally requested info (in this case, the PayPal Billing Agreement).

              1String authToken = paymentAccountEnrollment.getAdditionalEnrollmentData().get(0).getValue();
              2
              3if (authToken != null) {
              4 try {
              5 // Authenticate BraintreeFragment with user token
              6 BraintreeFragment mBraintreeFragment = BraintreeFragment.newInstance(SelectAccountTypeActivity.this, authToken);
              7 if (mBraintreeFragment != null) {
              8 // set listeners
              9 mBraintreeFragment.addListener(SelectAccountTypeActivity.this);
              10 mBraintreeFragment.addListener(SelectAccountTypeActivity.this);
              11 mBraintreeFragment.addListener(SelectAccountTypeActivity.this);
              12 // Request billing agreement
              13 PayPalRequest payPalRequest = new PayPalRequest();
              14 PayPal.requestBillingAgreement(mBraintreeFragment, payPalRequest);
              15 }
              16} catch (InvalidArgumentException e) {
              17 e.printStackTrace();
              18}
              19List<AdditionalEnrollmentData> additionalEnrollmentDataList = new ArrayList<>();
              20// set nonce as AdditionalEnrollmentData
              21AdditionalEnrollmentData paymentNonceEnrollmentData = new AdditionalEnrollmentData();
              22paymentNonceEnrollmentData.setKey("PAYMENT_METHOD_NONCE"));
              23paymentNonceEnrollmentData.setValue(nonce);
              24additionalEnrollmentDataList.add(paymentNonceEnrollmentData);
              25// Create ContinuePaymentAccountEnrollment instance with correlation ids and additional data
              26ContinuePaymentAccountEnrollment continuePaymentAccountEnrollment = new
              27ContinuePaymentAccountEnrollment();
              28continuePaymentAccountEnrollment.setAdditionalEnrollmentData(additionalEnrollmentDataList);
              29continuePaymentAccountEnrollment.setPaydiantCorrelationId(PayPalEnrollmentCorrelationID);
              30continuePaymentAccountEnrollment.setExternalCorrelationId(ExternalCorrelationId);
              31// Trigger continuePaymentAccountEnrollment
              32paymentAccountManagementService.continuePaymentAccountEnrollment(continuePaymentAccountEnrollment);
            1. Configure the secondary response in the same way as the starting response; if the enrollmentState is END, complete the enrollment.

                1onContinuePaymentAccountEnrollmentSuccess(PaymentAccountEnrollment paymentAccountEnrollment)

              addPaymentAccount

              Use this method to register a payment account as a valid tender in the wallet where, once verified, WLW becomes the system of record for the account, storing the PAN data within the secure platform Payment Account Manager database and managing payment authorization. This process is typically used for open-loop style tenders, such as credit and debit cards.

                1paymentAccountManagementService.addPaymentAccount(paymentAccountData);
                2@Override
                3public void onAddPaymentAccountSuccess(DetailedPaymentAccount detailedPaymentAccount)
                4{
                5 super.onAddPaymentAccountSuccess(detailedPaymentAccount););
                6}

                provisionPaymentAccount

                Use this method to create a new payment account in the wallet user's name and add it as a valid tender in the wallet. This method is most often used to issue a new loyalty card to the wallet user, which can be used as tender once enough rewards points have been earned.

                Refer to the WLW Android SDK Guide for implementation documentation for the provisionAccount method.

                NEXT STEP 4: Configure a payment