Terminal-2 icon

Make transactions

Add code to make Tap to Pay transactions using the Adyen POS Mobile SDK.

To enable the Adyen POS Mobile SDK for Android to handle payments, you need to add code to your Android POS app. This code starts a transaction with:

After you have added this code, payments take place as follows:

  1. Your Android POS app creates a Terminal API request that is serialized to JSON, or you receive the Terminal API payment request from your backend.
  2. You pass the Terminal API request to the Adyen POS Mobile SDK.
  3. The SDK checks if the session is still valid, and if necessary establishes a new session.
  4. The transaction starts on your mobile device.
  5. The SDK passes the Terminal API response to your POS app.

Handle a payment

In your Android POS app, add code for the following steps:

  1. If you create the Terminal API payment request in your POS app, use InPersonPayments.getInstallationId() as POIID in the MessageHeader of the payment request.
    Note that if you create the Terminal API payment request in the backend, the backend uses the installationId from the /checkout/posskd/v68/sessions response.

    For the structure of a Terminal API payment request, see Make a payment.

  2. Create an instance of TransactionRequest using TransactionRequest.create(nexoRequest), and pass the Terminal API payment request from your POS app or backend.

    val transactionRequest = TransactionRequest.create(nexoRequest)
  3. Get a PaymentInterface from InPersonPayments using InPersonPayments.getPaymentInterface(TapToPay).

    val paymentInterface = InPersonPayments.getPaymentInterface(TapToPay)
  4. Register a listener for the PaymentResult and pass the transactionResponse to your POS app. This is the Terminal API payment response, including data you can use to generate a receipt.

    InPersonPayments.registerForPaymentResult(context) { result -> 
      result.fold( 
        onSuccess = { paymentResult -> {
                      // Here your logic for paymentResult if (paymentResult.success) "Payment Successful" else "Payment Failed" 
                    }, 
        onFailure = { error -> {
                    // Here your logic for failure case 
                    },
            )
    
  5. Invoke InPersonPayments.performTransaction() with your transaction data, payment launcher, and authentication service.

    Then customize the user interface using merchantUiParameters with the following optional fields:

    • merchantLogo: A logo in WEBP, JPEG, or PNG format to show on your mobile device during the transaction flow. The logo will be shown at 100dp x 32dp (width x height).
    • autoDismissDelay: Indicates how long the SDK shows the screen that indicates the transaction succeeded. If not specified, this success screen is dismissed after four seconds. You can set a time in milliseconds as a Long with a minimum of 0.5 seconds (500L) and a maximum of 4 seconds (4000L).
    • tapToPayUiParameters: To choose different UI options for present card screen for Tap to Pay payments. Options for Front: Center, TopCenter, or BottomCenter. Options for Directional: TopCenter or BottomCenter.
    • cardReaderUiParameters: To choose different UI options for present card screen for NYC1 card reader payments. Options for Simplified: Center, CenterRight, or CenterLeft.
    InPersonPayments.performTransaction(
            context = this@DevAmountEntryActivity,
            paymentLauncher = paymentLauncher,
            paymentInterface = result.paymentInterface,
            transactionRequest = result.transactionRequest,
            merchantUiParameters = MerchantUiParameters.create(
                merchantLogo = commonR.drawable.temp_merchant_logo_int,
                tapToPayUiParameters = TapToPayUiParameters(Front(NfcFrontPosition.TopCenter)),
                cardReaderUiParameters = CardReaderUiParameters(Simplified(Position.CenterLeft)),
            ),
        )

    The Adyen POS Mobile SDK checks for a session and shows the transaction screen on your mobile device.

If the shopper does not present their payment method within 30 seconds, the payment request times out. If that happens, you need to make another payment request.

Handle a refund

There are two types of refund: referenced and unreferenced. The main difference is that a referenced refund is connected to the original payment, and an unreferenced refund isn't. That makes unreferenced refunds a bit riskier. For an overview of the differences, see Refund a payment.

Refunds are usually not processed synchronously. When you send a request for a referenced or unreferenced refund, the Terminal API response only confirms we received the request. Unreferenced refunds, however, can be processed synchronously. This depends on the card scheme and the country/region where the card is used. If processed synchronously, you receive an additional field in the Terminal API response: acquirerResponseCode.

To learn the outcome of a refund, you need to set up webhooks.

Handle a referenced refund

The Terminal API request for a referenced refund is a reversal request. The SDK contains a dedicated function for this.

In your Android POS app, add code for the following steps:

  1. If you create the Terminal API reversal request in your POS app, use InPersonPayments.getInstallationId() as POIID in the MessageHeader of the payment request.
    Note that if you create the Terminal API reversal request in the backend, the backend uses the installationId from the /checkout/posskd/v68/sessions response.

    For the structure of the Terminal API reversal request, see Referenced refund.

  2. Create an instance of TransactionRequestReversal using TransactionRequestReversal.create(nexoRequest), and pass the Terminal API payment request from your POS app or backend.

  3. Register a listener for the PaymentResult and pass the transactionResponse to your POS app. This is the Terminal API payment response, including data you can use to generate a receipt.

    val paymentLauncher = InPersonPayments.registerForPaymentResult(this) { refundResult ->
        // handle refund response here
        ...
    }
  4. Invoke performReversal() with your transaction data and authenticationProvider.
    Note that authenticationProvider is an implementation of the AuthenticationProvider interface, which extracts the sdkData from the server response.

    public fun performReversal(
        context: Context,
        paymentLauncher: ActivityResultLauncher<Intent>,
        transactionRequestReversal: TransactionRequestReversal,
    )  
  5. Check the refundResult that you receive in the paymentLauncher callback.

  6. Pass the refundResult to your POS app.

Handle an unreferenced refund

The Terminal API request for an unreferenced refund is a payment request with an additional parameter:

  • PaymentData.PaymentType: Refund

This means you can use the same code as for handling a payment. The only difference is the structure of the Terminal API payment request that you pass as the payload to the TransactionRequest.

For the structure of the Terminal API request, see Unreferenced refund.

Testing

To test transactions, you can use the following Adyen point-of-sale test cards:

The instructions are the same for both cards; see either of the pages mentioned above.

Troubleshooting

The Adyen payments platform performs regular checks to make sure that the mobile device on which the SDK is installed is secure. Errors that occur during the security attestation process need to be resolved to make transactions, including Store and Forward payments. Below you can find the table with the most common errors and how to handle them.

Error code Description Resolve offline Required action
ANDROID_NOT_UPDATED Transaction canceled. -x- Update the SDK to the latest software version and try again.
DEBUG_ENABLED_APK Transaction canceled. -white_check_mark- In Settings > System > Developer Options turn off Developer Options.
DEVELOPER_OPTIONS_ON Transaction canceled. -x- In Settings > System > Developer Options turn off Developer Options.
INVALID_NYC1_FIRMWARE_VERSION Card reader firmware version is invalid. -x- Update NYC1 to the latest software version and try again.
LOCAL_TIME_TAMPERING Transaction canceled. Unable to check the security requirements. -x- In Settings > System > Date and Time toggle on Automatic date and time.
NON_SELF_RESOLVABLE Transaction canceled. Unable to check the security requirements. -x- Contact our Support Team to resolve the issue.
NO_TOKEN Cannot transact. -x- Must go online for SDK to check security requirements.
PASSCODE_NOT_ENABLED Transaction canceled. Device passcode was removed, offline transaction data may have been lost. -white_check_mark- In Settings > System > Developer Options set a passcode for this device and try again.
All S&F transactions previously performed with passcode will be lost and cannot be recovered. You will not be able to continue transacting in S&F.
SECURITY_PATCH_LEVEL_OUTDATED Transaction canceled. -x- Update the SDK to the latest software version and try again.
SYSTEM_CHANGE Transaction canceled. Cannot transact due to system change. -white_check_mark- Must go online for SDK to check security requirements.
If the date/time of the device was changed, you must change it back to continue transacting. If the device was restarted, it must go online for the SDK to check security requirements.
TOKEN_EXPIRED_S&F Offline transaction window has expired. -x- Must go online for SDK to check security requirements.
UNSECURED_WIFI_NETWORK Transaction canceled. -white_check_mark- Connect to a secure Wi-Fi network and try again.
USB_DEBUGGING_ON Transaction canceled. -white_check_mark- In Settings > System > Developer Options turn off Developer Options.
WIFI_DEBUGGING_ON Transaction canceled. -white_check_mark- In Settings > System > Developer Options turn off Developer Options.

Next steps