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 all information. To complete this codelab, unzip and 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 button to request the payment information. This project uses Jetpack Compose for the UI and Kotlin Serialization for JSON serialization and deserialization.
For this codelab we will see how to implement the information request 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 | Action Type | 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 specific information |
As you can see the information request is a background action, this means that the payment solution will not show any UI when this intent is called. This is useful for requests that do not require user interaction, such as fetching configuration data. For this type of request we use Android Messenger service to get the response from the payment solution.
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 | ||||||
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, Not needed for Information | ||||||
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. Must be unique, part of the response, and not reused for subsequent requests (except for recovery). Any business application should store this before sending the intent. | 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 (see 3.3.1 Section in WPI interfacer) |
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 (see 3.3.1 Section in WPI interface) |
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_LAST_TRANSACTION | Recovery feature, know the status of latest transaction based of Session ID |
WPI_SVC_PAYMENT_INFORMATION | Used to reverse a previous transaction |
Response Data: Payment Solution Information
Field Name | Description | Type | Condition |
result | Result of the transaction (success or failure) | String (pre-defined 4.2.2 Result) | Mandatory |
errorCondition | Specific error reason (see table below) | String (pre-defined 4.2.3 Error Condition) | Mandatory |
softwareVersion | Software version of the payment solution | String | Conditional - WPI_RESULT_SUCCESS |
terminalIdentifier | Terminal identifier configured for the payment solution | String | Conditional - WPI_RESULT_SUCCESS |
terminalModel | Terminal model of the device | String | Conditional - WPI_RESULT_SUCCESS |
macAddress | MAC Address of used adapter. | String | Conditional - WPI_RESULT_SUCCESS |
supportedLanguages | Languages supported by the payment solution | Array | Conditional - WPI_RESULT_SUCCESS |
cardholderDefaultLanguage | Cardholder language | String | Conditional - WPI_RESULT_SUCCESS |
merchantLanguage | Merchant language | String | Conditional - WPI_RESULT_SUCCESS |
countryCode | Country code of the payment solution | String | Conditional - WPI_RESULT_SUCCESS |
defaultCurrency | Default currency | String | Conditional - WPI_RESULT_SUCCESS |
supportedCurrencies | Currencies the payment solution supports | Array | Conditional - WPI_RESULT_SUCCESS |
shopInfo | Shop information for the used terminal | Object (4.2.1 ShopInfo) | Conditional - WPI_RESULT_SUCCESS |
acquirerProtocol | The payment solution protocol used towards the acquirer | String | Conditional - WPI_RESULT_SUCCESS |
supportedTicketFormats | Receipt formats which the payment solution supports | Array | Conditional - WPI_RESULT_SUCCESS |
supportReceiptDelegation | Whether receipt delegation is supported or not. | Boolean | Conditional - WPI_RESULT_SUCCESS |
paymentInformation | Payment information per brand | Array | Conditional - WPI_RESULT_SUCCESS |
paymentSolutionSupportedServiceTypes | Supported services types by the payment solution | Array | Conditional - WPI_RESULT_SUCCESS |
supportsManualPanKeyEntry | Whether manual card data entry through the payment application is activated | Boolean | Conditional - WPI_RESULT_SUCCESS |
supportsTip | Whether tip is supported or not. | Boolean | Conditional - WPI_RESULT_SUCCESS |
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+.
For the purpose of the codelab we will be doing this in the MainActivity.kt file but in a real application you should create a dedicated class to handle the request. Create a bundle with the mandatory extras for payment information.
For the WPI_SESSION_ID
you can use a random UUID. For the WPI_VERSION
you are using "2.1" but, "2.0", "2.2" or "2.3" can be used depending on the WPI version supported by your payment solution.
val paymentInformationBundle = bundleOf(
"WPI_SERVICE_TYPE" to "WPI_SVC_PAYMENT_INFORMATION",
"WPI_VERSION" to "2.1",
"WPI_SESSION_ID" to UUID.randomUUID().toString()
)
You can get more information on how to use the Messenger service in the Android Messenger service
In hte main activity, we are going to declare the messenger service and the connection to the service, we also have a flag to know if we are bound to the service
/** Messenger for communicating with the service. */
private var mService: Messenger? = null
/** Flag indicating whether we have called bind on the service. */
private var bound: Boolean = false
/**
* Class for interacting with the main interface of the service.
*/
private val mConnection = object : ServiceConnection {
// Called when the connection with the service is established.
override fun onServiceConnected(className: ComponentName, service: IBinder) {
// Because we have bound to an explicit
// service that is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mService = Messenger(service)
bound = true
}
// Called when the connection with the service disconnects unexpectedly.
override fun onServiceDisconnected(className: ComponentName) {
bound = false
}
}
onStart
method of the activity:We create the intent with the action com.worldline.payment.action.PROCESS_INFORMATION
and we set the component to the first supported service for this action. and we put the extras with the payment information bundle we created in a previous step. Finally we bind the service with the intent and the connection we created before.
override fun onStart() {
super.onStart()
val intent = Intent("com.worldline.payment.action.PROCESS_INFORMATION").apply {
component = getWpiSupportedServices("com.worldline.payment.action.PROCESS_INFORMATION").first()
putExtras(paymentInformationBundle)
}
bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
}
We are using a helper function to get the first application that supports the action com.worldline.payment.action.PROCESS_INFORMATION
:
private fun Context.getWpiSupportedServices(action: String): List<ComponentName> {
val intent = Intent(action)
return packageManager.queryIntentServices(intent, 0)
.mapNotNull { ComponentName(it.serviceInfo.packageName, it.serviceInfo.name) }
}
895349
for the payment information response. private lateinit var updateJson: (String) -> Unit
private fun executePaymentInformation() {
val message = Message.obtain(
null,
895349,
paymentInformationBundle
)
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
895349 -> {
val data = msg.obj as? Bundle
val response = data?.getString("WPI_RESPONSE") ?: "No response"
updateJson(response)
}
else -> throw IllegalArgumentException("${msg.what} is an incorrect message identifier.")
}
}
}
val messenger = Messenger(handler)
message.replyTo = messenger
mService?.send(message)
}
In the onCreate
method of the activity we set up the UI with Jetpack Compose, for this you just need to update the updateJson
function to update the state of the paymentInfoJson
variable that is displayed in the UI. The PaymentInfoScreen composable is a simple screen with a button to execute the payment information request and a text field to display the response in JSON format. In a real application you would serialize the response and use it to update your business logic.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var paymentInfoJson by remember { mutableStateOf("") }
updateJson = { paymentInfoJson = it }
PaymentInfoScreen(paymentInfoJson) {
executePaymentInformation()
}
}
}
Now when you run the app and click on the button you should see the response from the payment solution in JSON format.
Congratulations, you've successfully completed this codelab and learned how to request payment information with the WPI!
You learned about how to create an intent request and bind yourself to the service to send a message, how to receive the response and display it.
What's next? Check out the others possible transactions in the documentation and try to handle them.