Performing a Checkout

The checkout process requires you to create a Checkout object with all the necessary components:

  • Line items
  • Billing address
  • Shipping address
  • Shipping charges
  • Discount, if applicable
  • Payment details

Building a Cart

Cart consists of one or more line items from product variants retrieved in the product list.

// Create a cart
Cart cart = new Cart();

// Add a product variant to the cart
// In this case, we're adding the first product and its first variant
Product product = products.get(0);
ProductVariant variant = product.getVariants().get(0);
cart.addVariant(variant);

Creating a Checkout

When the customer is ready to make a purchase, a Checkout must be created from the Cart object.

Checkout checkout = new Checkout(cart);

// Sync the checkout with Shopify
buyClient.createCheckout(checkout, new Callback<Checkout>() {
    @Override
    public void success(Checkout checkout) {
    // Save the returned checkout here
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Completing the Checkout

At this point you are ready to collect the payment information from the customer. If using a credit card payment, prompt the customer to enter the credit card information. If using Android Pay, keep a reference to the FullWallet.

Although the SDK supports payment by credit card, we highly recommend that you use Android Pay as the only source of payment within your app. Familiarize yourself with the Mobile PCI Standards before including a full credit card checkout flow in your app.

The are three ways to complete a checkout:

Web Checkout

Web checkout is the simplest way to complete a checkout. You only need to specify the line items on the checkout, and then start the web checkout. The browser will handle the rest.

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(checkout.getWebUrl()));
intent.setPackage("com.android.chrome");
startActivity(intent);

Set the Return button label and URL

Before you open the web checkout, you have the option of setting a custom URL and label for the Return button. This button appears at the bottom of the order status page after the user completes the checkout. If you do not set a custom URL and label, the button label will default to "Return to store" and it will take the user to your store's home page in the browser.

If you would prefer to send the user back to your store's Android app, do the following:

checkout.setWebReturnToUrl("myscheme://home"); // the custom URL for your app
checkout.setWebReturnToLabel("Return to App") // this label will appear on the button

For additional information on creating and handling app-specific URLs in Android, see Allowing Other Apps to Start Your Activity.

Android Pay

If you want to support Android Pay, familiarize yourself with the information available at Android Pay. The Android Pay Tutorial is a great resource for getting started with Android Pay.

Before you can use Android Pay in a production app, you will need to follow the instructions for getting production access

Ensure that Android Pay is enabled on the Mobile App Sales Channel page of your Shopify admin, and that your store has Shopify Payments enabled as your credit card gateway.

Tip

Android Pay does not support use of a test credit card. You are required to use a real credit card.

AndroidPayHelper.java contains utility functions for converting Shopify data to Wallet data for use with Android Pay. These functions will handle correctly setting up MaskedWalletRequest and FullWalletRequest objects for you from Checkout objects.

This guide will focus on how to use AndroidPayHelper to get user information, update a Checkout, and complete payment.

Getting User Information

Create a MaskedWalletRequest using a Checkout

// Create the Masked Wallet request
MaskedWalletRequest maskedWalletRequest = 
    AndroidPayHelper.createMaskedWalletRequest( 
        shop.getName(), 
        checkout, 
        ANDROID_PAY_PUBLIC_KEY, 
        true, 
        shop.getShipsToCountries());

When you make the MaskedWalletRequest to Android Pay, a MaskedWallet will be returned in OnActivityResult. The MaskedWallet contains user information such as shipping and billing addresses that can be used to update a Checkout.

Specifying Billing and Shipping Addresses

checkout.setShippingAddress(AndroidPayHelper.createShopifyAddress(maskedWallet.getBuyerShippingAddress()));
checkout.setBillingAddress(AndroidPayHelper.createShopifyAddress(maskedWallet.getBuyerBillingAddress()));
checkout.setEmail(maskedWallet.getEmail());

Important note: After adding additional information to the Checkout, you need to sync the checkout with the Shopify server:

buyClient.updateCheckout(checkout, new Callback<Checkout>() {
    @Override
    public void success(Checkout checkout) {
    // Save the updated checkout here
    }

    @Override
    public void failure(BuyClientError error) {        
    // Handle errors here
    }
});

Once the checkout has been updated with the shipping address, the shipping rates can be retrieved.

buyClient.getShippingRates(checkout.getToken(), new Callback<List<ShippingRate>>() {

    @Override
    public void success(List<ShippingRate> shippingRates) {
    // Save the shipping rates
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Add the selected shipping method to the Checkout object. The App should let the user select from the possible shipping rates. In this case, we will just pick the first one. After setting the shipping rate, you need to update the checkout again.

ShippingRate selectedShippingRate = shippingRates.get(0);
checkout.setShippingRate(selectedShippingRate);

// Update the checkout with the shipping rate
buyClient.updateCheckout(checkout, new Callback<Checkout>() {
    @Override
    public void success(Checkout checkout) {
    // Save the updated checkout here
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Completing the Checkout

Create a FullWalletRequest using a MaskedWallet and a Checkout.

FullWalletRequest fullWalletRequest = AndroidPayHelper.createFullWalletRequest(checkout, maskedWallet);

Complete the Checkout using the FullWallet. This operation involves a number of steps, and implicitly must wait on remote payment processors, so it will take longer than most simple requests.

PaymentToken paymentToken = AndroidPayHelper.getAndroidPaymentToken(fullWallet, ANDROID_PAY_PUBLIC_KEY);
buyClient.completeCheckout(paymentToken, checkoutToken, new Callback<Checkout>( {

    @Override
    public void success(Checkout checkout) {
        // Show confirmation of Payment
    }

    @Override
    public void failure(BuyClientError error) {
        // Handle errors here
    }
});

Using Native Checkout

If you want to provide a custom checkout and payment experience, you can do so using the native checkout interface.

Specifying Billing and Shipping Addresses

checkout.setEmail(String email);
checkout.setBillingAddress(com.shopify.buy.model.Address billingAddress);
checkout.setShippingAddress(com.shopify.buy.model.Address shippingAddress);
checkout.setShippingRate(com.shopify.buy.model.ShippingRate shippingRate);
checkout.setDiscountCode(String code);
checkout.addGiftCard(com.shopify.buy.model.GiftCard giftCard)

Important note: After adding additional information to the Checkout, you need to sync the checkout with the Shopify server:

buyClient.updateCheckout(checkout, new Callback<Checkout>() {
    @Override
    public void success(Checkout checkout) {
    // Save the updated checkout here
    }

    @Override
    public void failure(BuyClientError error) {        
    // Handle errors here
    }
});

Once the checkout has been updated with the shipping address, the shipping rates can be retrieved.

buyClient.getShippingRates(checkout.getToken(), new Callback<List<ShippingRate>>() {

    @Override
    public void success(List<ShippingRate> shippingRates) {
    // Save the shipping rates
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Add the selected shipping method to the Checkout object. The App should let the user select from the possible shipping rates. In this case, we will just pick the first one. After setting the shipping rate, you need to update the checkout again.

ShippingRate selectedShippingRate = shippingRates.get(0);
checkout.setShippingRate(selectedShippingRate);

// Update the checkout with the shipping rate
buyClient.updateCheckout(checkout, new Callback<Checkout>() {
    @Override
    public void success(Checkout checkout) {
    // Save the updated checkout here
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Charging a credit card

//Prompt the user for their credit card information, and create a `CreditCard` object.
CreditCard card = new CreditCard();
card.setFirstName("Dinosaur");
card.setLastName("Banana");
card.setMonth("2");
card.setYear("20");
card.setVerificationValue("123");
card.setNumber("4242424242424242");

// Associate the credit card with the checkout
buyClient.storeCreditCard(card, checkout, new Callback<PaymentToken>() {
    @Override
    public void success(PaymentToken paymentToken) {
    // Save payment token that is required for checkout completion 
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Once the credit card has been stored on the checkout on Shopify, the checkout can be completed. This operation involves a number of steps, and implicitly must wait on remote payment processors, so it will take longer than most simple requests.

buyClient.completeCheckout(paymentToken, checkout.getToken(), new Callback<Checkout>() {
    @Override
    public void success(Checkout returnedCheckout) {
        // Save the completed checkout here
    }

    @Override
    public void failure(BuyClientError error) {
    // Handle errors here
    }
});

Error Handling

In the case of an error a BuyClientError will be returned. You can check the body of the error for more detailed information about the reason for the failure.

There are several categories of BuyClientError error:

  • BuyClientError.ERROR_TYPE_API - for any errors returned by server side (e.g. HTTP_NOT_FOUND(404), HTTP_FORBIDDEN(403) etc.)
  • BuyClientError.ERROR_TYPE_NETWORK - for any errors related to the network connectivity
  • BuyClientError.ERROR_TYPE_UNKNOWN - for any others

The body of the BuyClientError can be retrieved by:

  • BuyClientError.getRetrofitResponse() - will return the raw retrofit response
  • BuyClientError.getRetrofitErrorBody() - will return the raw JSON string of the retrofit error body
  • BuyClientError.getErrors(String... path) - will return a map of error code/message pairs found for the specified path (e.g. error.getErrors("customer", "password") will return all error messages related to customer password)