peteross
peteross

Reputation: 236

Migrating from Android Pay to Google Payment API

TL;DR: Can I process a transaction using a PaymentDataRequest built using WalletConstants.TOTAL_PRICE_STATUS_ESTIMATED as the TransactionInfo's "TotalPriceStatus"?

Full Issue Description

I have an app that currently has AndroidPay integrated as a payment method, and I want to migrate this to use the new Google Payment API.

Users can purchase things that are shipped to them, and since shipping costs can change based on location, I can't calculate the final cost of the order until I get the user's shipping address from the MaskedWallet (AndroidPay) or PaymentData (Google Payment). When using AndroidPay, the user is shown a bottom-sheet dialog when I request the MaskedWallet, then I can calculate the order total, and then request the FullWallet with an exact amount to charge the user.

If I follow the same basic pattern with Google Payment, I request a PaymentData like so:

PaymentDataRequest.Builder request = PaymentDataRequest.newBuilder()
        .setTransactionInfo(TransactionInfo.newBuilder()
            .setTotalPriceStatus(WalletConstants.TOTAL_PRICE_STATUS_ESTIMATED)
            .setTotalPrice("123")
            .setCurrencyCode("USD")
            .build())
        .addAllowedPaymentMethod(WalletConstants.PAYMENT_METHOD_CARD)
        .addAllowedPaymentMethod(WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD)
        .setPhoneNumberRequired(true)
        .setEmailRequired(true)
        .setShippingAddressRequired(true)
        .setPaymentMethodTokenizationParameters(getTokenizationParameters())
        .setCardRequirements(getCardRequirements());

where getTokenizationParameters() and getCardRequirements() are locally defined helper methods. After I make this request, a dialog is shown to the user that confirms their address and credit card (just like requesting the MaskedWallet for AndroidPay), then I show a confirmation UI of my own that shows a breakdown in the price. When the user clicks to confirm the purchase and place the order, I'm creating another PaymentDataRequest, but this time using WalletConstants.TOTAL_PRICE_STATUS_FINAL in the TransactionInfo because I know know exactly how much the customer will be charged, like so:

PaymentDataRequest.Builder request = PaymentDataRequest.newBuilder()
        .setTransactionInfo(TransactionInfo.newBuilder()
            .setTotalPriceStatus(WalletConstants.TOTAL_PRICE_STATUS_FINAL)
            .setTotalPrice("133.5")
            .setCurrencyCode("USD")
            .build())
        .addAllowedPaymentMethod(WalletConstants.PAYMENT_METHOD_CARD)
        .addAllowedPaymentMethod(WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD)
        .setPhoneNumberRequired(true)
        .setEmailRequired(true)
        .setUiRequired(false)
        .setShippingAddressRequired(true)
        .setPaymentMethodTokenizationParameters(getTokenizationParameters())
        .setCardRequirements(getCardRequirements());

I'm doing this second request in part because this mirrors the process used in Android Pay with a FullWallet, but the UX is terrible because of this second dialog.

Do I have to create a PaymentDataRequest using WalletConstants.TOTAL_PRICE_STATUS_FINAL to get a PaymentData that I can use to charge the user, or can I use WalletConstants.TOTAL_PRICE_STATUS_ESTIMATED and use that PaymentData to charge the user, even though the exact dollar amount the user is charged may be different from the amount I created the request with?

Upvotes: 0

Views: 515

Answers (1)

fstanis
fstanis

Reputation: 5534

As you correctly pointed out, unlike the old Android Pay API which had loadMaskedWallet and loadFullWallet that were supposed to be called in different parts of the flow, the Google Pay API only has a single loadPaymentData call which can be, in this sense, considered a combination of the two (i.e. calling loadFullWallet immediately after loadMaskedWallet).

This means that there's no need to make the second PaymentDataRequest - since your final price is not known when you request the payment credentials from Google, TOTAL_PRICE_STATUS_ESTIMATED is the correct approach. Once you've received the payment credentials successfully, there's no need to make any further calls to the API.

Keep in mind that Google does not process transactions, so you would still need to provide your payment processor / gateway with the correct final amount.

Upvotes: 1

Related Questions