Integrate In-App payment into merchant apps using Samsung Pay SDK


Objective

Learn how to integrate In-App Payment with your merchant apps using Samsung Pay SDK.

Partnership Request

To use the Samsung Pay SDK, you must become an official Samsung partner. Once done, you can fully utilize this Code Lab. You can learn more about the partnership process by visiting Samsung Pay page, here in Samsung Developers.


Overview

The Samsung Pay SDK is an application framework for integrating selected Samsung Pay features with Android-based partner apps on Samsung devices. In-App Payment, which allows customers to pay for products and services with Samsung Pay, is one of the operations supported alongside Push Provisioning and Open Favorite Cards.

Partner apps can leverage the Samsung Pay SDK to perform different operations ― Push Provisioning and Open Favorite Cards for issuers; In-App Payment for merchants. Key components include:

  • Partner App: app developed by merchant or issuer for making online or offline payments and provisioning payment cards through Samsung Pay
  • Samsung Pay SDK: SDK integrated into the partner app for direct communication with Samsung Pay
  • Samsung Pay app: pay app with which the Samsung Pay SDK communicates
  • Financial network: comprises the payment gateways, acquirers, card associations, and issuers that participate in transaction processing under agreement with the merchant

Most common use case for In-App Payment:

  1. The merchant app allows the user to make payments with Samsung Pay.
  2. Upon user selection of the Samsung Pay option, the merchant app calls the APIs included in the Samsung Pay SDK to initiate a transaction with the Samsung Pay app.
  3. The Samsung Pay app responds with the tokenized payment information necessary to complete the transaction.
  4. The merchant app forwards this payment information to the designated Payment Gateway (PG), either directly through the merchant's web server or indirectly via the Samsung-PG Interface server for standard transaction processing.

For more detailed information, see the official Samsung Pay SDK programming guide.

Set up your environment

You will need the following:

  • Samsung Wallet or Samsung Pay app (depending on the country)
  • A compatible mobile device with Android Marshmallow 6.0 or Android API level 23 (or later Android OS versions)
  • Samsung Pay SDK
  • Android Studio (latest version recommended)
  • Java SE Development Kit (JDK) 11 or later

Sample Code

Here is a sample code for you to start coding in this Code Lab. Download it and start your learning experience!

In-App Payment Sample Code
(1.90 MB)

Integrate the Samsung Pay SDK with your app

The following steps comprise the general process for integrating the Samsung Pay SDK with your app:

  1. Sign up for the Samsung Pay Developers portal by clicking Sign Up and register your Samsung Account (or create it if you don't already have one), then Sign in.
  2. Follow the on-screen instructions for adding your app and creating a new service to generate the service ID you'll need to use in your project.
  3. Download the Samsung Pay SDK by going to Resources > SDK download.
  4. Add the Samsung Pay SDK jar file (samsungpay.jar) to your Android project using Android Studio or File Explorer.
  5. Develop your partner app with the required API calls and callbacks for Samsung Pay integration.
  6. Upload a release version of your app to the Samsung Pay Developers portal for approval.
  7. Upon Samsung approval, publish your partner app to the Google Play store and Samsung Galaxy Apps.

Start your project

After downloading the sample code containing the project files, in Android Studio click Open to open existing project.

Locate the downloaded Android Project (SampleOnlinePay) from the directory and click OK.

Add the SamsungPaySDK_2.18.00_release.jar file from the SDK's Libs folder to your Android project's libs folder.

Go to Gradle Scripts > build.gradle (Module: SampleOnlinePay.app) and enter the following to the dependencies block:

implementation files('libs/SamsungPaySDK_2.18.00_release.jar')

If the target SDK version is 30 (Android 11 or the R-OS), you must include the following <queries> element in AndroidManifest.xml.

<queries>
  <package android:name="com.samsung.android.spay" />
</queries>

Configure the API level

As of SDK version 1.4, enhanced version control management has been introduced to improve backward compatibility and handle API dependency from country and service type. For example, if a partner integrates the latest SDK—for instance, API level 2.18—but continues to use APIs based on level 1.4, the partner app remains compatible with Samsung Pay apps supporting API level 1.4 without upgrading the Samsung Pay app.

Implement the following in application tag of AndroidManifest.xml:

<meta-data
	android:name="spay_sdk_api_level"
	android:value="2.17" /> // most recent SDK version is recommended to leverage the latest APIs

Add an XML layout and modify the Activity

Next, replace the XML layout in res > layout > activity_main.xml.

This layout shows the sample item information such as image, name, and price.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="350dp"
            android:layout_height="184dp"
            android:layout_marginTop="100dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:src="@drawable/galaxy_s23_ultra_image"/>

        <ImageView
            android:id="@+id/samsung_pay_button"
            android:layout_width="wrap_content"
            android:layout_height="75dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:src="@drawable/pay_rectangular_full_screen_black"
            android:visibility="invisible"/>

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="Galaxy S23 Ultra"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/imageView" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="$1,199.00"
            android:textSize="14sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.517"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Since you added a data binding layout, you need to inflate the XML file differently.

Go to java > com > test > beta > pay > MainActivity.kt, and declare the dataBinding variable in the MainActivity class.

private lateinit var dataBinding: ActivityMainBinding

Replace the standard setContentView declaration with the data binding version inside the onCreate method.

dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

Check Samsung Pay status

In the MainActivity, create the SamsungPay instance. To determine if the device supports Samsung Pay and if the Samsung Pay button can be displayed as the user's payment option, check the Samsung Pay status.

SamsungPay() requires a valid PartnerInfo from the merchant app, which consists of service ID and service type. During onboarding, the Samsung Pay Developers portal assigns the service ID and service type.

In the MainActivity, declare the partnerInfo variable.

private lateinit var partnerInfo: PartnerInfo

Then, set the PartnerInfo in the onCreate method.

val bundle = Bundle()
bundle.putString(SpaySdk.PARTNER_SERVICE_TYPE, SpaySdk.ServiceType.INAPP_PAYMENT.toString())
partnerInfo = PartnerInfo(SERVICE_ID, bundle)

After setting PartnerInfo, call the getSamsungPayStatus method via updateSamsungPayButton function inside the onCreate method.

updateSamsungPayButton()

The getSamsungPayStatus method of the SamsungPay class must be called before using any other feature in the Samsung Pay SDK.

Write the updateSamsungPayButton function as follows:

private fun updateSamsungPayButton() {
    val samsungPay = SamsungPay(this, partnerInfo)

    samsungPay.getSamsungPayStatus(object : StatusListener {
        override fun onSuccess(status: Int, bundle: Bundle) {
            when (status) {
                SpaySdk.SPAY_READY -> {
                    dataBinding.samsungPayButton.visibility = View.VISIBLE

                    // Perform your operation.
                }
                SpaySdk.SPAY_NOT_READY -> {
                    // Samsung Pay is supported but not fully ready.

                    // If EXTRA_ERROR_REASON is ERROR_SPAY_APP_NEED_TO_UPDATE,
                    // Call goToUpdatePage().

                    // If EXTRA_ERROR_REASON is ERROR_SPAY_SETUP_NOT_COMPLETED,
                    // Call activateSamsungPay().

                    dataBinding.samsungPayButton.visibility = View.INVISIBLE
                }
                SpaySdk.SPAY_NOT_ALLOWED_TEMPORALLY -> {
                    // If EXTRA_ERROR_REASON is ERROR_SPAY_CONNECTED_WITH_EXTERNAL_DISPLAY,
                    // guide user to disconnect it.

                    dataBinding.samsungPayButton.visibility = View.INVISIBLE
                }
                SpaySdk.SPAY_NOT_SUPPORTED -> {
                    dataBinding.samsungPayButton.visibility = View.INVISIBLE
                }

                else -> dataBinding.samsungPayButton.visibility = View.INVISIBLE
            }
        }

        override fun onFail(errorCode: Int, bundle: Bundle) {
            dataBinding.samsungPayButton.visibility = View.INVISIBLE
            Toast.makeText(applicationContext, "getSamsungPayStatus fail", Toast.LENGTH_SHORT).show()
        }
    })
}

Activate the Samsung Pay app

The SamsungPay class provides an API method called activateSamsungPay() to activate the Samsung Pay app on the same device where the partner app is running.

If the getSamsungPayStatus() returns SPAY_NOT_READY and the EXTRA_ERROR_REASON is ERROR_SPAY_SETUP_NOT_COMPLETE, the partner app needs to display an appropriate message to the user. Then, call activateSamsungPay() to launch Samsung Pay app and request the user to sign in.

In updateSamsungPayButton function, add the code to call activateSamsungPay method via doActivateSamsungPay function when the status is SPAY_NOT_READY:

// If EXTRA_ERROR_REASON is ERROR_SPAY_SETUP_NOT_COMPLETED,
// Call activateSamsungPay().
val extraError = bundle.getInt(SamsungPay.EXTRA_ERROR_REASON)
if (extraError == SamsungPay.ERROR_SPAY_SETUP_NOT_COMPLETED) {
    doActivateSamsungPay(SpaySdk.ServiceType.INAPP_PAYMENT.toString())
}

Create the doActivateSamsungPay function as below:

private fun doActivateSamsungPay(serviceType: String) {
    val bundle = Bundle()
    bundle.putString(SamsungPay.PARTNER_SERVICE_TYPE, serviceType)
    val partnerInfo = PartnerInfo(SERVICE_ID, bundle)
    val samsungPay = SamsungPay(this, partnerInfo)
    samsungPay.activateSamsungPay()
}

Create a transaction request

Upon successfully initializing the SamsungPay class, the merchant app should create a transaction request with payment information. Samsung Pay offers two types of online payment sheet―normal and custom.

The normal payment sheet has fixed display items ― Items, Tax, and Shipping. The custom payment sheet offers more dynamic controls for customizing the UI, together with additional customer order and payment data.

For this Code Lab, use the custom payment sheet and populate the fields in CustomSheetPaymentInfo to initiate a payment transaction.

/*
 * Make user's transaction details.
 * The merchant app should send PaymentInfo to Samsung Pay via the applicable Samsung Pay SDK API method for the operation
 * being invoked.
 * Upon successful user authentication, Samsung Pay returns the "Payment Info" structure and the result string.
 * The result string is forwarded to the PG for transaction completion and will vary based on the requirements of the PG used.
 * The code example below illustrates how to populate payment information in each field of the PaymentInfo class.
 */
private fun makeTransactionDetailsWithSheet(): CustomSheetPaymentInfo? {
    val brandList = brandList

    val extraPaymentInfo = Bundle()
    val customSheet = CustomSheet()

    customSheet.addControl(makeAmountControl())
    return CustomSheetPaymentInfo.Builder()
        .setMerchantId("123456")
        .setMerchantName("Sample Merchant")
        .setOrderNumber("AMZ007MAR")
        // If you want to enter address, please refer to the javaDoc :
        // reference/com/samsung/android/sdk/samsungpay/v2/payment/sheet/AddressControl.html
        .setAddressInPaymentSheet(CustomSheetPaymentInfo.AddressInPaymentSheet.DO_NOT_SHOW)
        .setAllowedCardBrands(brandList)
        .setCardHolderNameEnabled(true)
        .setRecurringEnabled(false)
        .setCustomSheet(customSheet)
        .setExtraPaymentInfo(extraPaymentInfo)
        .build()
}

private fun makeAmountControl(): AmountBoxControl {
    val amountBoxControl = AmountBoxControl(AMOUNT_CONTROL_ID, "USD")
    amountBoxControl.addItem(PRODUCT_ITEM_ID, "Item", 1199.00, "")
    amountBoxControl.addItem(PRODUCT_TAX_ID, "Tax", 5.0, "")
    amountBoxControl.addItem(PRODUCT_SHIPPING_ID, "Shipping", 1.0, "")
    amountBoxControl.setAmountTotal(1205.00, AmountConstants.FORMAT_TOTAL_PRICE_ONLY)
    return amountBoxControl
}

private val brandList: ArrayList<SpaySdk.Brand>
	get() {
		val brandList = ArrayList<SpaySdk.Brand>()
		brandList.add(SpaySdk.Brand.VISA)
		brandList.add(SpaySdk.Brand.MASTERCARD)
		brandList.add(SpaySdk.Brand.AMERICANEXPRESS)
		brandList.add(SpaySdk.Brand.DISCOVER)
	
		return brandList
	}

Request payment with a custom payment sheet

The startInAppPayWithCustomSheet() method of the PaymentManager class is applied to request payment using a custom payment sheet in Samsung Pay.

When you call the startInAppPayWithCustomSheet() method, a custom payment sheet is displayed on the merchant app screen. From there, the user can select a registered card for payment and change the billing and shipping addresses as necessary. The payment sheet lasts for 5 minutes after calling the API. If the time limit expires, the transaction fails.

In the MainActivity class, declare the paymentManager variable.

private lateinit var paymentManager: PaymentManager 

Then, in onCreate(), set an onClickListener method before calling the updateSamsungPayButton function to trigger the startInAppPayWithCustomSheet function when the SamsungPayButton is clicked.

dataBinding.samsungPayButton.setOnClickListener { startInAppPayWithCustomSheet() }

Lastly, create a function to call startInAppPayWithCustomSheet() method of the PaymentManager class.

/*
 * PaymentManager.startInAppPayWithCustomSheet is a method to request online(in-app) payment with Samsung Pay.
 * Partner app can use this method to make in-app purchase using Samsung Pay from their
 * application with custom payment sheet.
 */
private fun startInAppPayWithCustomSheet() {
    paymentManager = PaymentManager(applicationContext, partnerInfo)

    paymentManager.startInAppPayWithCustomSheet(
        makeTransactionDetailsWithSheet(),
        transactionInfoListener
    )
}


/*
 * CustomSheetTransactionInfoListener is for listening callback events of online (in-app) custom sheet payment.
 * This is invoked when card is changed by the user on the custom payment sheet,
 * and also with the success or failure of online (in-app) payment.
 */
private val transactionInfoListener: PaymentManager.CustomSheetTransactionInfoListener =
    object : PaymentManager.CustomSheetTransactionInfoListener {
        // This callback is received when the user changes card on the custom payment sheet in Samsung Pay.
        override fun onCardInfoUpdated(selectedCardInfo: CardInfo, customSheet: CustomSheet) {
            /*
             * Called when the user changes card in Samsung Pay.
             * Newly selected cardInfo is passed and partner app can update transaction amount based on new card (if needed).
             * Call updateSheet() method. This is mandatory.
             */
            paymentManager.updateSheet(customSheet)
        }

        override fun onSuccess(
            response: CustomSheetPaymentInfo,
            paymentCredential: String,
            extraPaymentData: Bundle
        ) {
            /*
             * You will receive the payloads shown below in paymentCredential parameter
             * The output paymentCredential structure varies depending on the PG you're using and the integration model (direct, indirect) with Samsung.
             */
            Toast.makeText(applicationContext, "onSuccess() ", Toast.LENGTH_SHORT).show()
        }

        // This callback is received when the online payment transaction has failed.
        override fun onFailure(errorCode: Int, errorData: Bundle?) {
            Toast.makeText(applicationContext, "onFailure() ", Toast.LENGTH_SHORT).show()
        }
    }

Run the app

After building the APK, you can run the sample merchant app and see how it connects to Samsung Pay upon clicking the button at the bottom of the screen. To thoroughly test the sample app, you must add at least one card to the Samsung Pay app.

You're done!

Congratulations! You have successfully achieved the goal of this Code Lab. Now, you can integrate In-App Payment with your app by yourself! If you face any trouble, you may download this file:

In-App Payment Complete Code
(2.26 MB)

To learn more about developing apps for Samsung Pay devices, visit:
developer.samsung.com/pay