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.
NoteIn accordance with the applicable Samsung partner agreements, this Code Lab covers setup and use of the Samsung Pay SDK for purposes of integrating the Samsung Pay app with partner apps. The use cases and corresponding code samples included are representative examples only and should not be construed as either recommended or required.
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:
- The merchant app allows the user to make payments with Samsung Pay.
- 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.
- The Samsung Pay app responds with the tokenized payment information necessary to complete the transaction.
- 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:
- Sign up for the Samsung Pay Developers site by clicking Sign Up and register your Samsung Account (or create it if you don't already have one), then Sign in.
- 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.
- Download the Samsung Pay SDK by going to Resources > SDK download.
- Add the Samsung Pay SDK jar file (samsungpay.jar) to your Android project using Android Studio or File Explorer.
- Develop your partner app with the required API calls and callbacks for Samsung Pay integration.
- Upload a release version of your app to the Samsung Pay Developers site for approval.
- Upon Samsung approval, publish your partner app to the Google Play store and Samsung Galaxy Apps.
NoteThe service ID is already provided in the sample code for this Code Lab. However, this service ID is for test purposes only and cannot be used for an actual application or service. Using the provided test service ID enforces your app to use the fixed properties below:
- Service ID: 0915499788d6493aa3a038
- Package Name: com.test.beta.pay
- App Version: 1.0/ 1 (or higher)
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>
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 site 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()
}
})
}
NoteAs of SDK version 1.5, if the device has Android Lollipop 5.1 (Android API level 22) or earlier versions, the getSamsungPayStatus()
API method returns a SPAY_NOT SUPPORTED
status code. Merchant apps using SDK 1.4 or earlier must check their app's Android version.
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