{"title":"Android Payments app","category":"default","creationDate":1729690140,"content":"<p>If you want to accept Tap to Pay payments on your Android mobile device but do not want to integrate our POS Mobile SDK, you can download the Adyen Payments app from the Google Play store. You can then use the Payments app to connect your own POS app to the plataforma de pagamentos da Adyen and authenticate payment requests in a compliant way.<\/p>\n<p>This page explains how to build the Payments app solution. Before you begin, see <a href=\"\/pt\/point-of-sale\/mobile-android\/understand#sdk-or-papp\">Understand the solutions<\/a> to help you decide if the Payments app is the right solution for your situation.<\/p>\n<h2>Requirements<\/h2>\n<p>Before you begin, take into account the following requirements, limitations, and preparations.<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Requirement<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><strong>Integration type<\/strong><\/td>\n<td style=\"text-align: left;\">Your POS app must be integrated with <a href=\"\/pt\/point-of-sale\/design-your-integration\/terminal-api\/\">Terminal API<\/a>. The POS app can be installed on your mobile device or browser-based.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><strong><a href=\"\/pt\/development-resources\/api-credentials\/\">API credentials<\/a><\/strong><\/td>\n<td style=\"text-align: left;\">An API key specifically for the Adyen Payments app, with a <a href=\"\/pt\/development-resources\/client-side-authentication#get-your-client-key\">client key<\/a> and the <strong>Adyen Payments app role<\/strong>.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><strong>Hardware<\/strong><\/td>\n<td style=\"text-align: left;\">An Android commercial off-the-shelf (COTS) mobile device with an integrated NFC reader. Must not be a payment terminal. See <a href=\"\/pt\/point-of-sale\/mobile-android\/requirements\">Android system requirements<\/a> for the full hardware and software requirements.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><strong>Limitations<\/strong><\/td>\n<td style=\"text-align: left;\">Take into account the following limitations: <ul><li markdown=\"1\">See the countries\/regions, payment methods, and functionality that we <a href=\"\/pt\/point-of-sale\/ipp-mobile\">support<\/a>.<\/li> <li markdown=\"1\">Web-based POS apps are currently only supported in the US, the EU, and Australia.<\/li><\/ul><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><strong>Setup steps<\/strong><\/td>\n<td style=\"text-align: left;\">Before you begin: <ul><li markdown=\"1\">Contact our <a href=\"https:\/\/ca-test.adyen.com\/ca\/ca\/contactUs\/support.shtml?form=other\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Support Team<\/a> to enable Tap to Pay on Android and to enable the <strong>Adyen Payments app role<\/strong> for your API key. Optionally also ask them to <a href=\"\/pt\/point-of-sale\/basic-tapi-integration\/refund-payment\/unreferenced#before-you-begin-unreferenced\">enable unreferenced refunds<\/a>.<\/li> <li markdown=\"1\">Download the <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.adyen.ipp.mobile.companion.test\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Adyen Payments Test<\/a> app from the Google Play store.<\/li> <li markdown=\"1\">For testing, in your Customer Area order a <a href=\"\/pt\/point-of-sale\/testing-pos-payments\/test-card-v3\/\">White-green<\/a> Adyen test card. Or you can use a <a href=\"\/pt\/point-of-sale\/testing-pos-payments\/test-card-v2\/\">Blue-green<\/a> test card v2.4 or later, if you already have that.<\/li><\/ul><br>If your POS app is web-based: <ul><li markdown=\"1\">Contact our <a href=\"https:\/\/ca-test.adyen.com\/ca\/ca\/contactUs\/support.shtml?form=other\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Support Team<\/a> to enable receiving a <a href=\"#short-response\">short response in the browser<\/a>.<\/li> <li markdown=\"1\">Configure your web server to use HTTPS and enforce a minimum security protocol of TLS 1.2 or higher<\/li><\/ul><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>How it works<\/h2>\n<p>When building the various flows, you will use <a href=\"https:\/\/developer.android.com\/training\/app-links\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Android App Links<\/a> to call specific parts of the Android Payments app. To build an Android Payments app solution for Tap to Pay:<\/p>\n<ol>\n<li>Build the <a href=\"#board-the-app\">boarding flow<\/a>. The Payments app must be boarded on every Android mobile device where the app is installed.<\/li>\n<li>Build the <a href=\"#app-transactions\">payment flow<\/a>.<\/li>\n<\/ol>\n<p>In addition, do the following:<\/p>\n<ul>\n<li>Build the <a href=\"#reboard-the-app\">reboarding flow<\/a>. Reboarding enables you to switch to processing though a different store or merchant account using the same app instance and mobile device.<\/li>\n<li>Implement an API request to <a href=\"#revoke-app-instance\">revoke an app instance<\/a> for cases when the mobile device is defective, stolen, or no longer needed for payments.<\/li>\n<\/ul>\n<h2 id=\"board-the-app\">1. Board the app<\/h2>\n<p>After you download the Payments app from the Google Play store to a mobile device, you need to board the Payments app on that device. Boarding is a three-step process:<\/p>\n<ol>\n<li>\n<p><a href=\"#check-boarding-status\">Check the boarding status<\/a>.<br \/>\nFrom your POS app, you call a link to check if the Payments app is boarded. If the Payments app is not boarded, you receive a \"boarding request token\".<\/p>\n<\/li>\n<li>\n<p><a href=\"#authenticate-app-instance\">Authenticate the app instance<\/a>.<br \/>\nFrom your back-end, you send an API request that includes the boarding request token. In the response, you receive a one-time boarding token that is unique for the combination of Payments app instance and device.<\/p>\n<\/li>\n<li>\n<p><a href=\"#finish-boarding\">Finish boarding the app<\/a>.<br \/>\nFrom your POS app, you call a link that includes the boarding token. The response confirms that the Payments app is now boarded, and includes an installation ID that you need to pass in your transaction requests.<\/p>\n<\/li>\n<\/ol>\n<h3 id=\"check-boarding-status\">1.1 Check the boarding status<\/h3>\n<p>To start the boarding flow, you call an App Link from your POS app to check if the Adyen Payments app is already boarded.<\/p>\n<ol>\n<li>\n<p>From your POS app, call the link. The App Link format is as follows:<br \/>\n<code>https:\/\/www.adyen.com\/test\/boarded?returnUrl=URLEncoder(your_scheme)<\/code><\/p>\n<p>In this format:<\/p>\n<ul>\n<li><code>https:\/\/www.adyen.com\/test\/<\/code> is the test base URL.<\/li>\n<li><code>boarded<\/code> is the path to use for boarding checks.<\/li>\n<li><code>returnUrl<\/code> is the URL-encoded URL where you want to receive the response.<\/li>\n<\/ul>\n<p><\/p>\n<p>The following example shows how you could build the App Link in your Kotlin project.<\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Build an App Link to check if the Payments app is boarded'\" :id=\"''\" :code-data='[{\"language\":\"kotlin\",\"tabTitle\":\"\",\"content\":\"private fun createOnboardingCheckApplink(\\n    returnUrl: String,\\n): Uri {\\n    \\\/\\\/ Encode the returnUrl to ensure it is safe for use as a URL query parameter.\\n    val returnUrlEncoded = URLEncoder.encode(returnUrl, Charsets.UTF_8.name())\\n    return Uri.parse(\\\"${BuildConfig.APP_LINK_URL}\\\/boarded\\\").buildUpon()\\n        .appendQueryParameter(\\\"returnUrl\\\", returnUrlEncoded)\\n        .build()\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<p><\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'App Link example'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"https:\\\/\\\/www.adyen.com\\\/test\\\/boarded?returnUrl=your-scheme-test%3A%2F%2Fyour_company.example.com%2Fonboarding\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>Check the response you receive at your <code>returnUrl<\/code> and decide what to do next:<\/p>\n<ul>\n<li>If <code>boarded<\/code> is <span translate=\"no\"><strong>true<\/strong><\/span>: save the <code>installationId<\/code>, which you will need in your payment requests. You do not need to continue with the boarding process and you are ready to <a href=\"#app-transactions\">make a payment<\/a>.<\/li>\n<li>If <code>boarded<\/code> is <span translate=\"no\"><strong>false<\/strong><\/span>: pass the <code>installationId<\/code> and <code>boardingRequestToken<\/code> to your back-end and go to <a href=\"#authenticate-app-instance\">step 2 of the boarding process<\/a>.<\/li>\n<\/ul>\n<p>The response consists of the URL-encoded base URL where you want to receive the response and the following parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameter<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Type<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>boarded<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">Boolean<\/td>\n<td style=\"text-align: left;\">Indicates if the app is boarded or not.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>installationId<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The unique identifier of the Payments app instance on the specific device. <div class=\"sc-notice info\"><div> When creating Terminal API requests on your back-end, use this as the <code>POIID<\/code> in the <code>MessageHeader<\/code> of the request.<\/div><\/div><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>boardingRequestToken<\/code><\/td>\n<td style=\"text-align: center;\"><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The app token used to get the <code>boardingToken<\/code> from Adyen.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n\n<div id=\"taburBKi\">\n    <div data-component-wrapper=\"tabs\">\n        <tabs\n                        :items=\"[{&quot;title&quot;:&quot;Response: Payments app is not boarded&quot;,&quot;content&quot;:&quot;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Example response&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;text\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;{YOUR_SCHEME}%3A%2F%2Fyour_company.example.com%2Fonboarding?boarded=false&amp;amp;installationId=&amp;lt;INSTALLATION_ID&amp;gt;&amp;amp;boardingRequestToken=&amp;lt;BOARDING_REQUEST_TOKEN&amp;gt;\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&quot;,&quot;altTitle&quot;:null,&quot;oldTabId&quot;:&quot;response:_payments_app_is_not_boarded_0_1&quot;,&quot;relation&quot;:&quot;&quot;},{&quot;title&quot;:&quot;Response: Payments app is boarded&quot;,&quot;content&quot;:&quot;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Example response&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;text\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;{YOUR_SCHEME}%3A%2F%2Fyour_company.example.com%2Fonboarding?boarded=true&amp;amp;installationId=&amp;lt;INSTALLATION_ID&amp;gt;\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&quot;,&quot;altTitle&quot;:null,&quot;oldTabId&quot;:&quot;response:_payments_app_is_boarded_1_2&quot;,&quot;relation&quot;:&quot;&quot;}]\"\n            :should-update-when-url-changes='false'>\n        <\/tabs>\n    <\/div>\n<\/div>\n\n<\/li>\n<\/ol>\n<h3 id=\"authenticate-app-instance\">1.2. Authenticate the app instance<\/h3>\n<p>If you determined in <a href=\"#check-boarding-status\">step 1 of the boarding process<\/a> that the Payments app is not boarded yet or if you <a href=\"#initiate-reboarding\">initiated reboarding<\/a>, you send a  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/overview\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Payments app API<\/a> request from your back-end to authenticate your app installation. In the response you receive a <code>boardingToken<\/code>.<\/p>\n<p>To authenticate the app:<\/p>\n<ol>\n<li>\n<p>Make a POST request to the endpoint corresponding to where you want to accept payments:<\/p>\n<ul>\n<li>To route transactions over a merchant account, use  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/post\/merchants\/(merchantId)\/generatePaymentsAppBoardingToken\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">\/merchants\/merchantId\/generatePaymentsAppBoardingToken<\/a>.<\/li>\n<li>To route transactions over a store, use  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/post\/merchants\/(merchantId)\/stores\/(storeId)\/generatePaymentsAppBoardingToken\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">\/merchants\/merchantId\/stores\/storeId\/generatePaymentsAppBoardingToken<\/a>.<\/li>\n<\/ul>\n<div class=\"notices yellow\">\n<p>The app will be configured to the merchant account or store specified in the path, and route all transactions over that merchant account or store. Ensure this aligns with your account structure.<\/p>\n<\/div>\n<p>Specify the following in the request:<\/p>\n<ul>\n<li>\n<p>Path parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameters<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>merchantId<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">The unique identifier of the merchant account.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>storeId<\/code><\/td>\n<td style=\"text-align: center;\"><\/td>\n<td style=\"text-align: left;\">The unique identifier of the store. <div class=\"sc-notice info\"><div> The <code>storeId<\/code> is not the same as store <code>reference<\/code>. If you only know the <a href=\"https:\/\/docs.adyen.com\/api-explorer\/Management\/latest\/get\/merchants\/_merchantId_\/stores#query-reference\" class=\"codeLabel external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">reference<\/a>, you can use it to get the <code>storeId<\/code> with an API call. <\/div><\/div><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/li>\n<li>\n<p>Request parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameters<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>boardingRequestToken<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">The app token used to request a <code>boardingToken<\/code> from Adyen. You received the boarding request token in <a href=\"#check-boarding-status\">step 1 of the boarding process<\/a>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/li>\n<\/ul>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Create a boarding token request'\" :id=\"''\" :code-data=\"[{&quot;language&quot;:&quot;curl&quot;,&quot;tabTitle&quot;:&quot;&quot;,&quot;content&quot;:&quot;curl https:\\\/\\\/management-test.adyen.com\\\/v1\\\/merchants\\\/{merchantId}\\\/generatePaymentsAppBoardingToken \\\\\\n  -H 'x-API-key: ADYEN_API_KEY' \\\\\\n  -H 'content-type: application\\\/json' \\\\\\n  -X POST \\\\\\n  -d '{\\n    \\&quot;boardingRequestToken\\&quot;: \\&quot;BOARDING_REQUEST_TOKEN\\&quot;\\n}'&quot;}]\" :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>From the response, save the <code>boardingToken<\/code>, which you will need in the <a href=\"#finish-boarding\">last step of the boarding process<\/a>.<br \/>\nThe response consists of the following parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameter<\/th>\n<th style=\"text-align: left;\">Type<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>installationId<\/code><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The unique identifier of the Payments app instance on the specific device.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>boardingToken<\/code><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The one-time token used to authenticate the app installation. Valid for one hour.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Create boarding token response'\" :id=\"''\" :code-data='[{\"language\":\"json\",\"tabTitle\":\"\",\"content\":\"{\\n  \\\"installationId\\\": \\\"INSTALLATION_ID\\\",\\n  \\\"boardingToken\\\": \\\"BOARDING_TOKEN\\\"\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<\/ol>\n<h3 id=\"finish-boarding\">1.3. Finish boarding the app<\/h3>\n<p>When you have received the <code>boardingToken<\/code> from Adyen, you need to send the boarding token to the Payments app to finish boarding the app and prepare for making payments.<\/p>\n<ol>\n<li>\n<p>From your POS app, call the link. The App Link format is as follows:<\/p>\n<pre><code class=\"language-text\">https:\/\/www.adyen.com\/test\/board?boardingToken=Base64URL{APP_BOARDING_TOKEN}&amp;returnUrl=URLEncoder(your_scheme)<\/code><\/pre>\n<p>In this format:<\/p>\n<ul>\n<li><code>https:\/\/www.adyen.com\/test\/<\/code> is the test base URL.<\/li>\n<li><code>board<\/code> is the path to use for boarding requests.<\/li>\n<li><code>boardingToken<\/code> is the token generated for this <code>installationId<\/code> in <a href=\"#authenticate-app-instance\">step 2<\/a> of the boarding process. This token must be Base64URL-encoded.<\/li>\n<li><code>returnUrl<\/code> is the URL-encoded URL where you want to receive the onboarding result (the response).<\/li>\n<\/ul>\n<p><\/p>\n<p>The following example shows how you could build the App Link in your Kotlin project.<\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Build an App Link to board the Payments app'\" :id=\"''\" :code-data='[{\"language\":\"kotlin\",\"tabTitle\":\"\",\"content\":\"private fun createBoardingRequestApplink(\\n    returnUrl: String,\\n    boardingToken: String,\\n): Uri {\\n    \\\/\\\/ Encode the boarding token using Base64 URL encoding.\\n    val encodedBoardingToken = Base64.getUrlEncoder().encodeToString(boardingToken.toByteArray())\\n    \\\/\\\/ Encode the return URL to ensure it is safe for URL query parameters.\\n    val encodedUrl = URLEncoder.encode(returnUrl, Charsets.UTF_8.name())\\n\\n    return Uri.parse(\\\"${BuildConfig.APP_LINK_URL}\\\/board\\\").buildUpon()\\n        .appendQueryParameter(\\\"boardingToken\\\", encodedBoardingToken)\\n        .appendQueryParameter(\\\"returnUrl\\\", encodedUrl)\\n        .build()\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<p><\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'App Link example'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"https:\\\/\\\/www.adyen.com\\\/test\\\/board?boardingToken=ZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBZWFFpT2pFM05ERTROalkyT0RFMU9EWXNJbVY0Y0NJNk1UYzBNVGczTURJNE1UVTROaXdpYW1GaGMxVnpaWEpMWlhraU9pSjNjMTg0TXpZeU16RkFRMjl0Y0dGdWVTNVFZWGx0Wlc1MGMwMWhaR1ZGWVhONUlpd2liV1Z5WTJoaGJuUkJZMk52ZFc1MFEyOWtaU0k2SWsxcFkydE9kV2RuWlhSeklpd2lhVzV6ZEdGc2JHRjBhVzl1U1dRaU9pSkdOamxDUWprM05pMDJNRFkxTFRRME5URXRPVUZGTnkwMVFUaEJPVGsyUmpaQk1qa2lMQ0oxUTJGd2NFdGxlU0k2SWsxR2EzZEZkMWxJUzI5YVNYcHFNRU5CVVZsSlMyOWFTWHBxTUVSQlVXTkVVV2RCUlcxTmRqWmhTbTlSWkdabGFXbG5SWGRSVmxjMVlWSkJkM05ZZG1OaGMweGhTVk52ZGpnM05Hc3JUbEZFT0VsRVJXaDRLM1V5UTJkdVVVZDVXalpsU0RKNk5uWTJSVVpEU1U5VU5UWm5kbUpXV1VOeVozQjNQVDBpTENKaWRXNWtiR1ZKWkNJNkltTnZiUzVoWkhsbGJpNXBjSEF1bFc5aWFXeGxMbU52YlhCaGJtbHZiaTVrWlhZaUxDSnViMjVqWlNJNklrVjVTbkpFWkRGWE4zWjZiekJFVURraUxDSm9iM04wY3lJNmV5SmpiMjVtYVdkMWNtRjBhVzl1SWpvaWFIUjBjSE02THk5amFHVmphMjkxZEhCdmN5MTBaWE4wTG1Ga2VXVnVMbU52YlM5amFHVmphMjkxZEhCdmN5SjlMQ0owZVhCbElqb2lRazlCVWtSSlRrZGZWRTlMUlU0aWZRLkxXOS1mZ3g5V201dzVlMFlQdTNzRFAwbFZpNmQyQ21vRmpPQ0plcVlUQTl3ckM5NGNjeVJPaW0wbGJJeU9FbnJpSXVxMlVZWEJ2bGR2dmNPalVpeEhn&amp;returnUrl=your-scheme-test%3A%2F%2Fyour_company.example.com%2Fonboardingresult\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>Check the response and decide what to do next:<\/p>\n<ul>\n<li>If <code>boarded<\/code> is <span translate=\"no\"><strong>true<\/strong><\/span>: save the <code>installationId<\/code>. You need this when you <a href=\"#app-transactions\">make a payment<\/a>. You do not need board the app again.<\/li>\n<li>If <code>boarded<\/code> is <span translate=\"no\"><strong>false<\/strong><\/span>: check the <code>error<\/code> and try again.<\/li>\n<\/ul>\n<p>The response consist of the URL-encoded base URL where you want to receive the response and the following parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameter<\/th>\n<th style=\"text-align: left;\">Type<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>boarded<\/code><\/td>\n<td style=\"text-align: left;\">Boolean<\/td>\n<td style=\"text-align: left;\">Indicates if the app is boarded or not.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>installationId<\/code><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The unique identifier of the Payments app instance on the specific device. <div class=\"sc-notice info\"><div> When creating Terminal API requests on your back-end, use this as the <code>POIID<\/code> in the <code>MessageHeader<\/code> of the request.<\/div><\/div><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>error<\/code><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">Additional information in case an error occurred and <code>boarded<\/code> is <span translate=\"no\"><strong>false<\/strong><\/span>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Example response'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"{YOUR_SCHEME}%3A%2F%2Fyour_company.example.com%2Fonboardingresult?boarded=true&amp;installationId=APP_INSTALLATION_ID\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<\/ol>\n<h2 id=\"app-transactions\">2. Make a transaction<\/h2>\n<p>After the Payments app is boarded, you are ready to make transactions. To do this, you need to create a Terminal API request in Base64URL format and call the request as an App Link from your POS app. The boarded Payments app then communicates with Adyen, receives the response, and returns the response in Base64 format as part of an App Link to your POS app.<\/p>\n<p>To start a transaction from your POS app:<\/p>\n<ol>\n<li>\n<p>Create a Terminal API request with the <code>POIID<\/code> value set to the <code>installationId<\/code> value of the boarded Payments app.<\/p>\n<ul>\n<li>For a <a href=\"\/pt\/point-of-sale\/basic-tapi-integration\/make-a-payment\/#make-a-payment\">payment<\/a>, <a href=\"\/pt\/point-of-sale\/partial-payments\/\">partial payment<\/a>, <a href=\"\/pt\/point-of-sale\/pre-authorisation\/\">pre-authorization<\/a>, or <a href=\"\/pt\/point-of-sale\/basic-tapi-integration\/refund-payment\/unreferenced\/\">unreferenced refund<\/a>, create a  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/terminal-api\/latest\/post\/payment\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">PaymentRequest<\/a>.<\/li>\n<li>For a <a href=\"\/pt\/point-of-sale\/basic-tapi-integration\/refund-payment\/referenced\/\">referenced refund<\/a>, create a  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/terminal-api\/latest\/post\/reversal\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">ReversalRequest<\/a>.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Encrypt the Terminal API request as described for a Terminal API integration with local communications.<\/p>\n<ol>\n<li><a href=\"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/#set-up-shared-key\">Set up a shared key<\/a> in your Customer Area or using Management API.<\/li>\n<li>\n<p>Either <a href=\"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/protect\/\">write your own code<\/a> to encrypt and decrypt Terminal API messages, or <a href=\"\/pt\/point-of-sale\/design-your-integration\/choose-your-architecture\/local\/protect-with-library\/\">use a library<\/a>.<\/p>\n<p>The following example shows how you could encrypt Terminal API requests using the <a href=\"https:\/\/github.com\/Adyen\/adyen-java-api-library\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Java library<\/a> in a Kotlin project. We also have a <a href=\"https:\/\/github.com\/Adyen\/adyen-dotnet-api-library\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">.NET library<\/a> and a <a href=\"https:\/\/github.com\/Adyen\/adyen-node-api-library\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Node library<\/a>.<\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Encrypt using Java library'\" :id=\"''\" :code-data='[{\"language\":\"kotlin\",\"tabTitle\":\"\",\"content\":\"private fun encryptNexoRequest(\\n        serviceId: String = UUID.randomUUID().toString(),\\n        saleId: String = \\\"AndroidSampleApp\\\",\\n        currency: String,\\n        requestedAmount: BigDecimal,\\n        installationId: String,\\n    ): String {\\n        \\\/\\\/ Create and set up the message header for the Terminal API request\\n        val messageHeader = MessageHeader().apply {\\n            protocolVersion = \\\"3.0\\\"\\n            messageClass = MessageClassType.SERVICE\\n            messageCategory = MessageCategoryType.PAYMENT\\n            messageType = MessageType.REQUEST\\n            serviceID = serviceId\\n            saleID = saleId\\n            poiid = installationId\\n        }\\n\\n        \\\/\\\/ Set up the security key with the values from the Customer Area or Management API\\n        val securityKey = SecurityKey().apply {\\n            adyenCryptoVersion = 1\\n            keyIdentifier = BuildConfig.KEY_IDENTIFIER\\n            passphrase = BuildConfig.PASS_PHRASE\\n            keyVersion = BuildConfig.VERSION\\n        }\\n\\n        \\\/\\\/ This function creates a Terminal API request and returns the serialized value\\n        val nexoRequestJson = createNexoRequest(messageHeader = messageHeader, currency = currency, requestedAmount = requestedAmount)\\n\\n        \\\/\\\/ Encrypt the Terminal API request using the NexoCrypto class\\n        \\\/\\\/ The first parameter is the serialized Terminal API request, and the second parameter is the message header\\n        val encrypted = NexoCrypto(securityKey).encrypt(\\n            nexoRequestJson,\\n            messageHeader,\\n        )\\n\\n        \\\/\\\/ Add the encryption response to the TerminalAPISecuredRequest\\n        val terminalSecuredRequest = TerminalAPISecuredRequest()\\n        terminalSecuredRequest.saleToPOIRequest = encrypted\\n\\n        \\\/\\\/ You can use your own serialization library to convert the encrypted request to JSON\\n        \\\/\\\/ Ensure your serialization library properly handles HMAC and nonce properties:\\n        \\\/\\\/ These properties are byte arrays, and they need to be serialized into Base64-encoded strings.\\n        \\\/\\\/ If you use the Adyen Java library, it provides a specific Gson configuration for this purpose\\n        val gson = TerminalAPIGsonBuilder.create()\\n\\n        \\\/\\\/ Adjust if using a different serialization library\\n        return gson.toJson(terminalSecuredRequest)\\n    }\\n\\n    \\\/\\\/ This function creates an example Terminal API request. Include additional fields as needed.\\n    \\\/\\\/ You can use your own model and serialization library. This is just an example.\\n    private fun createNexoRequest(\\n        messageHeader: MessageHeader,\\n        currency: String,\\n        requestedAmount: BigDecimal,\\n        transactionID: String = \\\"SampleApp-AndroidTx\\\",\\n    ): String {\\n\\n        val saleTransactionID = TransactionIdentification().apply {\\n            timeStamp = getCurrentXMLGregorianCalendar()\\n            this.transactionID = transactionID\\n        }\\n\\n        val saleData = SaleData().apply {\\n            this.saleTransactionID = saleTransactionID\\n        }\\n\\n        val amountsReq = AmountsReq().apply {\\n            this.currency = currency\\n            this.requestedAmount = requestedAmount\\n        }\\n\\n        val paymentTransaction = PaymentTransaction().apply {\\n            this.amountsReq = amountsReq\\n        }\\n\\n        val paymentRequest = PaymentRequest().apply {\\n            this.saleData = saleData\\n            this.paymentTransaction = paymentTransaction\\n        }\\n\\n        val saleToPOIRequest = SaleToPOIRequest().apply {\\n            this.messageHeader = messageHeader\\n            this.paymentRequest = paymentRequest\\n        }\\n\\n        val terminalAPIRequest = TerminalAPIRequest().apply {\\n            this.saleToPOIRequest = saleToPOIRequest\\n        }\\n        val gson = TerminalAPIGsonBuilder.create()\\n        return gson.toJson(terminalAPIRequest)\\n    }\\n\\n    private fun getCurrentXMLGregorianCalendar(): XMLGregorianCalendar {\\n        \\\/\\\/ Create a GregorianCalendar instance with UTC timezone\\n        val calendar = GregorianCalendar().apply {\\n            time = Date()\\n        }\\n        calendar.timeZone = java.util.TimeZone.getTimeZone(\\\"UTC\\\")\\n        \\\/\\\/ Convert GregorianCalendar to XMLGregorianCalendar\\n        return DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar)\\n    }\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>Encode the Terminal API request to Base64URL.<\/p>\n<\/li>\n<li>\n<p>From your POS app, call the link. The App Link format is as follows:<\/p>\n<pre><code class=\"language-text\">https:\/\/www.adyen.com\/test\/nexo?request=NexoRequest.Base64Url{Encryption{NexoRequest}}&amp;returnUrl=URLEncoder(your_scheme)<\/code><\/pre>\n<p>In this format:<\/p>\n<ul>\n<li><code>https:\/\/www.adyen.com\/test\/<\/code> is the test base URL.<\/li>\n<li><code>nexo<\/code> is the path to use for transactions.<\/li>\n<li><code>request<\/code> is the Base64URL-encoded and encrypted Terminal API payment request.<\/li>\n<li><code>returnUrl<\/code> is the URL-encoded URL where you want to receive the Terminal API response.<\/li>\n<\/ul>\n<p><\/p>\n<p>The following example shows how you could build the App Link in your Kotlin project.<\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Build an App Link to initiate a payment'\" :id=\"''\" :code-data='[{\"language\":\"kotlin\",\"tabTitle\":\"\",\"content\":\"private fun buildPaymentRequestApplink(\\n    returnUrl: String,\\n    encryptedTapiRequest: String,\\n): Uri {\\n    val returnUrlEncoded = URLEncoder.encode(returnUrl, Charsets.UTF_8.name())\\n    val encoded = Base64.getUrlEncoder().encodeToString(encryptedTapiRequest.toByteArray())\\n    return Uri.parse(\\\"${BuildConfig.APP_LINK_URL}\\\/nexo\\\").buildUpon()\\n        .appendQueryParameter(\\\"request\\\", encoded)\\n        .appendQueryParameter(\\\"returnUrl\\\", returnUrlEncoded).build()\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<p><\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'App Link example'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"https:\\\/\\\/www.adyen.com\\\/test\\\/nexo?request=eyJTYWxlVG9QT0lSZXF1ZXN0Ijp7Ik1lc3NhZ2VIZWFkZXIiOnsiTWVzc2FnZUNhdGVnb3J5IjoiUGF5bWVudCIsIk1lc3NhZ2VDbGFzcyI6IlNlcnZpY2UiLCJNZXNzYWdlVHlwZSI6IlJlcXVlc3QiLCJQT0lJRCI6IkY2OUJCOTc2LTYwNjUtNDQ1MS05QUU3LTVBOEE5OTZGNkEyOSIsIlByb3RvY29sVmVyc2lvbiI6IjMuMCIsIlNhbGVJRCI6IkFuZHJvaWRTYW1wbGVBcHAiLCJTZXJ2aWNlSUQiOiI4NzE2MDg0NC02In0sIk5leG9CbG9iIjoiY3UrVGJwOHZWekIvZy9GWkZFMGJTWlpzUVh5Y1lWL3ZrM2ltZk9KbjhyTm1sQ1dEMkRnbS9qK2FQendIK3hXVDZhNU1JYjVSSlp5UkwrQmQ5c01SSStYYUFQYzBBTS9keWNXN2lTN0FJcGprUnZXNnV2OVlnUmdFbGl1NE1Nd1pkZndlNk11YzE1RGhqYko1SjVVc3VCSFFveHdDSjF5MTBSbTdlZUw3RXd1RlppZnU2OVBIWjB2U3ZxTytRL2doK0Eya1dVSThXSG5tTXAzWGlLL1JWdFp5WmJTaStSNkdFSVowVVVhYU85eW5TalpYZTBPTSs3YTdySXlqRmxQQkUvQS90SlRoVEtjZSs4YjZkc3JITFVLeVhmUFJjc1pGc1FUVk9ra2kvSkZnUjJqc2krZzZjUHJ4Y3oxVWpCRENGSTdiYk9pVjhKQ1pkdFlINnAxMUdpRXRJV1AzU2Qvb0ZDUkduK1lKelNRTGR2UFo0R2tHV3liZEoyb0ZaTEhrTmVXa0o1N29YN3RkcVNsajNrMjJCMzdzZ0p4STgzU3hielljRmQya2pQckFHOUpHOFNHL041M1JKTTNSY0lMK2Q1MndVM2MvRDl2TkNqYW01V2dOZldYT3cyeDFoNlR0L1lQNXdkdHFsTFpYNG55b3BKNndZMS9FZTBIUWIzVFJ0WEswWHBEbmphdGJkKzhWVm4xdGQxbmhDTDgzTDYxWXJRWUEyMG9XN25rOVI5dVY0ZDdnc0U2ZENGUzJMSmI4UytiYmVnd2szaGhJM0dRMEFJWHJpOG5ZaHhWNFF1M0o1dFJ3Unl4VDZYWW5oRnRDU3ZQTzNyY0VFcGpqeTZDTitBcHMrcVJrWWY0S1BnWkIyWU9mcnQrUlM1K080Tnp3OFkyOStaMCtHOVVJeHNLMVVIY1psWVFDTkFvOHNqRzdtalNDTm90Q2JTYk9BcVJIZmU5eXI1azRtdXZHenRzcUM4Y3R2aGRLeXpUQk5jTTJzR3NodzVJZis5TUJYRkR0WFJ1OFVFVEN3V2xDNnpNWXZreUphWHB6V2NOOVRJQ29HY2J4RkVMTWRBNjlVSjV2UktsNW9mTzd4UEhNSU9sSzBIYlpheElmeklJeDg1dGxPV2wzbUZnUCtJbzlDangrTXA4TklpaDJEeTkvVlE5L1NPeTVIeHFYYjRWb2JCNHdwUW91YXh0YzNuTEVLYktQaVZxd1R3PT0iLCJTZWN1cml0eVRyYWlsZXIiOnsiQWR5ZW5DcnlwdG9WZXJzaW9uIjoxLCJIbWFjIjoiT2N1aGMvVHJtaDlCL1FWQ2JmbFVsd3E0aTN3T2lKbkVTaC95RmovZDM1Zz0iLCJLZXlJZGVudGlmaWVyIjoidGhpcyIsIktleVZlcnNpb24iOjEyMywiTm9uY2UiOiJFK0VuRVFRUkFjc21YWlpMTng1c0lBPT0ifX19&amp;returnUrl=your-scheme-test%3A%2F%2Fyour_company.example.com\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<p>A Tap to Pay screen appears on the mobile device.<\/p>\n<div class=\"notices green\">\n<p>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.<\/p>\n<\/div>\n<\/li>\n<li>\n<p>Use the response to show the payment result in your POS app. Select the tab <em>Receive full response<\/em> if your POS app is installed on your mobile device. Select the tab <em>Receive short response in browser<\/em> if you are using a browser-based POS app.<\/p>\n\n<div id=\"tabA3sEC\">\n    <div data-component-wrapper=\"tabs\">\n        <tabs\n                        :items=\"[{&quot;title&quot;:&quot;Receive full response&quot;,&quot;content&quot;:&quot;\\n&lt;p&gt;When your POS app is installed on the mobile device, you receive the full payment response. The response consist of the &lt;code&gt;returnUrl&lt;\\\/code&gt; you specified in the link, and the following parameters:&lt;\\\/p&gt;\\n&lt;table&gt;\\n&lt;thead&gt;\\n&lt;tr&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Parameter&lt;\\\/th&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Type&lt;\\\/th&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Description&lt;\\\/th&gt;\\n&lt;\\\/tr&gt;\\n&lt;\\\/thead&gt;\\n&lt;tbody&gt;\\n&lt;tr&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;&lt;code&gt;response&lt;\\\/code&gt;&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;String&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;Base64URL-encoded and encrypted Terminal API payment response.&lt;\\\/td&gt;\\n&lt;\\\/tr&gt;\\n&lt;tr&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;&lt;code&gt;error&lt;\\\/code&gt;&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;String&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;Additional information in case an error occurs.&lt;\\\/td&gt;\\n&lt;\\\/tr&gt;\\n&lt;\\\/tbody&gt;\\n&lt;\\\/table&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Response example&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;raw\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;{YOUR_SCHEME}:\\\\\\\/\\\\\\\/your_company.example.com?response=PAYMENT_RESPONSE\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&lt;\\\/li&gt;\\n&lt;li&gt;\\n&lt;p&gt;Decrypt the Terminal API response using the security key.&lt;\\\/p&gt;\\n&lt;p&gt;The following example shows how you could do that using the Adyen Java library in a Kotlin project.&lt;\\\/p&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Decrypt using Java library&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;kotlin\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;private fun decryptNexoResponse(response: String): String {\\\\n        \\\\\\\/\\\\\\\/ Decode the Base64 URL-encoded response string to retrieve the original encrypted Terminal API response\\\\n        val decoded = String(Base64.getUrlDecoder().decode(response))\\\\n\\\\n        val securityKey = SecurityKey()\\\\n        securityKey.adyenCryptoVersion = 1\\\\n        securityKey.keyIdentifier = BuildConfig.KEY_IDENTIFIER\\\\n        securityKey.passphrase = BuildConfig.PASS_PHRASE\\\\n        securityKey.keyVersion = BuildConfig.VERSION\\\\n        val gson = TerminalAPIGsonBuilder.create()\\\\n        val data = gson.fromJson(decoded, TerminalAPISecuredResponse::class.java)\\\\n        return NexoCrypto(securityKey).decrypt(data.saleToPOIResponse)\\\\n    }\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&quot;,&quot;altTitle&quot;:&quot;full-response&quot;,&quot;oldTabId&quot;:&quot;full-response_1&quot;,&quot;relation&quot;:&quot;&quot;},{&quot;title&quot;:&quot;Receive short response in browser&quot;,&quot;content&quot;:&quot;\\n&lt;p&gt;&lt;a id=\\&quot;short-response\\&quot;&gt;&lt;\\\/a&gt; A web-based POS app requires a short payment response, because the full Terminal API response is too large for some browsers. The short response contains the result of the transaction, and a URL from which the full payment result can be retrieved.&lt;\\\/p&gt;\\n&lt;p&gt;The short payment response is an App Link you receive from the Payments app with the following parameters:&lt;\\\/p&gt;\\n&lt;table&gt;\\n&lt;thead&gt;\\n&lt;tr&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Parameter&lt;\\\/th&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Type&lt;\\\/th&gt;\\n&lt;th style=\\&quot;text-align: left;\\&quot;&gt;Description&lt;\\\/th&gt;\\n&lt;\\\/tr&gt;\\n&lt;\\\/thead&gt;\\n&lt;tbody&gt;\\n&lt;tr&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;&lt;code&gt;response&lt;\\\/code&gt;&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;String&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;Base64URL-encoded and encrypted short payment response object, containing:&lt;ul&gt;&lt;li markdown=\\&quot;1\\&quot;&gt;&lt;code&gt;result&lt;\\\/code&gt;: Possible values: &lt;span translate=\\&quot;no\\&quot;&gt;&lt;strong&gt;Success&lt;\\\/strong&gt;&lt;\\\/span&gt;, &lt;span translate=\\&quot;no\\&quot;&gt;&lt;strong&gt;Partial&lt;\\\/strong&gt;&lt;\\\/span&gt;, or &lt;span translate=\\&quot;no\\&quot;&gt;&lt;strong&gt;Failure&lt;\\\/strong&gt;&lt;\\\/span&gt;.&lt;\\\/li&gt;&lt;li markdown=\\&quot;1\\&quot;&gt;&lt;code&gt;url&lt;\\\/code&gt;: The URL to retrieve the full payment response from. When the transaction is cancelled, this field is returned empty.&lt;\\\/li&gt;&lt;li markdown=\\&quot;1\\&quot;&gt;&lt;code&gt;errorCondition&lt;\\\/code&gt;:  If &lt;code&gt;result&lt;\\\/code&gt; is &lt;span translate=\\&quot;no\\&quot;&gt;&lt;strong&gt;Failure&lt;\\\/strong&gt;&lt;\\\/span&gt; it contains the error reason.&lt;\\\/li&gt;&lt;li markdown=\\&quot;1\\&quot;&gt;&lt;code&gt;traceParent&lt;\\\/code&gt;: If result is &lt;span translate=\\&quot;no\\&quot;&gt;&lt;strong&gt;Failure&lt;\\\/strong&gt;&lt;\\\/span&gt; it contains the trace that can be shared with our Support team for troubleshooting if the error is unclear&lt;\\\/li&gt;&lt;\\\/ul&gt;&lt;\\\/td&gt;\\n&lt;\\\/tr&gt;\\n&lt;tr&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;&lt;code&gt;securityTrailer&lt;\\\/code&gt;&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;String&lt;\\\/td&gt;\\n&lt;td style=\\&quot;text-align: left;\\&quot;&gt;A Base64URL-encoded object containing information about the shared key used for the encryption. This information is needed to decode and decrypt the short response.&lt;\\\/td&gt;\\n&lt;\\\/tr&gt;\\n&lt;\\\/tbody&gt;\\n&lt;\\\/table&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Short response example&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;raw\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;{YOUR_SCHEME}:\\\\\\\/\\\\\\\/your_company.example.com?response=SHORT_PAYMENT_RESPONSE&amp;amp;securityTrailer=SECURITY_TRAILER\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&lt;\\\/li&gt;\\n&lt;li&gt;\\n&lt;p&gt;Decode the Base64URL from the &lt;code&gt;response&lt;\\\/code&gt; string. Note that the result is a Base64-encoded ciphertext.&lt;\\\/p&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Decode Base64URL from the response&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;kotlin\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;val decodedBase64 = String(Base64.getUrlDecoder().decode(responseFromDeeplink))\\\\n    decryptShortNexoResponse(securityTrailerModel, decoded)\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&lt;\\\/li&gt;\\n&lt;li&gt;\\n&lt;p&gt;Decrypt the Base64-encoded ciphertext. The following example shows how you can do that using the Adyen Java library in a Kotlin project.&lt;\\\/p&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Decrypt using Java library&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;kotlin\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;private fun decryptShortNexoResponse(securityTrailer: SecurityTrailer, nexoResponse: String): String {\\\\n         val securityKey = SecurityKey()\\\\n         securityKey.adyenCryptoVersion = 1\\\\n         securityKey.keyIdentifier = BuildConfig.KEY_IDENTIFIER\\\\n         securityKey.passphrase = BuildConfig.PASS_PHRASE\\\\n         securityKey.keyVersion = BuildConfig.VERSION\\\\n\\\\n         val nexoModel = com.adyen.terminal.security.SaleToPOISecuredMessage()\\\\n         nexoModel.nexoBlob = nexoResponse\\\\n         nexoModel.securityTrailer = com.adyen.model.terminal.security.SecurityTrailer().apply {\\\\n             hmac = Base64.getDecoder().decode(securityTrailer.hmac.toByteArray())\\\\n             nonce = Base64.getDecoder().decode(securityTrailer.nonce.toByteArray())\\\\n         }\\\\n         return NexoCrypto(securityKey).decrypt(nexoModel)\\\\n     }\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&lt;p&gt;Below is an example of a short response in plaintext that contains the result and the URL to call to receive the full response.&lt;\\\/p&gt;\\n&lt;div data-component-wrapper=\\&quot;code-sample\\&quot;&gt;\\n&lt;code-sample :title=\\&quot;&#039;Short response in plain text&#039;\\&quot; :id=\\&quot;&#039;&#039;\\&quot; :code-data=&#039;[{\\&quot;language\\&quot;:\\&quot;text\\&quot;,\\&quot;tabTitle\\&quot;:\\&quot;\\&quot;,\\&quot;content\\&quot;:\\&quot;result=Success&amp;amp;url=https:\\\\\\\/\\\\\\\/checkoutpos-live.adyen.com\\\\\\\/checkoutpos\\\\\\\/v1\\\\\\\/merchants\\\\\\\/{merchantId}\\\\\\\/paymentsApps\\\\\\\/{installationId}\\\\\\\/payments\\\\\\\/{pspReference}\\&quot;}]&#039; :enable-copy-link-to-code-block=\\&quot;true\\&quot; :code-sample-card-size=\\&quot;&#039;fullsize&#039;\\&quot;&gt;&lt;\\\/code-sample&gt;\\n&lt;\\\/div&gt;\\n&lt;\\\/li&gt;\\n&lt;li&gt;\\n&lt;p&gt;Optionally, make a GET request to the URL your received in the short response to receive the full &lt;a href=\\&quot;\\\/pt\\\/point-of-sale\\\/basic-tapi-integration\\\/make-a-payment\\\/#payment-response\\&quot;&gt;payment response&lt;\\\/a&gt;.&lt;\\\/p&gt;\\n&quot;,&quot;altTitle&quot;:&quot;short-response&quot;,&quot;oldTabId&quot;:&quot;short-response_2&quot;,&quot;relation&quot;:&quot;&quot;}]\"\n            :should-update-when-url-changes='true'>\n        <\/tabs>\n    <\/div>\n<\/div>\n\n<\/li>\n<\/ol>\n<h2 id=\"reboard-the-app\">Reboard the app<\/h2>\n<p>If you need to change the merchant account or store that you want to process payments for, you must reboard the app.<\/p>\n<p>As soon as you start the reboarding flow, the app loses the association with the merchant account or store that the app was previously boarded to. This means you cannot use the app\/mobile device combination for payments until the reboarding process is completed. If an error occurs during the reboarding, you need to start the reboarding flow again.<\/p>\n<p>Reboarding is a three-step process that is the same as the initial boarding process, except for the first step of initiating the reboarding.<\/p>\n<ol>\n<li>\n<p><a href=\"#initiate-reboarding\">Initiate reboarding<\/a>.<br \/>\nFrom your POS app, you call a link to force the app to start a new boarding process even though it is already boarded.<\/p>\n<\/li>\n<li>\n<p>Authenticate the app instance.<br \/>\nThis step is exactly the same <a href=\"#authenticate-app-instance\">as described under \"Board the app\"<\/a>.<\/p>\n<\/li>\n<li>\n<p>Finish boarding the app.<br \/>\nThis step is exactly the same <a href=\"#finish-boarding\">as described under \"Board the app\"<\/a>.<\/p>\n<\/li>\n<\/ol>\n<h3 id=\"initiate-reboarding\">Initiate reboarding<\/h3>\n<p>To start the reboarding flow, you call an App Link from your POS app to force the Adyen Payments app to start a new boarding process.<\/p>\n<ol>\n<li>\n<p>From your POS app, call the link. The App Link format is as follows:<br \/>\n<code>https:\/\/www.adyen.com\/test\/boarded?returnUrl=URLEncoder(your_scheme)&amp;reboard=true<\/code><\/p>\n<p>In this format:<\/p>\n<ul>\n<li><code>https:\/\/www.adyen.com\/test\/<\/code> is the test base URL.<\/li>\n<li><code>boarded<\/code> is the path to use for boarding checks.<\/li>\n<li><code>returnUrl<\/code> is the URL-encoded URL where you want to receive the response.<\/li>\n<li><code>reboard<\/code> is a Boolean parameter that must be set to <span translate=\"no\"><strong>true<\/strong><\/span> to start the reboarding process.<\/li>\n<\/ul>\n<p><\/p>\n<p>The following example shows how you could build the App Link in your Kotlin project.<\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Build an App Link to start reboarding'\" :id=\"''\" :code-data='[{\"language\":\"kotlin\",\"tabTitle\":\"\",\"content\":\"private fun createReboardingCheckApplink(\\n    returnUrl: String,\\n): Uri {\\n    \\\/\\\/ Encode the returnUrl to ensure it is safe for use as a URL query parameter.\\n    val returnUrlEncoded = URLEncoder.encode(returnUrl, Charsets.UTF_8.name())\\n    return Uri.parse(\\\"${BuildConfig.APP_LINK_URL}\\\/boarded\\\").buildUpon()\\n        .appendQueryParameter(\\\"returnUrl\\\", returnUrlEncoded)\\n        .appendQueryParameter(\\\"reboard\\\", \\\"true\\\") \\\/\\\/ Add this line for reboarding\\n        .build()\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<p><\/p>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'App Link example'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"https:\\\/\\\/www.adyen.com\\\/test\\\/boarded?returnUrl=your-scheme-test%3A%2F%2Fyour_company.example.com%2Fonboarding&amp;reboard=true\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>Check the response you receive at your <code>returnUrl<\/code>, and Base64-decode the <code>data<\/code> string.<\/p>\n<p>The response consists of the URL-encoded base URL where you want to receive the response and the following parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameter<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Type<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>boarded<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">Boolean<\/td>\n<td style=\"text-align: left;\">Indicates if the app was previously boarded. If the app was not previously boarded, the value is <span translate=\"no\"><strong>false<\/strong><\/span> and the reboarding process will serve to board the app.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>installationId<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The unique identifier of the Payments app instance on the specific device. <div class=\"sc-notice info\"><div> When creating Terminal API requests on your back-end, use this as the <code>POIID<\/code> in the <code>MessageHeader<\/code> of the request.<\/div><\/div><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>boardingRequestToken<\/code><\/td>\n<td style=\"text-align: center;\"><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The app token used to get the <code>boardingToken<\/code> from Adyen.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>data<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">A Base64-encoded JSON object with details of the previous boarding.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When you Base64-decode the <code>data<\/code> string, this results in a JSON object with the following parameters:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameter<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Type<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>date<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">Timestamp indicating when the reboarding started, in ISO-8601 UTC format. Example: <span translate=\"no\"><strong>2025-11-10T17:34:48.123Z<\/strong><\/span><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>reboarding<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">Indicates that this is a reboarding flow. Will be <span translate=\"no\"><strong>true<\/strong><\/span>.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>merchantAccountCode<\/code><\/td>\n<td style=\"text-align: center;\"><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The merchant account that the app was <em>previously<\/em> boarded to. Will be <span translate=\"no\"><strong>null<\/strong><\/span> if the app was not previously boarded.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>merchantStoreCode<\/code><\/td>\n<td style=\"text-align: center;\"><\/td>\n<td style=\"text-align: left;\">String<\/td>\n<td style=\"text-align: left;\">The ID of the store that the app was <em>previously<\/em> boarded to. Will be <span translate=\"no\"><strong>null<\/strong><\/span> if the app was not previously boarded.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Example response after initiating reboarding'\" :id=\"''\" :code-data='[{\"language\":\"text\",\"tabTitle\":\"\",\"content\":\"{YOUR_SCHEME}%3A%2F%2Fyour_company.example.com%2Fonboarding?boarded=false&amp;installationId=&lt;INSTALLATION_ID&gt;&amp;boardingRequestToken=&lt;BOARDING_REQUEST_TOKEN&gt;&amp;data=&lt;BASE64_ENCODED_DATA&gt;\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>Continue with the steps to authenticate and finish boarding the app. For instructions, see:<\/p>\n<ul>\n<li><a href=\"#authenticate-app-instance\">Authenticate the app instance<\/a>.<\/li>\n<li><a href=\"#finish-boarding\">Finish boarding the app<\/a>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2 id=\"revoke-app-instance\">Revoke app instance<\/h2>\n<p>If your Android mobile device is defective, stolen, or you do not need it anymore for payments processing, you must stop the Payments app from processing transactions with Adyen. To do this, you make an API call to Adyen to revoke the specified <code>installationId<\/code>.<\/p>\n<p>To revoke a boarding token:<\/p>\n<ol>\n<li>\n<p>Optionally, make either a GET  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/get\/merchants\/(merchantId)\/paymentsApps\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">\/merchants\/merchantId\/paymentsApps<\/a> or  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/get\/merchants\/(merchantId)\/stores\/(storeId)\/paymentsApps\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">\/merchants\/merchantId\/stores\/storeId\/paymentsApps<\/a> request to retrieve the list of Payments app instances for a merchant account or a store. You can then use the <code>installationId<\/code> to revoke boarding tokens.<\/p>\n<\/li>\n<li>\n<p>Make a POST  <a href=\"https:\/\/docs.adyen.com\/api-explorer\/payments-app\/latest\/post\/merchants\/(merchantId)\/paymentsApps\/(installationId)\/revoke\" class=\"codeLabel  external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">\/merchants\/merchantId\/paymentsApps\/installationId\/revoke<\/a> request specifying:<\/p>\n<ul>\n<li>As path parameters:<\/li>\n<\/ul>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">Parameters<\/th>\n<th style=\"text-align: center;\">Required<\/th>\n<th style=\"text-align: left;\">Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\"><code>installationId<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">The unique identifier of the Payments app instance on the specific device.<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\"><code>merchantId<\/code><\/td>\n<td style=\"text-align: center;\"><img title=\"-white_check_mark-\" alt=\"-white_check_mark-\" class=\"smileys\" src=\"\/user\/data\/smileys\/emoji\/white_check_mark.png\" \/><\/td>\n<td style=\"text-align: left;\">The unique identifier of the merchant account.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div data-component-wrapper=\"code-sample\">\n<code-sample :title=\"'Revoke Payments app instance authentication'\" :id=\"''\" :code-data=\"[{&quot;language&quot;:&quot;curl&quot;,&quot;tabTitle&quot;:&quot;&quot;,&quot;content&quot;:&quot;curl https:\\\/\\\/management-test.adyen.com\\\/v1\\\/merchants\\\/{merchantId}\\\/paymentsApps\\\/{installationId}\\\/revoke \\\\\\n  -H 'x-API-key: ADYEN_API_KEY' \\\\\\n  -H 'content-type: application\\\/json' \\\\\\n  -X POST \\\\&quot;}]\" :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<\/li>\n<li>\n<p>If successful, the response returns <span translate=\"no\"><strong>200 OK<\/strong><\/span>.<\/p>\n<\/li>\n<li>\n<p>In the Payments app, go to <strong>Settings<\/strong> and select <strong>Unregister<\/strong> to revoke the app from the UI of your mobile device.<\/p>\n<\/li>\n<\/ol>\n<h2>Test your solution<\/h2>\n<p>To make test transactions:<\/p>\n<ol>\n<li>\n<p>Make sure you are using the test version of the Payments app.  <\/p>\n<\/li>\n<li>\n<p>Initiate a test transaction using the following Adyen point-of-sale test cards to complete the payment:<\/p>\n<ul>\n<li><a href=\"\/pt\/point-of-sale\/testing-pos-payments\/test-card-v3\/\">White-green test card<\/a><\/li>\n<li><a href=\"\/pt\/point-of-sale\/testing-pos-payments\/test-card-v2\/\">Blue-green test card<\/a> version <strong>2.4<\/strong> or later<\/li>\n<\/ul>\n<p>The instructions are the same for both cards; see either of the pages mentioned above.<\/p>\n<\/li>\n<\/ol>\n<h2>Go live<\/h2>\n<p>When you have finished testing your integration and are ready to go live:<\/p>\n<ol>\n<li>If new to Adyen, get a <a href=\"\/pt\/get-started-with-adyen\/#apply-for-your-live-account\">live account<\/a>. You need to have access to your organization's live Customer Area to generate an API credentials for the live environment.<\/li>\n<li>In your <a href=\"https:\/\/ca-live.adyen.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">live Customer Area<\/a> generate a new API key with the <strong>Adyen Payments app role<\/strong> for use with the Adyen Payments app.<\/li>\n<li>Download the <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.adyen.ipp.mobile.companion.live\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Adyen Payments<\/a> app from the Google Play store.<\/li>\n<li>Contact us to enable Tap to Pay on Android, and optionally also enable unreferenced refunds.<\/li>\n<li>Update your code to use the live URLs for App Links:\n<ul>\n<li><code>https:\/\/www.adyen.com\/boarded<\/code><\/li>\n<li><code>https:\/\/www.adyen.com\/board<\/code><\/li>\n<li><code>https:\/\/www.adyen.com\/nexo<\/code><\/li>\n<\/ul><\/li>\n<li>Update your code to use the live Management API endpoints:\n<ul>\n<li><code>https:\/\/management-live.adyen.com<\/code><\/li>\n<\/ul><\/li>\n<\/ol>\n<h2>Verify app instance<\/h2>\n<p>Adyen continuously checks if the app instance on your Android mobile device is authentic. This is to protect your integration against <a href=\"https:\/\/en.wikipedia.org\/wiki\/Man-in-the-middle_attack\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">man-in-the-middle<\/a> attacks, eavesdropping, and tampering. You can also check this yourself manually using a different device and your email address.<\/p>\n<p>To verify the app instance, in the Payments app:<\/p>\n<ol>\n<li>Go to <strong>Settings<\/strong> and tap <strong>Verify app<\/strong>.<\/li>\n<li>Enter your email address and tap <strong>Send email<\/strong>.<\/li>\n<li>Check your email on another device. You should have received an email with a 5-character code.<\/li>\n<li>In the Payments app, if you received the email, tap <strong>Continue<\/strong>. If you did not receive the email, check the email address you entered, and tap <strong>Resend email<\/strong> and go back to step 2.<\/li>\n<li>Under <strong>Verify app<\/strong>, check that the 5-character code on the screen matches the code you received in the email.<\/li>\n<\/ol>\n<p>If the app instance verification is successful, you can continue making payments with the Payments app. If the verification fails, Adyen automatically revokes the app instance. In this case, you need to <a href=\"#board-the-app\">board the app again<\/a> on that Android mobile device.<\/p>\n<h2>Next steps<\/h2>\n<div class=\"next-steps\" id=\"next-steps\" >\n<a href=\"\/point-of-sale\/mobile-android\/manage\" class=\"next-steps__step\" style=\"width:29%;\" target=\"_self\"><div class=\"next-steps__label\">required<\/div><p class=\"next-steps__body\"><div style=\"text-align: center;\"><img src=\"\/user\/themes\/adyen\/images\/illustrations\/settings.svg\"><h6 class=\"next-steps__title\">Manage your solution<\/h6><p>Make your solution available and keep the software up-to-date.<\/p><\/div><\/p><\/a><a href=\"\/point-of-sale\/mobile-android\/checklists\" class=\"next-steps__step\" style=\"width:29%;\" target=\"_self\"><p class=\"next-steps__body\"><div style=\"text-align: center;\"><img src=\"\/user\/themes\/adyen\/images\/illustrations\/checkmark.svg\"><h6 class=\"next-steps__title\">Checklists<\/h6><p>Get a list of what needs to be done to get started and go live with a Mobile solution.<\/p><\/div><\/p><\/a><a href=\"\/point-of-sale\/mobile-android\/troubleshooting\" class=\"next-steps__step\" style=\"width:29%;\" target=\"_self\"><p class=\"next-steps__body\"><div style=\"text-align: center;\"><img src=\"\/user\/themes\/adyen\/images\/illustrations\/close.svg\"><h6 class=\"next-steps__title\">Error handling<\/h6><p>Resolve errors that appear on the mobile Android device.<\/p><\/div><\/p><\/a><\/div>\n","url":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/mobile-android\/build\/payments-app","articleFields":{"description":"Use our Payments app to enable Tap to Pay on your Android mobile devices without integrating our POS Mobile SDK.","type":"page","parameters":{"solution":"pappAndroid","solution_name":"Android Payments app","platform":"Android","generic_sdk_name":"Payments app"},"_expandable":{"operations":""},"status":"current","feedback_component":true,"filters_component":false,"decision_tree":"[]","page_id":"bada878b-efa5-479e-a303-f3f68c0e69f5","last_edit_on":"12-03-2026 10:58"},"algolia":{"url":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/mobile-android\/build\/payments-app","title":"Android Payments app","content":"If you want to accept Tap to Pay payments on your Android mobile device but do not want to integrate our POS Mobile SDK, you can download the Adyen Payments app from the Google Play store. You can then use the Payments app to connect your own POS app to the plataforma de pagamentos da Adyen and authenticate payment requests in a compliant way.\nThis page explains how to build the Payments app solution. Before you begin, see Understand the solutions to help you decide if the Payments app is the right solution for your situation.\nRequirements\nBefore you begin, take into account the following requirements, limitations, and preparations.\n\n\n\nRequirement\nDescription\n\n\n\n\nIntegration type\nYour POS app must be integrated with Terminal API. The POS app can be installed on your mobile device or browser-based.\n\n\nAPI credentials\nAn API key specifically for the Adyen Payments app, with a client key and the Adyen Payments app role.\n\n\nHardware\nAn Android commercial off-the-shelf (COTS) mobile device with an integrated NFC reader. Must not be a payment terminal. See Android system requirements for the full hardware and software requirements.\n\n\nLimitations\nTake into account the following limitations: See the countries\/regions, payment methods, and functionality that we support. Web-based POS apps are currently only supported in the US, the EU, and Australia.\n\n\nSetup steps\nBefore you begin: Contact our Support Team to enable Tap to Pay on Android and to enable the Adyen Payments app role for your API key. Optionally also ask them to enable unreferenced refunds. Download the Adyen Payments Test app from the Google Play store. For testing, in your Customer Area order a White-green Adyen test card. Or you can use a Blue-green test card v2.4 or later, if you already have that.If your POS app is web-based: Contact our Support Team to enable receiving a short response in the browser. Configure your web server to use HTTPS and enforce a minimum security protocol of TLS 1.2 or higher\n\n\n\nHow it works\nWhen building the various flows, you will use Android App Links to call specific parts of the Android Payments app. To build an Android Payments app solution for Tap to Pay:\n\nBuild the boarding flow. The Payments app must be boarded on every Android mobile device where the app is installed.\nBuild the payment flow.\n\nIn addition, do the following:\n\nBuild the reboarding flow. Reboarding enables you to switch to processing though a different store or merchant account using the same app instance and mobile device.\nImplement an API request to revoke an app instance for cases when the mobile device is defective, stolen, or no longer needed for payments.\n\n1. Board the app\nAfter you download the Payments app from the Google Play store to a mobile device, you need to board the Payments app on that device. Boarding is a three-step process:\n\n\nCheck the boarding status.\nFrom your POS app, you call a link to check if the Payments app is boarded. If the Payments app is not boarded, you receive a \"boarding request token\".\n\n\nAuthenticate the app instance.\nFrom your back-end, you send an API request that includes the boarding request token. In the response, you receive a one-time boarding token that is unique for the combination of Payments app instance and device.\n\n\nFinish boarding the app.\nFrom your POS app, you call a link that includes the boarding token. The response confirms that the Payments app is now boarded, and includes an installation ID that you need to pass in your transaction requests.\n\n\n1.1 Check the boarding status\nTo start the boarding flow, you call an App Link from your POS app to check if the Adyen Payments app is already boarded.\n\n\nFrom your POS app, call the link. The App Link format is as follows:\nhttps:\/\/www.adyen.com\/test\/boarded?returnUrl=URLEncoder(your_scheme)\nIn this format:\n\nhttps:\/\/www.adyen.com\/test\/ is the test base URL.\nboarded is the path to use for boarding checks.\nreturnUrl is the URL-encoded URL where you want to receive the response.\n\n\nThe following example shows how you could build the App Link in your Kotlin project.\n\n\n\n\n\n\n\n\n\nCheck the response you receive at your returnUrl and decide what to do next:\n\nIf boarded is true: save the installationId, which you will need in your payment requests. You do not need to continue with the boarding process and you are ready to make a payment.\nIf boarded is false: pass the installationId and boardingRequestToken to your back-end and go to step 2 of the boarding process.\n\nThe response consists of the URL-encoded base URL where you want to receive the response and the following parameters:\n\n\n\nParameter\nRequired\nType\nDescription\n\n\n\n\nboarded\n\nBoolean\nIndicates if the app is boarded or not.\n\n\ninstallationId\n\nString\nThe unique identifier of the Payments app instance on the specific device.  When creating Terminal API requests on your back-end, use this as the POIID in the MessageHeader of the request.\n\n\nboardingRequestToken\n\nString\nThe app token used to get the boardingToken from Adyen.\n\n\n\n\n\n    \n        \n        \n    \n\n\n\n\n1.2. Authenticate the app instance\nIf you determined in step 1 of the boarding process that the Payments app is not boarded yet or if you initiated reboarding, you send a  Payments app API request from your back-end to authenticate your app installation. In the response you receive a boardingToken.\nTo authenticate the app:\n\n\nMake a POST request to the endpoint corresponding to where you want to accept payments:\n\nTo route transactions over a merchant account, use  \/merchants\/merchantId\/generatePaymentsAppBoardingToken.\nTo route transactions over a store, use  \/merchants\/merchantId\/stores\/storeId\/generatePaymentsAppBoardingToken.\n\n\nThe app will be configured to the merchant account or store specified in the path, and route all transactions over that merchant account or store. Ensure this aligns with your account structure.\n\nSpecify the following in the request:\n\n\nPath parameters:\n\n\n\nParameters\nRequired\nDescription\n\n\n\n\nmerchantId\n\nThe unique identifier of the merchant account.\n\n\nstoreId\n\nThe unique identifier of the store.  The storeId is not the same as store reference. If you only know the reference, you can use it to get the storeId with an API call. \n\n\n\n\n\nRequest parameters:\n\n\n\nParameters\nRequired\nDescription\n\n\n\n\nboardingRequestToken\n\nThe app token used to request a boardingToken from Adyen. You received the boarding request token in step 1 of the boarding process.\n\n\n\n\n\n\n\n\n\n\nFrom the response, save the boardingToken, which you will need in the last step of the boarding process.\nThe response consists of the following parameters:\n\n\n\nParameter\nType\nDescription\n\n\n\n\ninstallationId\nString\nThe unique identifier of the Payments app instance on the specific device.\n\n\nboardingToken\nString\nThe one-time token used to authenticate the app installation. Valid for one hour.\n\n\n\n\n\n\n\n\n1.3. Finish boarding the app\nWhen you have received the boardingToken from Adyen, you need to send the boarding token to the Payments app to finish boarding the app and prepare for making payments.\n\n\nFrom your POS app, call the link. The App Link format is as follows:\nhttps:\/\/www.adyen.com\/test\/board?boardingToken=Base64URL{APP_BOARDING_TOKEN}&amp;returnUrl=URLEncoder(your_scheme)\nIn this format:\n\nhttps:\/\/www.adyen.com\/test\/ is the test base URL.\nboard is the path to use for boarding requests.\nboardingToken is the token generated for this installationId in step 2 of the boarding process. This token must be Base64URL-encoded.\nreturnUrl is the URL-encoded URL where you want to receive the onboarding result (the response).\n\n\nThe following example shows how you could build the App Link in your Kotlin project.\n\n\n\n\n\n\n\n\n\nCheck the response and decide what to do next:\n\nIf boarded is true: save the installationId. You need this when you make a payment. You do not need board the app again.\nIf boarded is false: check the error and try again.\n\nThe response consist of the URL-encoded base URL where you want to receive the response and the following parameters:\n\n\n\nParameter\nType\nDescription\n\n\n\n\nboarded\nBoolean\nIndicates if the app is boarded or not.\n\n\ninstallationId\nString\nThe unique identifier of the Payments app instance on the specific device.  When creating Terminal API requests on your back-end, use this as the POIID in the MessageHeader of the request.\n\n\nerror\nString\nAdditional information in case an error occurred and boarded is false.\n\n\n\n\n\n\n\n\n2. Make a transaction\nAfter the Payments app is boarded, you are ready to make transactions. To do this, you need to create a Terminal API request in Base64URL format and call the request as an App Link from your POS app. The boarded Payments app then communicates with Adyen, receives the response, and returns the response in Base64 format as part of an App Link to your POS app.\nTo start a transaction from your POS app:\n\n\nCreate a Terminal API request with the POIID value set to the installationId value of the boarded Payments app.\n\nFor a payment, partial payment, pre-authorization, or unreferenced refund, create a  PaymentRequest.\nFor a referenced refund, create a  ReversalRequest.\n\n\n\nEncrypt the Terminal API request as described for a Terminal API integration with local communications.\n\nSet up a shared key in your Customer Area or using Management API.\n\nEither write your own code to encrypt and decrypt Terminal API messages, or use a library.\nThe following example shows how you could encrypt Terminal API requests using the Java library in a Kotlin project. We also have a .NET library and a Node library.\n\n\n\n\n\n\n\nEncode the Terminal API request to Base64URL.\n\n\nFrom your POS app, call the link. The App Link format is as follows:\nhttps:\/\/www.adyen.com\/test\/nexo?request=NexoRequest.Base64Url{Encryption{NexoRequest}}&amp;returnUrl=URLEncoder(your_scheme)\nIn this format:\n\nhttps:\/\/www.adyen.com\/test\/ is the test base URL.\nnexo is the path to use for transactions.\nrequest is the Base64URL-encoded and encrypted Terminal API payment request.\nreturnUrl is the URL-encoded URL where you want to receive the Terminal API response.\n\n\nThe following example shows how you could build the App Link in your Kotlin project.\n\n\n\n\n\n\n\nA Tap to Pay screen appears on the mobile device.\n\nIf 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.\n\n\n\nUse the response to show the payment result in your POS app. Select the tab Receive full response if your POS app is installed on your mobile device. Select the tab Receive short response in browser if you are using a browser-based POS app.\n\n\n    \n        \n        \n    \n\n\n\n\nReboard the app\nIf you need to change the merchant account or store that you want to process payments for, you must reboard the app.\nAs soon as you start the reboarding flow, the app loses the association with the merchant account or store that the app was previously boarded to. This means you cannot use the app\/mobile device combination for payments until the reboarding process is completed. If an error occurs during the reboarding, you need to start the reboarding flow again.\nReboarding is a three-step process that is the same as the initial boarding process, except for the first step of initiating the reboarding.\n\n\nInitiate reboarding.\nFrom your POS app, you call a link to force the app to start a new boarding process even though it is already boarded.\n\n\nAuthenticate the app instance.\nThis step is exactly the same as described under \"Board the app\".\n\n\nFinish boarding the app.\nThis step is exactly the same as described under \"Board the app\".\n\n\nInitiate reboarding\nTo start the reboarding flow, you call an App Link from your POS app to force the Adyen Payments app to start a new boarding process.\n\n\nFrom your POS app, call the link. The App Link format is as follows:\nhttps:\/\/www.adyen.com\/test\/boarded?returnUrl=URLEncoder(your_scheme)&amp;reboard=true\nIn this format:\n\nhttps:\/\/www.adyen.com\/test\/ is the test base URL.\nboarded is the path to use for boarding checks.\nreturnUrl is the URL-encoded URL where you want to receive the response.\nreboard is a Boolean parameter that must be set to true to start the reboarding process.\n\n\nThe following example shows how you could build the App Link in your Kotlin project.\n\n\n\n\n\n\n\n\n\nCheck the response you receive at your returnUrl, and Base64-decode the data string.\nThe response consists of the URL-encoded base URL where you want to receive the response and the following parameters:\n\n\n\nParameter\nRequired\nType\nDescription\n\n\n\n\nboarded\n\nBoolean\nIndicates if the app was previously boarded. If the app was not previously boarded, the value is false and the reboarding process will serve to board the app.\n\n\ninstallationId\n\nString\nThe unique identifier of the Payments app instance on the specific device.  When creating Terminal API requests on your back-end, use this as the POIID in the MessageHeader of the request.\n\n\nboardingRequestToken\n\nString\nThe app token used to get the boardingToken from Adyen.\n\n\ndata\n\nString\nA Base64-encoded JSON object with details of the previous boarding.\n\n\n\nWhen you Base64-decode the data string, this results in a JSON object with the following parameters:\n\n\n\nParameter\nRequired\nType\nDescription\n\n\n\n\ndate\n\nString\nTimestamp indicating when the reboarding started, in ISO-8601 UTC format. Example: 2025-11-10T17:34:48.123Z\n\n\nreboarding\n\nString\nIndicates that this is a reboarding flow. Will be true.\n\n\nmerchantAccountCode\n\nString\nThe merchant account that the app was previously boarded to. Will be null if the app was not previously boarded.\n\n\nmerchantStoreCode\n\nString\nThe ID of the store that the app was previously boarded to. Will be null if the app was not previously boarded.\n\n\n\n\n\n\n\n\nContinue with the steps to authenticate and finish boarding the app. For instructions, see:\n\nAuthenticate the app instance.\nFinish boarding the app.\n\n\n\nRevoke app instance\nIf your Android mobile device is defective, stolen, or you do not need it anymore for payments processing, you must stop the Payments app from processing transactions with Adyen. To do this, you make an API call to Adyen to revoke the specified installationId.\nTo revoke a boarding token:\n\n\nOptionally, make either a GET  \/merchants\/merchantId\/paymentsApps or  \/merchants\/merchantId\/stores\/storeId\/paymentsApps request to retrieve the list of Payments app instances for a merchant account or a store. You can then use the installationId to revoke boarding tokens.\n\n\nMake a POST  \/merchants\/merchantId\/paymentsApps\/installationId\/revoke request specifying:\n\nAs path parameters:\n\n\n\n\nParameters\nRequired\nDescription\n\n\n\n\ninstallationId\n\nThe unique identifier of the Payments app instance on the specific device.\n\n\nmerchantId\n\nThe unique identifier of the merchant account.\n\n\n\n\n\n\n\n\nIf successful, the response returns 200 OK.\n\n\nIn the Payments app, go to Settings and select Unregister to revoke the app from the UI of your mobile device.\n\n\nTest your solution\nTo make test transactions:\n\n\nMake sure you are using the test version of the Payments app.  \n\n\nInitiate a test transaction using the following Adyen point-of-sale test cards to complete the payment:\n\nWhite-green test card\nBlue-green test card version 2.4 or later\n\nThe instructions are the same for both cards; see either of the pages mentioned above.\n\n\nGo live\nWhen you have finished testing your integration and are ready to go live:\n\nIf new to Adyen, get a live account. You need to have access to your organization's live Customer Area to generate an API credentials for the live environment.\nIn your live Customer Area generate a new API key with the Adyen Payments app role for use with the Adyen Payments app.\nDownload the Adyen Payments app from the Google Play store.\nContact us to enable Tap to Pay on Android, and optionally also enable unreferenced refunds.\nUpdate your code to use the live URLs for App Links:\n\nhttps:\/\/www.adyen.com\/boarded\nhttps:\/\/www.adyen.com\/board\nhttps:\/\/www.adyen.com\/nexo\n\nUpdate your code to use the live Management API endpoints:\n\nhttps:\/\/management-live.adyen.com\n\n\nVerify app instance\nAdyen continuously checks if the app instance on your Android mobile device is authentic. This is to protect your integration against man-in-the-middle attacks, eavesdropping, and tampering. You can also check this yourself manually using a different device and your email address.\nTo verify the app instance, in the Payments app:\n\nGo to Settings and tap Verify app.\nEnter your email address and tap Send email.\nCheck your email on another device. You should have received an email with a 5-character code.\nIn the Payments app, if you received the email, tap Continue. If you did not receive the email, check the email address you entered, and tap Resend email and go back to step 2.\nUnder Verify app, check that the 5-character code on the screen matches the code you received in the email.\n\nIf the app instance verification is successful, you can continue making payments with the Payments app. If the verification fails, Adyen automatically revokes the app instance. In this case, you need to board the app again on that Android mobile device.\nNext steps\n\nrequiredManage your solutionMake your solution available and keep the software up-to-date.ChecklistsGet a list of what needs to be done to get started and go live with a Mobile solution.Error handlingResolve errors that appear on the mobile Android device.\n","type":"page","locale":"pt","boost":16,"hierarchy":{"lvl0":"Home","lvl1":"Terminais","lvl2":"Android Mobile solutions","lvl3":"Build your Android Mobile solution","lvl4":"Android Payments app"},"hierarchy_url":{"lvl0":"https:\/\/docs.adyen.com\/pt","lvl1":"https:\/\/docs.adyen.com\/pt\/point-of-sale","lvl2":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/mobile-android","lvl3":"https:\/\/docs.adyen.com\/pt\/point-of-sale\/mobile-android\/build","lvl4":"\/pt\/point-of-sale\/mobile-android\/build\/payments-app"},"levels":5,"category":"In-person payments","category_color":"green","tags":["Android","Payments"]}}
