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.

What You'll Learn

Get the code

Click the following link to download all the code for this codelab:

Download Zip

Check out the sample app

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.

Getting familiar with the code and running the sample app

Take a moment to explore the project structure and run the app.

Project structure

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.

Project structure

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.

Extras

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

Data Dictionary

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+.

Creation of the request

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

Define a ServiceConnection to manage the connection:

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
    }
}

Bound the service in the 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) }
    }

 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)
}

Display the response in your UI

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.

App payment information

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.