Android Connect
Integrate with Android SDK
Integrate PortOne Payment Gateway with your Android app using the PortOne Android SDK and start accepting payments.
You can use PortOne SDK to integrate the PortOne Payment Gateway with your Android Application.
Video Tutorial
Part-1 : Installation of Android Native SDK
Part 2: Initialise the SDK and Set Intent Filters to receive the Payment Status
Sample App
Check the sample app to integrate on GitHub
Prerequisites
- Create an account on PortOne
- Enable Payment Channels and Methods which you want to use
- An Android application for the integration
authKey
to access the SDK 💡 *authKey will be issued by the PortOne Team. 1.* Send an email to [[email protected]](mailto:[email protected]) to request the authKey.
Integration
Steps to integrate your Android application with PortOne Android SDK.
- Install PortOne Android SDK and authorise it.
- Initialise theÂ
PortOne
 Instance in the activity where the checkout is being processed. - Set the Intent Filters in the manifests of the Android App.
- Set Intent Receivers to receive the payment status
- Have a setup to get JWT token from the server.
- Generate a signature hash to be passed with the payload
1. Install PortOne Android SDK and authorise it.
- To add PortOne SDK as a dependency, locate
build.gradle
(:app) in your Android app and add the following line
implementation 'com.github.iamport-intl:chaipay-android-native-sdk:V3.0.37'
- To access the PortOne SDK, you will require authorisation key to be added in your
gradle.properties
authKey= XXXXXXXXXXXXXXXXXXXXXX
- We must utilize the authkey in order to access the PortOne SDK. To
build.gradle
(:Project) orsettings.gradle
, add the following snippets.
repositories {
maven { url '<https://maven.google.com/>' }
maven{
url '<https://jitpack.io>'
credentials { username authKey }
}
}
- Include the following lines of code in build.gradle (:Project), mentioning the project dependency and the kotlin version.
buildscript {
ext.kotlin_version = "1.5.10"
dependencies {
classpath 'com.google.gms:google-services:3.0.0'
}
}
2. Initialise the PortOne
 Instance in the activity where the checkout is being processed.
PortOne
 Instance in the activity where the checkout is being processed.The PortOne object will be used to access checkout functions. You will additionally require to pass the environment, whether SANDBOX or LIVE.
private var environment = "sandbox" // For Sandbox
private var environment = "live" // For Live
private lateinit var portOne: PortOne
portone = PortOneImpl(this, "$environment")
3. Set the Intent Filters in the manifests of the Android App.
Add the following Intent Filter to the Activity to which you want the user to navigate after payment is completed. Default should be Checkout Activity.
To configure the intent filters, there are two parameters in the data
tag: host
and scheme
, whose values will be determined by the redirection URL.
if redirectionUrl= "**portone://checkout"**
then host = "**checkout"**
`scheme = "**portone"**`
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="checkout"
android:scheme="portone" />
</intent-filter>
4. Set Intent Receivers and listeners to receive the payment status
- The following method is to set the listener to receive the payment status
5. Have a setup to get JWT token from the server
On the server side, a JWT token must be constructed that accepts portoneKey as input. Further information on JWT token generation is described in the link below.
6. Generate Signture Hash
Make a Signature Hash on server side using secret key which will be included in the payload.
Merchant’s Checkout (V2)
Merchant’s Checkout The Android Native SDK is designed so that merchants can use their own user interfaces based on the theme that best suits the app, and they can inherit business logic in the form of various methods based on functionalities that do not involve a user interface.
The following methods are described in depth along with their application:
-
The following method is used to fetch the enabled payment channel and methods which are accessible for checkout.
Parameters Data Type portoneKey String mandatory subMerchantKey String Optional currency String mandatory portOne.getPaymentMethods( portoneKey = portoneKey, subMerchantKey = subMerchantKey, currency = currency, object : ApiCallbackInterface<PaymentDto.PaymentMethodResponse> { override fun onSucceed(response: PaymentDto.PaymentMethodResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
-
The following method is used to process the checkout using the the new card so it means if you have not saved this card before do the payment from the beginning using a card then this is the method to be used.
portOne.checkoutUsingNewCard( paymentDetails = PaymentDto.CheckoutUsingTokenizationRequest(), newCard = PaymentDto.NewCard(), token = jwtToken, )
PaymentDto.NewCard
Parameters Data Type cardNumber String mandatory cardType String mandatory cardholderName String mandatory serviceCode String mandatory expiryYear String mandatory expiryMonth String mandatory environment String mandatory portoneKey String mandatory PaymentDto.CheckoutUsingTokenizationRequest
Parameters Data Type portoneKey String mandatory paymentChannel String mandatory paymentMethod String mandatory merchantOrderId String mandatory amount Double mandatory currency String mandatory billingDetails CheckoutPaymentDto.BillingDetails Optional shippingDetails CheckoutPaymentDto.ShippingDetails Optional orderDetails List<CheckoutPaymentDto.OrderDetail> Optional successUrl String mandatory failureUrl String mandatory environment String mandatory signatureHash String mandatory redirectUrl String mandatory description String Optional source String mandatory transactionType String mandatory
💡 jwtToken is used for the Authentication in the Api which is being generated as per the instructions in the integration documentation.jwtToken
-
In order to do payment with the saved cards for the first time, the following method helps to fetch the cards associated with the phone number but to get cards OTP authentication is required so its divided into two steps:
-
Fetching the saved cards for the first time
-
The below method is used to send OTP to the registered phone number.
Parameters Data Type phoneNo String mandatory portOne.getOTP(phoneNo = phoneNo, object : ApiCallbackInterface<PaymentDto.OtpResponse> { override fun onSucceed(response: PaymentDto.OtpResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
-
After completion of the above step an OTP will be received on the phone. which will be used as the input.
Parameters Data Type token String Optional portoneKey String mandatory phoneNo String mandatory otp String mandatory portOne.getSavedCards( token = null, portoneKey = portoneKey, phoneNo = phoneNo, otp = otp, object : ApiCallbackInterface<PaymentDto.CreditCardDetailsResponse> { override fun onSucceed(response: PaymentDto.CreditCardDetailsResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
-
-
Fetching the saved cards multiple time
After fetching the saved cards for the first time in the response, the token is being received which can also be as an alternative of the authentication so instead of the otp, the token can be passed in the token param.| Parameters | Data Type | | | --- | --- | --- | | token | String | mandatory | | portoneKey | String | mandatory | | phoneNo | String | mandatory | | otp | String | Optional | ```kotlin portOne.getSavedCards( token = token, portoneKey = portoneKey, phoneNo = phoneNo, otp = null, object : ApiCallbackInterface<PaymentDto.CreditCardDetailsResponse> { override fun onSucceed(response: PaymentDto.CreditCardDetailsResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } }) ```
-
-
In order to process non-tokenise flow the following method is used. When we speak of non-tokenise checkout we include the payment methods which does not need to be tokenise.
portOne.checkoutWithoutTokenization( request = PaymentDto.CheckoutWithoutTokenizationReques() )
For the non-tokenise flow we need one object to be passed which contains the request for the checkout.
PaymentDto.CheckoutWithoutTokenizationRequest
💡 The above Params are common for all the non-tokenise checkout but according to the methods few additional params need to be passed with are described below.Parameters Data Type portoneKey String mandatory paymentChannel String mandatory paymentMethod String mandatory merchantOrderId String mandatory amount Double mandatory currency String mandatory billingDetails CheckoutPaymentDto.BillingDetails Optional shippingDetails CheckoutPaymentDto.ShippingDetails Optional orderDetails List<CheckoutPaymentDto.OrderDetail> Optional successUrl String mandatory failureUrl String mandatory environment String mandatory signatureHash String mandatory redirectUrl String mandatory description String Optional source String mandatory transactionType String mandatory - Direct Bank Transfer
- Instalments
The above two methods are also falls into the category of non-tokenise flow but these methods require few additional params in the request so below the whole flow for these methods has been described.
Direct Bank TransferFor Direct Bank Transfer checkout the following steps are required to be followed:
-
Fetch the Direct Bank Transfer details using the following method which only takes
portoneKey
as input:portOne.getDBTDetails(portoneKey = portoneKey, object : ApiCallbackInterface<PaymentDto.DBTResponse> { override fun onSucceed(response: PaymentDto.DBTResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
-
After getting the bank details we can pass the details to payload and process checkout.
portOne.checkoutUsingDirectBankTransfer( PaymentDto.CheckoutWithDirectBankTransferRequest() )
The following Request is replica of he request object checkout without tokenisation except the last added object
InstalmentsFor Instalments checkout the following steps are required to be followed:
-
To process the instalment fetching the bank list which provides instalments is required.
portOne.getBankList( channel = paymentChannel, request = PaymentDto.BankListRequest(), object : ApiCallbackInterface<PaymentDto.BankListResponse> { override fun onSucceed(response: PaymentDto.BankListResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
PaymentDto.BankListRequest()
Parameters Data Type amount Double mandatory environment String mandatory portoneKey String mandatory isMerchantSponsored Boolean mandatory paymentMethod String mandatory overrideDefault Boolean mandatory currency String mandatory In the response a list of banks and terms will be provided which are needed to be pass in the request body.
Parameters Data Type portoneKey String mandatory paymentChannel String mandatory paymentMethod String mandatory merchantOrderId String mandatory amount Double mandatory currency String mandatory billingDetails CheckoutPaymentDto.BillingDetails Optional shippingDetails CheckoutPaymentDto.ShippingDetails Optional orderDetails List<CheckoutPaymentDto.OrderDetail> Optional successUrl String mandatory failureUrl String mandatory environment String mandatory signatureHash String mandatory redirectUrl String mandatory description String Optional source String mandatory transactionType String mandatory DBTDetails PaymentDto.DBTDetails mandatory PaymentDto.DBTDetails
Parameters Data Type customerName String mandatory transactionTime String mandatory amountPaid Double mandatory -
The below request params are replica of of the request object checkout without tokenisation except the last added object
portOne.checkoutUsingInstallation( PaymentDto.CheckoutWithInstallationRequest() )
Parameters Data Type portoneKey String mandatory paymentChannel String mandatory paymentMethod String mandatory merchantOrderId String mandatory amount Double mandatory currency String mandatory billingDetails CheckoutPaymentDto.BillingDetails Optional shippingDetails CheckoutPaymentDto.ShippingDetails Optional orderDetails List<CheckoutPaymentDto.OrderDetail> Optional successUrl String mandatory failureUrl String mandatory environment String mandatory signatureHash String mandatory redirectUrl String mandatory description String Optional source String mandatory transactionType String mandatory bankDetails PaymentDto.BankDetails mandatory PaymentDto.BankDetails
Parameters Data Type bankCode String mandatory bankName String mandatory isMerchantSponsored Boolean mandatory overrideDefault Boolean mandatory installmentPeriod PaymentDto.TermObject mandatory PaymentDto.TermObject
Parameters Data Type month Int mandatory
Merchant Centric Card Vault
In the merchant centric card vault first a merchant is being enrolled and then for that merchant the customers are being added and we save cards according to the unique customer and below few methods are provided to do operations.
-
The following method is used to add customer.
portOne.addCustomer( token = token, portOneKey = portoneKey, subMerchantKey = subMerchantKey, request = PaymentDto.AddCustomerRequest( name = name, phoneNo = phoneNo, email = email, customerRef = customerRef ), object : ApiCallbackInterface<PaymentDto.AddCustomerResponse> { override fun onSucceed(response: PaymentDto.AddCustomerResponse) { val gson = Gson() val json = gson.toJson(response) LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
Parameters Data Type token String mandatory portoneKey String mandatory subMerchantKey String Optional name String mandatory phoneNo String mandatory email String mandatory customerRef String mandatory -
The following method is used to save a particular card for a specific customer.
portOne.addCardForCustomer( customerUUID = customerUUID, token = token, portoneKey = portoneKey, subMerchantKey = subMerchantKey, request = PaymentDto.NewCard(), object : ApiCallbackInterface<PaymentDto.AddCardsResponse> { override fun onSucceed(response: PaymentDto.AddCardsResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
Parameters Data Type customerUUID String mandatory token String mandatory portoneKey String mandatory subMerchantKey String Optional PaymentDto.NewCard
Parameters Data Type cardNumber String mandatory cardType String mandatory cardholderName String mandatory serviceCode String mandatory expiryYear String mandatory expiryMonth String mandatory environment String mandatory portoneKey String mandatory -
The following method is used to fetch the saved cards according to the customer.
portOne.listCardsForCustomer( customerUUID = customerUUID, token = token, portoneKey = portoneKey, subMerchantKey = subMerchantKey, object : ApiCallbackInterface<PaymentDto.ListCardsForCustomerResponse> { override fun onSucceed(response: PaymentDto.ListCardsForCustomerResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
Parameters Data Type customerUUID String mandatory token String mandatory portoneKey String mandatory subMerchantKey String Optional -
The following method is used to delete any particular card for a specific customer.
portOne.deleteCardForCustomer( customerUUID = customerUUID, token = token, portoneKey = portoneKey, subMerchantKey = subMerchantKey, request = PaymentDto.DeleteCardRequest(token = cardToken), object : ApiCallbackInterface<PaymentDto.GenericResponse> { override fun onSucceed(response: PaymentDto.GenericResponse) { LoggerUtil.info("Successful") } override fun onFailure( errorCode: Int?, status: String?, errorMessage: String, throwable: Throwable ) { LoggerUtil.info("Failed") } })
Parameters Data Type customerUUID String mandatory token String mandatory portoneKey String mandatory subMerchantKey String Optional Parameters Data Type Remarks cardToken String mandatory The Card Token can be retrieved in the above fetching the list of cards method
Pre Auth and Capture Payment
In Pre Authorisation the transaction is authorised first and after a certain time or days that payment can be captured using the Capture Api.
To set any transaction to be pre authorised one param need to be set in the payload which is
transactionType = *PREAUTH*
val paymentDetails= PaymentDto.CheckoutUsingTokenizationRequest()
paymentDetails.transactionType= "PREAUTH"
After pre authorising the transaction, the following method is used to capture the transaction.
portOne.captureTransaction(
orderReference = orderReference,
portoneKey = portoneKey,
token = token,
object : ApiCallbackInterface<PaymentDto.GenericResponse> {
override fun onSucceed(response: PaymentDto.GenericResponse) {
LoggerUtil.info("Successful")
}
override fun onFailure(
errorCode: Int?,
status: String?,
errorMessage: String,
throwable: Throwable
) {
LoggerUtil.info("Failed")
}
})
Parameters | Data Type | |
---|---|---|
orderReference | String | mandatory |
portoneKey | String | mandatory |
token | String | mandatory |
Probable Errors:
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
- Check whether PortOne Key and the Secret Key are of the same account
- Check whether the Secret Key is not modified
- Check whether
Bearer
keyword is added before the generated token with a white space.Bearer $jwtToken
- Verify if the expiration time should be greater than the current time
INVALID_UNAUTHORISED_TRANSACTION_SIGNATURE_ERROR
INVALID_UNAUTHORISED_TRANSACTION_SIGNATURE_ERROR
- Check whether all params match with the payload/request
- Check whether the portone key match with the payload and the account
INVALID_UNAUTHORISED_TRANSACTION_IAMPORTKEY_ERROR
INVALID_UNAUTHORISED_TRANSACTION_IAMPORTKEY_ERROR
- Check whether the portone key match with the payload and the account
INVALID_PAYMENT_CHANNEL
INVALID_PAYMENT_CHANNEL
- Make sure the payment channels and payment methods which are added in the payload are enable from the portone portal
INVALID_ENVIRONMENT
INVALID_ENVIRONMENT
- Make sure you have added environment either
sandbox
orlive
Summation of order value, tax, duties, shipping and discount is equal to amount
Summation of order value, tax, duties, shipping and discount is equal to amount
- If items are provided then please verify the values provided should match the total amount:Â
sum(items price * items quantity) + shipping charge - discount = amount
- Mandatory params in payload:
price
promo_discount (0 is also acceptable)
shipping_charges (0 is also acceptable)
Updated 11 days ago