STEP 3 Enroll payment methods

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 Paydiant'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. Paydiant facilitates payment authorization through a secure, tokenized transmission directly from Paydiant's platform to the processor's server. Paydiant 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, Paydiant'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 Paydiant 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.
private final ServiceConnection paymentAccountManagementServiceConnection = new ServiceConnection()
{
    @Override
    @SuppressWarnings("unchecked")
    public void onServiceConnected(final ComponentName arg0, final IBinder binder) {
        paymentAccountManagementService = ((LocalBinder PaymentAccountManagementService ) binder).getService();
        paymentAccountManagementService.setPaymentAccountRetrieveListener(paymentListenerAdapter);
        paymentAccountManagementService.retrieveAllTenderTypes();
        progressBar.setVisibility(View.VISIBLE);
    }
    @Override
    public void onServiceDisconnected(final ComponentName arg0)
    {
        paymentAccountManagementService = null;
        paymentAccountManagementService.removeListener();
    }
};
Intent paymentAccountMgmtIntent = new Intent(this, PaymentAccountManagementService.class);
bindService(paymentAccountMgmtIntent, paymentAccountManagementServiceConnection, BIND_AUTO_CREATE);
}

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.

Note: Within each standard enrollment type, the process for any supported tender often varies slightly depending on the specific configuration of that tender and what the network processor requires. For example, PayPal requires a client token to call it's vZero SDK to facilitate user login, while some debit networks require double deposit verification. Therefore, most apps configure each tender enrollment as a separate segment that can be called when the corresponding dependencies are met.

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.

PaymentAccountData paymentAccountData = new PaymentAccountData();
paymentAccountData.setAdditionalData(getAdditionalDataList());
if (selectedTender != null)
{
    paymentAccountData.setPaymentAccountNetworkTypeUri(selectedTender.getNetworkType().getPaymentAccountNetworkTypeUri());
    paymentAccountData.setPaymentAccountTypeUri(selectedTender.getAccountType().getPaymentAccountTypeUri());
}

Compile the Relevant Data

List PaymentAccountMetaData currentPaymentAccountMetaData = selectedTender.getMetaData();
for (PaymentAccountMetaData paymentAccountMetaData: currentPaymentAccountMetaData)
{
    AdditionalData additionalData = new AdditionalData();
    currentViewText = null;
    if (paymentAccountMetaData.getDataGroup().equalsIgnoreCase(getResources().getResourceEntryName(R.id.ISSUER_PROVIDED)))
    {
        additionalData.setKey(paymentAccountMetaData.getKey());
        additionalData.setValue(paymentAccountMetaData.getDefaultValue());
        additionalDataList.add(additionalData);
        continue;
    }
    if (paymentAccountMetaData.getDataGroup().equalsIgnoreCase(getResources().getResourceEntryName(R.id.PAYDIANT_GENERATED)))
    {
        continue;
    }
    key = paymentAccountMetaData.getKey();
    if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.STATE)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.STATE);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.COUNTRY)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.COUNTRY);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.EXPIRY_DATE)))
    {
        additionalData.setKey(key);
        additionalData.setValue("12-" + (Calendar.getInstance().get(Calendar.YEAR) + 1));
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.CARD_NUMBER)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.VISA_CREDIT_CARD_NO);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.NICK_NAME)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.NICK_NAME);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.HOLDER_NAME)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.USER_FIRST_NAME + " " + AppConstants.USER_LAST_NAME);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ADDRESS_LINE1)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.ADDRESS1);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ADDRESS_LINE2)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.ADDRESS2);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.ZIP_CODE)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.ZIP_CODE);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.EMAIL)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.EMAIL);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.SECURITY_CODE)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.CVV);
        additionalDataList.add(additionalData);
    }
    else if (key.equalsIgnoreCase(getResources().getResourceEntryName(R.id.CITY)))
    {
        additionalData.setKey(key);
        additionalData.setValue(AppConstants.CITY);
        additionalDataList.add(additionalData);
    }
}

Note: Paydiant recommends implementing field-level validation in the app to ensure that the user's input complies with the data specifications for each field, such as whether a value is required and what format is expected, etc. This will ensure that the enrollment call does not fail due to invalid input and also allows the app to provide specific feedback about what is expected. If validation is not implemented and the enrollment call fails, the failure response will not indicate which field(s) contained invalid or missing values, possibly resulting in a poor user experience.

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.

Note: The sample excerpts shown are for demonstration purposes and do not represent the entire body of code associated with PayPal tender enrollment. Refer to the PayPal Integration Solution Guide for more comprehensive information.

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

     StartPaymentAccountEnrollment startPaymentAccountEnrollment = new
     StartPaymentAccountEnrollment();
     startPaymentAccountEnrollment.setEnrollmentType(EnrollmentType.PROVISION);
     startPaymentAccountEnrollment.setPaymentAccountNetworkTypeUri(paypalTender.getNetworkType().getPaymentAccountNetworkTypeUri());
     startPaymentAccountEnrollment.setPaymentAccountTypeUri(paypalTender.getAccountType().getPaymentAccountTypeUri());
     com.paydiant.android.core.domain.transactionflow.AdditionalData additionalData = new
     com.paydiant.android.core.domain.transactionflow.AdditionalData();
     additionalData.setKey("NICK_NAME");
     additionalData.setValue("PayPal");
     List com.paydiant.android.core.domain.transactionflow.AdditionalData additionalDataList = new ArrayList <> ();
     additionalDataList.add(additionalData);
     startPaymentAccountEnrollment.setAdditionalData(additionalDataList);
     paymentAccountManagementService.startPaymentAccountEnrollment(startPaymentAccountEnrollment);
     
  2. 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).

     String authToken = paymentAccountEnrollment.getAdditionalEnrollmentData().get(0).getValue();
    

    if (authToken != null) { try { // Authenticate BraintreeFragment with user token BraintreeFragment mBraintreeFragment = BraintreeFragment.newInstance(SelectAccountTypeActivity.this, authToken); if (mBraintreeFragment != null) { // set listeners mBraintreeFragment.addListener(SelectAccountTypeActivity.this); mBraintreeFragment.addListener(SelectAccountTypeActivity.this); mBraintreeFragment.addListener(SelectAccountTypeActivity.this); // Request billing agreement PayPalRequest payPalRequest = new PayPalRequest(); PayPal.requestBillingAgreement(mBraintreeFragment, payPalRequest); } } catch (InvalidArgumentException e) { e.printStackTrace(); } ListAdditionalEnrollmentData additionalEnrollmentDataList = new ArrayList<>(); // set nonce as AdditionalEnrollmentData AdditionalEnrollmentData paymentNonceEnrollmentData = new AdditionalEnrollmentData(); paymentNonceEnrollmentData.setKey("PAYMENT_METHOD_NONCE")); paymentNonceEnrollmentData.setValue(nonce); additionalEnrollmentDataList.add(paymentNonceEnrollmentData); // Create ContinuePaymentAccountEnrollment instance with correlation ids and additional data ContinuePaymentAccountEnrollment continuePaymentAccountEnrollment = new ContinuePaymentAccountEnrollment(); continuePaymentAccountEnrollment.setAdditionalEnrollmentData(additionalEnrollmentDataList); continuePaymentAccountEnrollment.setPaydiantCorrelationId(PayPalEnrollmentCorrelationID); continuePaymentAccountEnrollment.setExternalCorrelationId(ExternalCorrelationId); // Trigger continuePaymentAccountEnrollment paymentAccountManagementService.continuePaymentAccountEnrollment(continuePaymentAccountEnrollment);

  3. Configure the secondary response in the same way as the starting response; if the enrollmentState is END, complete the enrollment.

     onContinuePaymentAccountEnrollmentSuccess(PaymentAccountEnrollment paymentAccountEnrollment)
     

addPaymentAccount

Use this method to register a payment account as a valid tender in the wallet where, once verified, Paydiant 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.

paymentAccountManagementService.addPaymentAccount(paymentAccountData);
@Override
public void onAddPaymentAccountSuccess(DetailedPaymentAccount detailedPaymentAccount)
{
    super.onAddPaymentAccountSuccess(detailedPaymentAccount););
}

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 Paydiant Android SDK Guide for implementation documentation for the provisionAccount method.

NEXT STEP 4: Configure a payment

Feedback

Have feedback?

Let us know.