Skip to content

    SDK integration

    Overview

    In addition to the backend B2B API integration, the App2App SDK provides the client-side component necessary to complete the enrollment and payment flows from within the merchant’s mobile application. Acting as a bridge between the merchant app and the Nexi POS app (SoftPOS or mPOS), the SDK ensures a seamless and secure user experience by handling device-level interactions and deeplinks during key operations like enrollment, payment, reversal, account closure and get last transaction.

    The SDK relies on the App2AppIPC class, which must be instantiated in the merchant application and configured with core parameters such as appId, merchantUsername, redirectUri, and deviceId. A key element of this setup is the onGetRequestUri callback, which connects the SDK to the previously described PAR B2B API call, allowing the app to request a request_uri from the backend. This request_uri, once returned via callback, is injected into the SDK to complete the device enrollment process in a secure and standardized way.

    Once enrollment is complete, the SDK can execute operations such as payment, reversal, and get last transaction, each of which triggers the Nexi POS app via inter-process communication (IPC). Results are returned to the merchant app via deeplinks using a predefined scheme (e.g., demonexi://) and include full transaction details.

    The SDK design is fully asynchronous and coroutine-compatible, ensuring smooth integration with Kotlin and proper support for Java applications. Developers must handle thread management and UI updates carefully to avoid exceptions during background-to-main thread transitions.

    By combining the B2B API layer with the client-side SDK, the App2App solution provides a robust, end-to-end integration path for managing secure payment workflows between the merchant backend, frontend, and Nexi's payment infrastructure.

    Scope

    The technical interaction between App2App SDK and Merchant App involves the exchange of data through defined operations. In this context:

    • Incoming data: refers to data that App2App SDK receives from Merchant App during various operations.

    • Outgoing data: represents the data that App2App SDK sends back to Merchant App as a result of the operations.

    The scope of the interaction between the app (merchant application) and the App2App SDK is primarily related to facilitating secure and seamless payment transactions.

    The SDK likely serves as a bridge between the merchant's application and Nexi POS application, enabling the app to initiate, authorize, and handle payments.

    To perform any operation, the app is required to instance the App2AppIPC class, needed to send developer data and then, setup the connection to Nexi POS app.

    code

    class App2AppIPC( 
    internal val activity: Activity,     internal val appData: AppData,     
    internal val onGetRequestUri: (    
       deviceId: String, 
       onSuccess: (String) -> Unit,   
       onError: (String) -> Unit 
    ) -> Unit, 
    internal val onConnectionEvent: (ConnectionEvent) -> Unit = {} )

    The App2App IPC (Inter-Process Communication) class is responsible for setting up and handling the interaction with the App2App SDK. Hence, an instance of this class is needed before starting any operation. The class requires the following parameters:

    1. activity , current active activity.

    2. appData , data representing the app created by developer on web portal. AppData contains:

    • appId, the id of the app. (ID CLIENT on the web portal)

    • redirectUri, the URI chosen during app creation. (once created the App, save this info, cannot be retrieved if lost, and a new app logic Is required)

    • merchantUsername, the merchant username with which any operation will be run. ( If the email is not handled, please follow this setting: noreply@(companyname).com noreply2@(companyname).com noreplyn@(companyname).com)

    • merchantId, the merchant id corresponding to the account assigned on the portal. (ID AMMINISTRATORE on the web portal)

    • deeplinkScheme, the scheme used to get back to the caller app. “demonexi” as default.

    • domain, desired service domain among INTEGRATION, STAGING, PRODUCTION.

    1. onGetRequestUri (deviceId, onSuccess, onError), the callback through which it will be possible to enroll the current device during the enrollment phase.

    2. onConnectionEvent(ConnectionEvent): After having created an App2AppIPC instance, the connection must be opened by calling the connectToRemoteService method. This callback will notify any connection event, allowing the caller app to continue with any operation (pay, reversal,..)

    The App2AppIPC instance should be created ahead (ex: Activity/Fragment onCreate) and kept in memory, since it works with remote time sync to ensure secure network calls.

    Connection Event

    After having called the connectToRemoteService method, the SDK will search for one of the following apps in your device:

    • Nexi POS – package it.nexi.mpos
    • Nexi POS debug – package it.nexi.mpos.debug

    Aiming to connect the caller app with ONE instance of the Nexi POS application. The outcome of the search will be notified using the ConnectionEvent.

    Let’s explore all the possible outcomes:

    • One app is found, and the connection is secured, event type will be CONNECTED. After having received this specific event, the caller can interact with the SDK.

    • No app is found, the event type will be ERROR_APP_NOT_INSTALLED, and a service message is filled within the object. The Nexi POS app should be installed.

    • Both apps are found, the event type will be ERROR_MULTIPLE_APPS_INSTALLED, and a service message is filled within the object. One app should be removed.

    Throughout the caller app lifecycle, it could be useful receiving the DISCONNECTED event. This one can occur whether the Nexi App is closed or in case of OS memory cleaning.
    Having received a disconnection, it will be possible to call connectToRemoteService again to fix it up.

    To recap, the callback will make sure that the caller app is kept updated about the connection status.

    SDK APIs

    The caller app can run the following operations:

    • Payment, using the pay method.
    • Revert a transaction, using the revert method.
    • Close MPOS account, using the closeAccount method.
    • Retrieve the last transaction, using lastTransaction method.

    When calling any of them, the SDK will check if the device is enrolled, which implies a group of security checks have been executed on the device. The enrollment involves SDK internal calls, requesting the merchant application to provide the requestUri parameter.

    By passing the onGetRequestUri callback, the merchant app can prepare a specific flow to use the device id and produce the requestUri. The latter must be passed to the SDK, using the onSuccess callback, to allow the SDK to perform the enrollment

    SDK outcome and App outcome

    All methods will return an outcome via operationListener, which is not the real outcome of the operation (payment, reversal, close account), but the outcome of the SDK task. In case of failure, for example, the listener will tell why the SDK operation has failed. In case of success, instead, the SDK will notify about having completed its task and the Nexi POS app will be opened to finalize the operation.

    Happy flow:

    1. App calls pay method
    2. OperationListener notifies a success (could be used for tracking or logging events)
    3. The Nexi POS app is opened for running the payment through mPOS or SoftPOS
    4. After having completed the payment, the result is sent back via deeplink, using given deeplinkScheme and an operation-based authority (in this case payment)

    Unhappy flow:

    1. App calls pay method
    2. OperationListener notifies a failure, which can be used to show an error
    3. The Nexi POS is not opened

    Outcome and threads

    The operationListener will return the outcome in a background thread, so any operation inside success and failure callback should be a legit background operation.

    For example, to show a Toast, the app will have to wrap the logic inside a runOnUiThread scope.

    In the same way, a LiveData implementation should handle the result using the postValue method, instead of the classic value setter method.

    Any violation of background thread rules will result into an exception.

    Enrollment

    During payment or any App2App operation, the enrollment could be requested. In case of need, the onGetRequestUri callback will be called from the SDK and the application should gather necessary params to send a network request and get a request URI from our side.

    Request

    This is used to request a specific URI from the App2App service. It takes the following parameters:

    Name parameterDescriptionTypeMandatory
    thirdAppUserna meMerchantRepresents the username associated with the third-party application or merchant making the request.Stringyes
    thirdAppDeviceIdRepresents the unique identifier associated with the device of the third-party application or merchant.Stringyes
    appIdRepresents the application identifier associated with the third-party application.Stringyes
    merchantIdRepresents the merchant identifier associated with the third-party application.Stringyes
    terminalIdsRepresents a list of terminal identifiers associated with the thirdparty application or merchant.Stringyes

    Enrollment Constraints

    Keep in mind that:

    • After having enrolled a merchantUsername, any previous enrollment linked to the same username will be disabled.
    • After having enrolled a merchantUsername with a specific terminal ID, any previous enrollment linked to the same terminal ID will be disabled.

    This implies that a merchantUsername or a single terminal ID cannot be used on two devices at the same time. Therefore, in case of active enrollment on device A and a successful enrollment on device B:

    • The device B will have an active session
    • The device A will keep the previous one. In case of transaction on device A, it will receive a server error, easily solvable by calling the enrollment again. The session of device B will be invalidated.

    Payment

    The payment can be run by calling the pay method.

    code

    suspend fun pay(     paymentData: PaymentData, 
    operationListener: OperationListener 
    )

    The pay method takes an instance of PaymentData as an argument and an operationListener, which will propagate the operation outcome to the caller application.

    code

    data class PaymentData( <br>
    val amount: String?,<br>
    val callerTrxId: String?,<br>
    val isSendTicket: Boolean,<br>
    val isUrlTicket: Boolean,<br>
    val callerName: String?,<br>
    val addInfo1: String?,<br>
    val addInfo2: String?,<br>
    val addInfo3: String?,<br>
    val addInfo4: String?,<br>
    val addInfo5: String?,<br>
    val email: String?,<br>
    val sms: String?,<br>
    val autoClose: Boolean = false )
    
    interface OperationListener { <br>
    fun onSuccess(response: A2ASDKResponse? = null) <br>
    fun onFailure(error: A2ASDKResponse? = null) }
    
    data class A2ASDKResponse(     
    @SerializedName("isSuccess") val isSuccess: Boolean,     
    @SerializedName("exception") val exception: A2AException? 
    ) 
    data class A2AException( 
    @SerializedName("isServiceError")     val isServiceError: Boolean,
    @SerializedName("errorCode")     var errorCode: String? = null,
    @SerializedName("errorMessage")     val errorMessage: String?
    )

    In OnSuccess callback, the exception field will contain a null value.

    In OnFailure callback, the exception will be filled with an A2AException instance. In case of NetworkException, the HTTP error code and reason will be sent through errorCode and errorMessage fields. For any other error, the errorMessage field will be filled with a specific error message.

    PaymentData

    The PaymentData is a class used for holding information related to a payment. Each property in the class corresponds to a different aspect of the payment. PaymentData class properties are detailed below:

    Name parameterDescriptionTypeMandatory
    amountRepresents the amount of reversal in cents.Stringyes
    callerTrxIdRepresents the transaction ID associated with the callerStringyes
    isSendTicketFlag that enables the display of the send receipt button on transaction resultBooleanyes
    isUrlTicket ***Indicates whether the ticket is a URL linkBooleanyes
    callerNameRepresents the name of the caller initiating the reversalStringyes
    addInfo1Additional information fields that can be included with the paymentStringyes
    addInfo2Additional information fields that can be included with the paymentStringyes
    addInfo3Additional information fields that can be included with the paymentStringyes
    addInfo4Additional information fields that can be included with the paymentStringyes
    addInfo5Additional information fields that can be included with the paymentStringyes
    emailRepresents the email associated with the reversalStringyes
    smsRepresents the SMS information associated with the reversalStringyes
    autoCloseFlag that hides the buttons on transaction result and allows the application to automatically go back to caller application ONLY for not retryable transactions resultBooleanno (default false)

    *** Available only for MobilePOS

    Retryable Transaction Result

    A retryable transaction result occurs when the transaction can be retried. Examples:

    • Transaction canceled
    • Card read timeout
    • Wrong pin

    This result requires a user interaction, more precisely the tap on “Retry”. Hence, the autoClose flag will not affect the flow in this case.

    For not retryable ones, like a successful transaction or denied transaction, if autoClose value is true, the app will show the outcome animation and then close itself automatically. The caller app will receive the transaction data via deeplink.

    Since autoClose flag implies the buttons hiding and the isSendTicket implies the visualization of “send ticket” button, the usage of both together will NOT be allowed. If isSendTicket and autoClose are requested within the same session (both are true), the application will send the error “-21”.

    NB: The default isSendTicket value is true for backward compatibility, so to use the autoClose feature it is mandatory to specify the value isSendTicket false.

    Payment response example

    demonexi://payment?amount=00000000 0500&callerTrxId=316874221216&operationType=PAYMENT&f30=00000000 0500&F42=1000000278548%20%20&f12=171433&f11=000784&f55=9F36020345910A8113BDBAE2392050 0012&CT121=PIAZZA%20ARCOLE%20100%2C%2020143%2C%20MILANO%20(MI)&f13=210901&CT120=LA %20PATENTE%20(E- MAIL%2012)&f38=362077&9F14=1100&f37=424717057296&f39=000&CT118=978&CT117=Online&CT116 =00034&CT115=Contactless&CT114=NEXI%20Core&CT112=************5291&CT111=0&acquirerId=909 517&CT119=Grazie%20e%20arrivederci&f41=02546095&f43=LA%20PATENTE%20(E- MAIL%2012)%20PIAZZA%20ARCOLE%20100%2C%2020143%2C%20MILANO%20(MI)&f42=1000000278548 %20%20&CT110=2024-09- 03T17%3A14%3A36%2B02%3A00&f04=000000000500&CT107=17%3A14&CT106=03%2F09%2F2024&CT10 5=0100&CT104=LA%20PATENTE%20(E- MAIL%2012)%20PIAZZA%20ARCOLE%20100%2C%2020143%2C%20MILANO%20(MI)&CT103=42471705729 6&CT102=A0000000041010&CT101=96&CT123=9F360203459F2608D19D309F9058D6639F37046FCA3A23 95050000008001&CT100=5291&CT109=Mastercard&CT108=Mastercard&result=0&terminalId=02546095

    Reversal

    The reversal can be run by calling the reversal method.

    code

    suspend fun revert(    
    reversalData: ReversalData,     
    operationListener: OperationListener 
    )

    The reversal method takes an instance of ReversalData as an argument and an operationListener, which will propagate the operation outcome to the caller application.

    code

    data class ReversalData(   
    val amount: String?,    <br> 
    val timestamp: String?, <br> 
    val callerName: String?,  <br> 
    val email: String?,<br> 
    val sms: String?,<br> 
    val callerTrxId: String?,<br> 
    val terminalId: String?,<br> 
    val isSendTicket: Boolean,<br> 
    val isUrlTicket: Boolean,<br> 
    val autoClose: Boolean = false<br>  )

    ReversalData

    The ReversalData is a class used for holding information related to a reversal operation. Each property in the class corresponds to a different aspect of the payment. ReversalData class properties are detailed below:

    Name parameterDescriptionTypeMandatory
    amountRepresents the amount of reversal in cents.Stringyes
    timestampRepresents the timestamp of the reversalStringyes
    callerNameRepresents the name of the caller initiating the reversalStringyes
    emailRepresents the email associated with the reversalStringyes
    smsRepresents the SMS information associated with the reversalStringyes
    callerTrxIdRepresents the transaction ID associated with the callerStringyes
    terminalIdRepresents the ID of the terminalStringyes
    isSendTicketFlag that enables the display of the send receipt button on transaction resultBooleanyes
    isUrlTicket ***Indicates whether the ticket is a URL linkBooleanyes
    autoCloseFlag that hides the buttons on transaction result and allows the application to automatically go back to caller application ONLY for not retryableBooleanno (default false)

    *** Available only for MobilePOS

    Get Last Transaction

    The get last transaction action can be run by calling the getLastTransaction method.

    code

    suspend fun getLastTransaction( 
    getLastTransactionData: GetLastTransactionData,
    operationListener: OperationListener 
    )

    The getLastTransaction method takes an instance of GetLastTransactionData as an argument and an operationListener, which will propagate the operation outcome to the caller application.

    code

    data class GetLastTransactionData(    
    val callerName: String?,
    val terminalId: String?,
    val callerTrxId: String?
    ) 
    
    interface OperationListener {
    fun onSuccess(response: A2ASDKResponse? = null)
    
    fun onFailure(error: A2ASDKResponse? = null) 
    }

    GetLastTransactionData

    The GetLastTransactionData class is used for holding information related to the getLastTransaction operation. Class properties are detailed below:

    Name parameterDescriptionTypeMandatory
    callerNameRepresents the name of the caller appStringyes
    terminalIdRepresents the merchant terminal IDStringyes
    callerTrxIdRepresents the transaction ID associated with the callerStringyes

    The last transaction related to the given terminalId will be returned by back deeplink, containing all receipt parameters. The parameters will be returned through receipt field keys (documented in app2app specifications > SoftPOS Android > Receipt Field Keys) for both MPOS and SOFTPOS transactions.

    Moreover, to maintain the same signature of payment and reversal operations, the amount field is also returned via deeplink, valued with the same content of f30 receipt field.

    Coherently with transaction result, the result key will contain 0 in case of success call. In case of missing receipt error, the result key will contain the value -41.

    Accounting closure

    Account closure – MobilePOS Only! The account closure can be run by calling the closeAccount method. Only callable with an active MobilePOS TID

    code

    suspend fun closeAccount(
    closeAccountData: CloseAccountData,     operationListener: OperationListener )

    The closeAccount method takes an instance of CloseAccountData as an argument and an operationListener, which will propagate the operation outcome to the caller application.

    code

    data class CloseAccountData(     
    val callerName: String?,     val callerTrxId: String? 
    ) 
    
    interface OperationListener { <br>
    fun onSuccess(response: A2ASDKResponse? = null) 
    
    fun onFailure(error: A2ASDKResponse? = null) }

    CloseAccountData

    The CloseAccountData is a class used for holding information related to an account closure operation. Each property in the class corresponds to a different aspect of the account closure. CloseAccountData class properties are detailed below:

    Name parameterDescriptionTypeMandatory
    callerNameRepresents the name of the caller initiating the account closureStringyes
    callerTrxIdRepresents the transaction ID associated with the callerStringyes

    Was this helpful?

    What was your feeling about it?