The Worldline Payment Interface (WPI) is an Android intent-based interface that enables easy and fast integration with payment apps. It is designed to allow additional business applications to execute payments on any Worldline offered SmartPOS device. A SmartPOS device is a payment device that runs Android And also smartphones using Tap On Mobile..
All Worldline Payment Solutions support WPI, which means that business applications that use this interface can run everywhere without any change of code. This makes it easy for developers to build payment apps that are compatible with a wide range of payment devices and payment protocols.
The WPI interface is built on top of the Android Intent mechanism, which allows different parts of an app to communicate with each other in a structured way. By using intents to trigger payment-related actions, the WPI interface simplifies the payment integration process and makes it easier for developers to build business applications on top of Payment Solutions.
Click the following link to download all the code for this codelab:
For this codelab we will use Android studio Narwhal Feature Drop, SDK 36 and Gradle 8.14.3Important Please verify that you have a payment application running on your device.
The code you just downloaded contains code for all codelabs available. To complete this codelab, open the samplecode
project inside Android Studio.
The codelabs repo contains starter code for all codelabs in the pathway. For this codelab, use the wpiCodelab project.
The project is built with two app folders:
We recommend that you start with the code in the start folder and follow the codelab step-by-step at your own pace.
During the codelab, you'll be presented with snippets of code that you'll need to add to the project. In some places, you'll also need to remove code that is explicitly mentioned in comments on the code snippets.
Take a moment to explore the project structure and run the app.
When you run the app from the ‘start' folder , you'll see that this is a very simple application with only a text field to enter an amount and a button to proceed to the payment.
For this codelab we will see how to implement a payment but the WPI provides a set of intents that developers can use to build apps that work with the interface. The following table lists each intent, along with its purpose:
Type | Display Action / Background Action | Intent | Purpose |
Financial | Display Action | com.worldline.payment.action.PROCESS_TRANSACTION | Process a financial transaction |
Management | Display Action | com.worldline.payment.action.PROCESS_MANAGEMENT | Trigger payment solution managed actions |
Information | Background Action | com.worldline.payment.action.PROCESS_INFORMATION | Background management of payment solution info |
Learn more about Android Messenger Service
An extra in Android intents is a way to pass additional data or parameters to another component in order to provide more context or information for the requested action. In WPI we have extras for request and response. The request extras needs to be provided by the Business Application that is using the interface and the response extra is provided by the Payment Solution.
Request:
Extra | Description | Type | Condition |
WPI_SERVICE_TYPE | Specify the subtype of action to be executed | String | Mandatory for all service types except WPI_SVC_LAST_TRANSACTION |
WPI_REQUEST | The request contains JSON structured data mandatory for given service type, in some specific cases this field is not given or empty | String | Mandatory for Financial, Optional for Management |
WPI_VERSION | Used WPI version | String | Mandatory |
WPI_SESSION_ID | Used as an identifier of a WPI exchange (a request/response) between a client application and a payment application. Is used to recover the status of the exchange in case of an unexpected failure. Is provided by the client and is part of the response. The session id must be unique, must be part of the response, must not be reused for subsequent requests (except for the last transaction request as it is used to do the recovery). Any business application should store the WPI_SESSION_ID before sending the intent. Due to this the business application can do a recovery with the last transaction function to check the outcome of the previous transaction in case that the business application has crashed. | String | Mandatory |
Response:
Extra | Description | Type | Condition |
WPI_SERVICE_TYPE | Specify the subtype of action that was executed | String | Mandatory for all service types except WPI_SVC_LAST_TRANSACTION |
WPI_RESPONSE | The response contains JSON structured data processed for the requested service type | String | Mandatory for all service types except WPI_SVC_LAST_TRANSACTION |
WPI_VERSION | Used WPI version | String | Mandatory |
WPI_SESSION_ID | Identifier of a WPI exchange provided by the client. | String | Mandatory |
Service type | Purpose |
WPI_SVC_PAYMENT | Used to perform a simple sale transaction also known as purchase |
WPI_SVC_CANCEL_PAYMENT | Used to reverse a previous transaction |
WPI_SVC_REFUND | Used to refund a previous transaction |
WPI_SVC_PRE_AUTHORIZATION | Used to perform a reservation |
WPI_SVC_CANCEL_PRE_AUTHORIZATION | Used to cancel a previous reservation |
WPI_SVC_UPDATE_PRE_AUTHORIZATION | Used to increment a previous reservation |
WPI_SVC_CANCEL_UPDATE_PRE_AUTHORIZATION | Used to cancel the previous incrementation of a reservation |
WPI_SVC_PAYMENT_COMPLETION | Used to purchase a reservation / incremented reservation |
WPI_SVC_CANCEL_PAYMENT_COMPLETION | Used to cancel the purchased reservation |
WPI_SVC_DEFERRED_PAYMENT_AUTHORIZATION | Used to execute a deferred payment authorization (energy solution use-case) |
WPI_SVC_DEFERRED_PAYMENT_COMPLETION | Used to execute a deferred payment completion of a previous authorization(energy solution use-case) |
WPI_SVC_PAYMENT_WITH_PRODUCT_DELIVERY | Used to execute a transaction with product delivery (vending use-case) |
WPI_SVC_PRODUCT_DELIVERY | Used to inform the payment solution that the product was delivered (vending use-case) |
WPI_SVC_PAYMENT_INSTRUMENT_RECOGNITION | Used to do a payment card of non payment card recognition request without performing a real transaction (token) |
Service type | Purpose |
WPI_SVC_PAYMENT_MENU | Used to open the payment solution menu |
WPI_SVC_DAY_END | Used to upload the transactions (online and offline) to perform the final settlement. |
WPI_SVC_PAYMENT_PARAMETERIZATION | Used to fetch the latest payment solution configuration from the payment solution related configuration system. |
WPI_SVC_ACQUIRER_PARAMETERIZATION | Used to fetch the latest acquirer parameters from the acquirer |
WPI_SVC_REPEAT_RECEIPT | Used to repeat the receipt printing |
WPI_SVC_ABORT | Used to abort an ongoing transaction |
WPI_SVC_LAST_TRANSACTION | Used to return the last transaction result |
WPI_SVC_PAYMENT_INFORMATION | Used to retrieve the payment solution information especially which service types are supported. |
Payment Request Data:
Field Name | Description | Type |
currency | Currency of the amount. Alpha code value defined in ISO 4217 (e.g. EUR) | String |
requestedAmount | Total payment amount as minor unit. The fractional digits are evaluated based on the currency. For example, 11.91€ must be sent as 1191 and the currency as EUR | Integer |
tipAmount | Tip amount to be added to the transaction | Integer |
cashbackAmount | Cashback amount to be added to the transaction | Integer |
reference | Reference to be sent to the payment solution for reconciliation | String |
customerLanguage | Language to be used for the cardholder (ISO 639-1 alpha-2 code) | String |
useManualPanKeyEntry | Whether manual card data entry is activated | Boolean |
receiptFormat | Receipt format(s) to override the default (see 4.1.1 Receipt Format) | Array |
receiptDelegation | Whether receipt delegation is supported | Boolean |
receiptWidth | Width of the receipt in characters | Integer |
recognitionTimeout | Defines the timeout before an error will be returned in milliseconds | Integer |
recognitionOptions | Card recognition options | Array |
Response Data:
Field Name | Description | Type |
result | Result of the transaction (success or failure) | String |
errorCondition | Specific error reason (see table below) | String |
reference | Reference to be sent to the payment app for reconciliation. | String |
remark | Terminal/transaction specific message for detailed error descriptions. | String |
actionCode | Specific action to be performed by the business application | String |
timestamp | Date and time of the transaction, indicated by the acquirer. ISO 8601 format | String |
currency | Currency code of the transaction. Alpha code value defined in ISO 4217 e.g. EUR | String |
authorizedAmount | Amount of the transaction. The fraction is taken from the currency code. | Integer |
customerLanguage | Language used on all screens towards the cardholder and when formatting the receipt. | String |
brandName | Brand name of used payment card, like MasterCard, VISA, AMEX and so on. | String |
applicationIdentifier | Payment card application identifier dependent on the used card | String |
applicationLabel | Payment card application label, depending on the used card | String |
receipt | Merchant and cardholder receipt. See section 5.2.5 Receipt. | Object |
paymentSolutionReference | Transaction specific and unique identification. | String |
acquirerIdentifier | Acquirer identifier | String |
merchantIdentifier | Merchant identifier | String |
terminalIdentifier | Terminal identifier configured for the payment solution | String |
authorizationCode | Authorization code | String |
cashbackAmount | Cashback amount | Integer |
tipAmount | Tip amount entered by the cardholder or provided in the request | Integer |
dccUsed | Whether DCC was used or not for the transaction | Boolean |
dccOffered | Whether DCC selection was shown towards the cardholder | Boolean |
dccAmount | DCC amount | Integer |
dccCurrency | DCC currency | String |
dccExchangeRate | DCC exchange rate | String |
entryMode | The technology that was used to read the card (see 4.2.7 Supported Technologies) | String |
authorizationMode | Authorization mode (see 4.2.10 Authorization Mode) | String |
pan | PAN of the card | String |
cardholderVerificationMethod | Cardholder verification method (see 4.2.13 Cardholder Verification Method) | String |
cardDataInput | Card data input (see 4.2.12 Card Data Input) | String |
Important: If your app targets Android 11 (API level 30) or higher, you must declare the external intents your app queries in your AndroidManifest.xml
using the queries
element. Without this, your app will not be able to discover or interact with payment solutions using WPI intents.
Add the following to your AndroidManifest.xml
(outside the
tag):
<queries>
<intent>
<action android:name="com.worldline.payment.action.PROCESS_INFORMATION" />
</intent>
<intent>
<action android:name="com.worldline.payment.action.PROCESS_TRANSACTION" />
</intent>
<intent>
<action android:name="com.worldline.payment.action.PROCESS_MANAGEMENT" />
</intent>
</queries>
This ensures your app can query and interact with payment solutions using the WPI interface on Android 11+.
Create a new data class SaleTransactionRequest
in the package com.worldline.wpi_codelab.model.request
. This class takes 2 parameters: the currency and the amount as these are the only mandatory parameters for a sale transaction.
@Serializable
public data class SaleTransactionRequest(
val currency: String,
val requestedAmount: Long,
)
To use the Serialization
you need to add the following code in your gradle.app:
plugins {
id("kotlinx-serialization")
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
}
To finish sync your project with Gradle files.
Create a second data class SaleTransactionResponse
in the package com.worldline.wpi_codelab.model.response
. This class takes 3 parameters: the result the currency and the amount. We can serialiaze more fields of the response based on the table of response data but, for this codelab we will only use these 3 fields.
@Serializable
data class SaleTransactionResponse(
val result: String?,
val authorizedAmount: Long? = null,
val currency: String? = null,
)
In the MainActivity
we will execute the transaction and handle the response. To do so we will use a registerForActivityResult
.
To have more information about how to get a result from an activity you can click here.
The first method will be executeSaleTransaction
and it will execute the registerForActivityResult
:
private fun executeSaleTransaction(amount: Long) {
val saleTransaction = SaleTransactionRequest("eur", amount)
val saleTransactionJson: String = Json.encodeToString(saleTransaction)
val intent = Intent("com.worldline.payment.action.PROCESS_TRANSACTION")
// These extras are mandatory whether the intent comes from the payment
// application or a 3rd party application.
intent.putExtra("WPI_SERVICE_TYPE", "WPI_SVC_PAYMENT")
intent.putExtra("WPI_REQUEST", saleTransactionJson)
intent.putExtra("WPI_VERSION", "2.1")
// Session value is always up to the third party application
// Random unique identifier of the current communication session
// Can be used to restore the state of the transaction in multipart communication (e.g. product delivery)
intent.putExtra("WPI_SESSION_ID", UUID.randomUUID().toString())
launcher.launch(intent)
}
The second method will be handleTransactionResponse
:
//allows ignoring fields we don't need in the response
private val json = Json { ignoreUnknownKeys = true }
private fun handleTransactionResponse(intent: Intent) {
val rawJsonResponse = intent.getStringExtra("WPI_RESPONSE")
if (rawJsonResponse != null) {
Log.d("Transaction response", rawJsonResponse)
val transactionResponse = json.decodeFromString<SaleTransactionResponse>(rawJsonResponse)
val paymentMessage = "${transactionResponse.result}: ${(transactionResponse.authorizedAmount?.toDouble()?.div(100))} ${transactionResponse.currency}"
Toast.makeText(this, paymentMessage, Toast.LENGTH_SHORT).show()
}
// Handle response
}
To finish this step, just add to your main activity the launcher
that will handle the result of the activity when you perform a payment:
private val launcher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
result.data?.let { handleTransactionResponse(it) }
}
Now that everything is set up, we will make the payment start by pressing the button.
As the amount formating is not the subject of this codelab, we use a simple solution with radio buttons and pre-defined amount.
To finish on this codelab, just add the executeSaleTransaction
function in the onSubmit of your SaleTransactionScreen
Composable:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SaleTransactionScreen { amount ->
executeSaleTransaction(amount)
}
}
}
Here we check which radio is checked and we lauch executeSaleTransaction
with the selected amount.
You can now run the app on a terminal and proceed to your first payment.
Congratulations, you've successfully completed this codelab and learned how to proceed to a payment with the WPI!
You learned about how to create a request, a response, and how to use the Worldline Payment Interface.
What's next? Check out the others possible transactions in the documentation and try to handle them.