availability

Samsung Pay is currently available to US merchants.

Get the SDKs

Braintree

See the client SDK setup guide for Android v3. Samsung Pay requires braintree and samsung-pay modules.

Groovy
dependencies {
    implementation 'com.braintreepayments.api:braintree:3.3.0'
    implementation 'com.braintreepayments.api:samsung-pay:2.0.0'
}

Samsung Pay is only available on Samsung devices with Android 6.0 (API level 23) and above.

Samsung Pay

Add the samsungpay JAR to the libs folder of your project.

Groovy
repositories {
    // ...
    flatDir {
        dirs "${rootDir}/libs"
    }
}

dependencies {
    implementation(group: 'com.samsung.android', name: 'samsungpay', version: '1.9.0', ext: 'jar')
}

Integration

Prepare Samsung Pay button assets

note

Click here to download Samsung's brand guidelines, and be sure to follow them when configuring the Samsung Pay button.

Add a Samsung Pay button to your app to let users select Samsung Pay as their payment method. Depending on your app's theme you can select the appropriate button assets. Click here to download Samsung's button assets.

Add the Samsung Pay assets you wish to use to your drawable resources.

Initialization

First use a tokenization key or get a client token from your server and initialize BraintreeFragment.

Then register a listener to receive a payment method nonce once the Samsung Pay flow finishes.

Before showing the Samsung Pay button, use the SamsungPay#isReadyToPay method to check whether the user's current device is compatible.

Java
SamsungPay.isReadyToPay(mBraintreeFragment, new BraintreeResponseListener<SamsungPayAvailability>() {
    @Override
    public void onResponse(SamsungPayAvailability availability) {
        switch(availability.getStatus()) {
            case SPAY_READY:
                // Samsung Pay is ready!
                // Show the Samsung Pay button.
                mSamsungPayButton.setEnabled(true);
                break;

            case SPAY_NOT_READY:
                // Samsung Pay is not ready yet.
                // Check the reason to see if it can be resolved.
                Integer reason = availability.getReason();
                if (reason == ERROR_SPAY_APP_NEED_TO_UPDATE) {
                    // Samsung Pay's app needs an update.
                    // Let Samsung Pay navigate to the update page.
                    SamsungPay.goToUpdatePage(mBraintreeFragment);
                } else if (reason == ERROR_SPAY_SETUP_NOT_COMPLETED) {
                    // Samsung Pay's activation setup is not complete.
                    // Let Samsung Pay's app continue to activate.
                    SamsungPay.activateSamsungPay(mBraintreeFragment);
                } else if (reason == SamsungPay.SPAY_NO_SUPPORTED_CARDS_IN_WALLET) {
                    // Samsung Pay has no supported cards currently.
                }
                break;

            case SPAY_NOT_SUPPORTED:
                // Samsung Pay is not currently supported on this device.
                // Disable and hide the Samsung Pay button.
                mSamsungPay.setEnabled(false);
                break;
        }
    }
});

Create a PaymentManager

When the user updates their payment sheet with payment information you will receive listener calls with the updates. Use these notifications to verify addresses, price, etc.

Samsung Pay requires you to verify the changes and update the PaymentManager on these changes.

Create a PaymentManager instance that knows how to interact with Braintree using SamsungPay#createPaymentManager for later use.

Java
SamsungPay.createPaymentManager(mBraintreeFragment, new BraintreeResponseListener<PaymentManager>() {
    @Override
    public void onResponse(PaymentManager paymentManager) {
        mPaymentManager = paymentManager;
    }
}

Build a payment sheet

Samsung Pay lets you tailor the payment sheet for display to the user, and Braintree provides a pre-populated CustomSheetPaymentInfo.Builder for the integration.

Use SamsungPay#createPaymentInfo to access the CustomSheetPaymentInfo.Builder and add properties to it.

The following example demonstrates how to build a CustomSheet based on the controls you configure:

Java
SamsungPay.createPaymentInfo(mBraintreeFragment, new BraintreeResponseListener<CustomSheetPaymentInfo.Builder>() {
    @Override
    public void onResponse(CustomSheetPaymentInfo.Builder builder) {
        CustomSheetPaymentInfo paymentInfo = builder
            .setCustomSheet(getCustomSheet());
            .build();
    }
});

The next snippet shows you how to create a payment sheet that returns the billing and shipping addresses:

Java
private CustomSheet getCustomSheet() {
    CustomSheet sheet = new CustomSheet();

    // This AddressControl has Samsung Pay ask for the user's billing address.
    final AddressControl billingAddressControl = new AddressControl("billingAddressId", SheetItemType.BILLING_ADDRESS);
    billingAddressControl.setAddressTitle("Billing Address");
    billingAddressControl.setSheetUpdatedListener(new SheetUpdatedListener() {
        @Override
        public void onResult(String controlId, final CustomSheet customSheet) {
            // Determine if the billing address requires a price adjustment.

            // A call to PaymentManager#updateSheet is required whenever the payment sheet is updated.
            mPaymentManager.updateSheet(customSheet);
        }
    });
    sheet.addControl(billingAddressControl);

    // To have Samsung Pay request a shipping address from the user, add the following code:
    final AddressControl shippingAddressControl = new AddressControl("shippingAddressId", SheetItemType.SHIPPING_ADDRESS);
    shippingAddressControl.setAddressTitle("Shipping Address");
    shippingAddressControl.setSheetUpdatedListener(new SheetUpdatedListener() {
        @Override
        public void onResult(String controlId, final CustomSheet customSheet) {
            AmountBoxControl amountBoxControl = (AmountBoxControl) customSheet.getSheetControl("amountID");
            // Determine if the shipping address requires a price adjustment.

            // A call to PaymentManager#updateSheet is required whenever the payment sheet is updated.
            mPaymentManager.updateSheet(customSheet);
        }
    });
    sheet.addControl(shippingAddressControl);

    // Use AmountBoxControl to present the price to the user.
    AmountBoxControl amountBoxControl = new AmountBoxControl("amountID", "USD");
    amountBoxControl.setAmountTotal(0.01, AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
    sheet.addControl(amountBoxControl);

    return sheet;
}

Launch Samsung Pay

Once the payment sheet is built, start Samsung Pay with SamsungPay#requestPayment.

There are two methods to listen to when starting Samsung Pay:

  • onSuccess is called when the payment request is successful. The payment method nonce will continue to be sent back in the onPaymentMethodNonceCreated callback. This method is for accessing other information given by Samsung Pay such as addresses set in the CustomSheet.

  • onCardInfoUpdated is called when the user selects a payment method. This method can be used to update pricing on the sheet.

Java
// ...
CustomSheetPaymentInfo paymentInfo = builder
  .setCustomSheet(getCustomSheet());
  .build();

SamsungPay.requestPayment(mBraintreeFragment, mPaymentManager, paymentInfo, new SamsungPayCustomTransactionUpdateListener() {
  @Override
  public void onSuccess(CustomSheetPaymentInfo response, Bundle extraPaymentData) {
    // This callback can be used to access other information from the SamsungPay request such
    // as addresses:

    CustomSheet customSheet = response.getCustomSheet();
    AddressControl billingAddressControl = (AddressControl) customSheet.getSheetControl("billingAddressId");
    CustomSheetPaymentInfo.Address billingAddress = billingAddressControl.getAddress();
    CustomSheetPaymentInfo.Address shippingAddress = response.getPaymentShippingAddress();

    // Record the billing and shipping addresses.
    // As an example, here is how to access the customers billing postal code
    // billingAddress.getPostalCode();
  }

  @Override
  public void onCardInfoUpdated(@NonNull CardInfo cardInfo, @NonNull CustomSheet customSheet) {
    AmountBoxControl amountBoxControl = (AmountBoxControl) customSheet.getSheetControl("amountID");

    // Determine if the payment method update requires a price adjustment.

    // Remember, you must call PaymentManager#updateSheet whenever the payment sheet is updated.
    mPaymentManager.updateSheet(customSheet);
  }
});

If completed successfully, a SamsungPayNonce will be passed to your PaymentMethodNonceCreatedListener.

Java
@Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
  if (paymentMethodNonce instanceof SamsungPayNonce) {
    // PaymentMethodNonce returned from Samsung Pay.
    // Send this to your server.
  }
}

If canceled, your BraintreeCancelListener will be called.

Java
@Override
public void onCancel(int requestCode) {
  if (requestCode == BraintreeRequestCodes.SAMSUNG_PAY) {
    // The user has canceled the Samsung Pay flow.
  }
}

Handling errors

If an error occurs during the Samsung Pay flow, your BraintreeErrorListener will be called with a SamsungPayException:

Java
@Override
public void onError(Exception error) {
  if (error instanceof SamsungPayException) {
    SamsungPayException samsungPayException = (SamsungPayException) error;

    switch (samsungPayException.getCode()) {
      case SpaySdk.ERROR_NO_NETWORK:
        // Handle errors like these accordingly.
        break;

      // case ...
    }
  }
}

Full example

A complete example of an integration between Braintree and Samsung Pay shows you how to get started and provides a handy reference for your integration project.

Java
public class SamsungPayExampleActivity extends AppCompatActivity implements SamsungPayCustomTransactionUpdateListener,
        PaymentMethodNonceCreatedListener,
        BraintreeErrorListener,
        BraintreeCancelListener {
    private BraintreeFragment mBraintreeFragment;
    private PaymentManager mPaymentManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            // 1. Create a BraintreeFragment.
            mBraintreeFragment = BraintreeFragment.newInstance(this, "Your Tokenization Key or Client Token");
        } catch (InvalidArgumentException e) {
            // There was an issue with the authorization used when creating Braintree.
            e.printStackTrace();
        }

        // 2. Confirm Samsung Pay is ready to Pay.
        SamsungPay.isReadyToPay(mBraintreeFragment, mSamsungPayAvailabilityListener);
    }

    private BraintreeResponseListener<SamsungPayAvailability> mSamsungPayAvailabilityListener =
            new BraintreeResponseListener<SamsungPayAvailability>() {
                @Override
                public void onResponse(SamsungPayAvailability samsungPayAvailability) {
                    switch (samsungPayAvailability.getStatus()) {
                        case SPAY_READY:
                            // 3. Create a payment manager.
                            SamsungPay.createPaymentManager(mBraintreeFragment, mPaymentManagerListener);
                            break;
                        case SPAY_NOT_READY:
                            Integer reason = samsungPayAvailability.getReason();
                            if (reason == ERROR_SPAY_APP_NEED_TO_UPDATE) {
                                SamsungPay.goToUpdatePage(mBraintreeFragment);
                            } else if (reason == ERROR_SPAY_SETUP_NOT_COMPLETED) {
                                SamsungPay.activateSamsungPay(mBraintreeFragment);
                            } else if (reason == SamsungPay.SPAY_NO_SUPPORTED_CARDS_IN_WALLET) {
                            }
                            break;
                        case SPAY_NOT_SUPPORTED:
                            // Samsung Pay not supported on this device.
                            break;
                    }
                }
            };

    private BraintreeResponseListener<PaymentManager> mPaymentManagerListener =
            new BraintreeResponseListener<PaymentManager>() {
                @Override
                public void onResponse(PaymentManager paymentManager) {
                    // 4. Save the PaymentManager instance for later.
                    mPaymentManager = paymentManager;

                    // 5. Create a Braintree pre-populated CustomSheetPaymentInfo.Builder.
                    SamsungPay.createPaymentInfo(mBraintreeFragment, mPaymentInfoListener);
                }
            };

    private BraintreeResponseListener<CustomSheetPaymentInfo.Builder> mPaymentInfoListener =
            new BraintreeResponseListener<Builder>() {
                @Override
                public void onResponse(Builder builder) {
                    CustomSheetPaymentInfo paymentInfo = builder
                            // 6. Let the builder know we need billing and shipping addresses.
                            .setAddressInPaymentSheet(CustomSheetPaymentInfo.AddressInPaymentSheet.NEED_BILLING_AND_SHIPPING)
                            // 7. Create a payment sheet.
                            .setCustomSheet(getCustomSheet())
                            .build();

                    // 8. Request a payment from Samsung Pay.
                    SamsungPay.requestPayment(mBraintreeFragment, paymentInfo, SamsungPayExampleActivity.this);
                }
            };

    private CustomSheet getCustomSheet() {
        CustomSheet sheet = new CustomSheet();

        final AddressControl billingAddressControl = new AddressControl("billingAddressId", SheetItemType.BILLING_ADDRESS);
        billingAddressControl.setAddressTitle("Billing Address");
        billingAddressControl.setSheetUpdatedListener(new SheetUpdatedListener() {
            @Override
            public void onResult(String controlId, final CustomSheet customSheet) {
                // This listener will be called when the customer updates their billing address.

                // Determine if the billing address is acceptable.

                // A call to PaymentManager#updateSheet is required whenever the payment sheet is updated.
                mPaymentManager.updateSheet(customSheet);
            }
        });
        sheet.addControl(billingAddressControl);

        final AddressControl shippingAddressControl = new AddressControl("shippingAddressId", SheetItemType.SHIPPING_ADDRESS);
        shippingAddressControl.setAddressTitle("Shipping Address");
        shippingAddressControl.setSheetUpdatedListener(new SheetUpdatedListener() {
            @Override
            public void onResult(String controlId, final CustomSheet customSheet) {
                // This listener will be called when the customer updates their shipping address.

                // Determine if the shipping address is acceptable.

                // A call to PaymentManager#updateSheet is required whenever the payment sheet is updated.
                mPaymentManager.updateSheet(customSheet);
            }
        });
        sheet.addControl(shippingAddressControl);

        AmountBoxControl amountBoxControl = new AmountBoxControl("amountID", "USD");
        amountBoxControl.setAmountTotal(0.01, AmountConstants.FORMAT_TOTAL_PRICE_ONLY);
        sheet.addControl(amountBoxControl);

        return sheet;
    }

    @Override
    public void onCardInfoUpdated(@NotNull CardInfo cardInfo, @NotNull CustomSheet customSheet) {
        // 9. When the card is updated, this listener is called.
        AmountBoxControl amountBoxControl = (AmountBoxControl) customSheet.getSheetControl("amountID");

        // Determine if any price adjustments are required and then update the PaymentManager.
        mPaymentManager.updateSheet(customSheet);
    }

    @Override
    public void onSuccess(@NotNull CustomSheetPaymentInfo response, @NotNull Bundle extraPaymentData) {
        // 10. Access the billing and shipping addresses.
        CustomSheet customSheet = response.getCustomSheet();
        AddressControl billingAddressControl = (AddressControl) customSheet.getSheetControl("billingAddressId");

        CustomSheetPaymentInfo.Address billingAddress = billingAddressControl.getAddress();
        CustomSheetPaymentInfo.Address shippingAddress = response.getPaymentShippingAddress();
    }

    @Override
    public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
        // 11. A Samsung Pay payment method nonce was created!
        // Send this payment method nonce back to your server.
    }

    @Override
    public void onCancel(int requestCode) {
        // Samsung Pay was canceled by the user.

        // Revert the UI back to payment method selection to try a different payment method.
    }

    @Override
    public void onError(Exception error) {
        // There was an error using Samsung Pay.

        // Revert the UI back to payment method selection to try a different payment method.
    }
}

Next Page: Server-side →