# Android SDK (/it/in-store/integration/android_sdk)



The Accept SDK turns an Android device into a card terminal. Use it from your Android app to sign in a merchant,
take card payments, refund them, and read NFC tags. This page lists every API with an example. For a guided setup,
start with [Mobile SDK Integration](/in-store/integration/sdk_integration).

| Detail           | Value                                                                                                                 |
| ---------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Package**      | `com.tapaya:accept` on [Maven Central](https://central.sonatype.com/artifact/com.tapaya/accept)                       |
| **Language**     | Kotlin. Most calls are `suspend` functions; call them from a coroutine.                                               |
| **Payment app**  | Every card payment runs in the Tapaya Terminal app. See [Terminal app](#terminal-app).                                |
| **NFC tags**     | Optional `com.tapaya:accept-nfc`, plus `accept-nfc-sunmi` for Sunmi P-series terminals                                |
| **React Native** | `@tapayadot/accept-react-native` wraps this SDK. See [Mobile SDK Integration](/in-store/integration/sdk_integration). |

## Install and initialize [#install-and-initialize]

```kotlin title="build.gradle.kts"
dependencies {
    implementation("com.tapaya:accept:$acceptVersion")
}
```

```kotlin title="App.kt"
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Accept.initialize(context = this, isProduction = !BuildConfig.DEBUG)
    }
}
```

Set `acceptVersion` to the latest release on Maven Central. Keep every Accept artifact on the same version.

## All APIs [#all-apis]

| API                                                                                 | Use it to                                                              |
| ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [`Accept.initialize()`](#initialize-the-sdk)                                        | Start the SDK once, when your app starts.                              |
| [`Accept.auth.authenticate()`](#sign-in-a-merchant)                                 | Sign in a merchant with a token from your backend.                     |
| [`Accept.state`](#watch-the-sdk-state)                                              | React when the SDK is ready.                                           |
| [`Accept.clear()`](#sign-out)                                                       | Sign out and clear everything the SDK stored.                          |
| [`Accept.setDebugLoggingEnabled()`](#turn-on-debug-logs)                            | See detailed logs while you develop.                                   |
| [`Accept.payments.pay()`](#take-a-payment)                                          | Take a card payment.                                                   |
| [`Accept.payments.setOptions()`](#set-payment-defaults)                             | Set the receipt, timeout, tap animation, and screen for every payment. |
| [`Accept.payments.status()`](#get-a-payment)                                        | Read a payment's state, amounts, and receipt link.                     |
| [`Accept.payments.cancel()`](#cancel-a-payment)                                     | Stop a payment that is still running.                                  |
| [`Accept.payments.refund()`](#refund-a-payment)                                     | Give the money back for a completed payment.                           |
| [`Accept.plugin.isInstalled()`, `install()`](#install-the-terminal-app)             | Check for the Tapaya Terminal app and open its store page.             |
| [`Accept.plugin.activateTerminal()`](#activate-the-terminal)                        | Link this device to the merchant, once per device.                     |
| [`Accept.plugin.status()`](#check-the-terminal-app)                                 | Check whether the terminal is ready for payments.                      |
| [`Accept.plugin.updateInfo()`](#check-for-an-update)                                | Find out whether the terminal app needs an update.                     |
| [`Accept.plugin.logout()`](#sign-out-of-the-terminal-app)                           | Sign the merchant out of the terminal app.                             |
| [`Accept.merchant.info()`](#get-the-merchant-profile)                               | Read the merchant's business details.                                  |
| [`Accept.merchant.config()`, `availableCurrencies()`](#get-the-merchant-currencies) | Find the currencies the merchant can accept.                           |
| [`Accept.merchant.onboardingStatus()`](#check-onboarding)                           | Check whether the merchant may take payments yet.                      |
| [`Accept.sdk`](#get-sdk-and-device-details)                                         | Read the environment, device ID, and minimum amounts.                  |
| [`Accept.displays`](#use-a-customer-screen)                                         | Find a customer-facing screen on two-screen terminals.                 |
| [`Accept.nfc.isSupported()`](#check-nfc-support)                                    | Check whether this device can read NFC tags.                           |
| [`Accept.nfc.openSession()`](#read-a-tag)                                           | Wait for a tag tap and start talking to it.                            |
| [Tag session commands](#tag-commands)                                               | Read and write NTAG, MIFARE Classic, and smart cards.                  |
| [`session.close()`, `session.ended`](#end-a-tag-session)                            | Free the reader, and learn why a session ended.                        |

Amounts are whole numbers in the currency's minor unit: `1500` with `CZK` is 15.00 Kč.

## Setup and sign-in [#setup-and-sign-in]

Start the SDK, sign in a merchant, and sign out again.

<Accordions type="multiple">
  <Accordion title="Initialize the SDK" id="initialize-the-sdk">
    **Use it to** start the SDK. Call it once, in your `Application` class.

    ```kotlin
    Accept.initialize(context = this, isProduction = !BuildConfig.DEBUG)
    ```

    **Good to know:**

    * Sandbox is the default. Pass `isProduction = true` for real payments.
    * Every other API throws `NotInitialized` until you call this.
  </Accordion>

  <Accordion title="Sign in a merchant" id="sign-in-a-merchant">
    **Use it to** sign in a merchant with a token your backend creates.

    ```kotlin
    try {
        val sdkToken = myBackendApi.getSdkToken()
        Accept.auth.authenticate(sdkToken)
    } catch (e: AcceptException) {
        showError(e)
    }
    ```

    **Good to know:**

    * Get the token from your backend. Never build it in the app.
    * After a `SessionExpired` error, call it again with a fresh token.
    * It also warms up the terminal, so the first payment starts faster.
  </Accordion>

  <Accordion title="Watch the SDK state" id="watch-the-sdk-state">
    **Use it to** show the payment screen only when the SDK is ready.

    ```kotlin
    Accept.state.collect { state ->
        if (state == SdkState.Authenticated) showPaymentScreen()
    }
    ```

    **Good to know:**

    * `Accept.state` is a `StateFlow<SdkState>`.
    * It moves from idle, to initialized, to authenticated.
  </Accordion>

  <Accordion title="Sign out" id="sign-out">
    **Use it to** sign the merchant out when they log out of your app.

    ```kotlin
    Accept.plugin.logout() // signs out of the Tapaya Terminal app
    Accept.clear()         // clears the SDK's stored token, device ID, and settings
    ```

    **Good to know:**

    * `clear()` returns the SDK to idle. Sign in again before the next payment.
    * Call `plugin.logout()` first if the terminal app should sign out too.
  </Accordion>

  <Accordion title="Turn on debug logs" id="turn-on-debug-logs">
    **Use it to** see what the SDK is doing while you develop.

    ```kotlin
    Accept.setDebugLoggingEnabled(BuildConfig.DEBUG)
    ```

    **Good to know:**

    * Turn it off in release builds.
  </Accordion>
</Accordions>

## Payments [#payments]

Take card payments, then read, cancel, or refund them. See [Card Terminal](/in-store/integration/card_terminal)
for the full flow.

<Accordions type="multiple">
  <Accordion title="Take a payment" id="take-a-payment">
    **Use it to** charge a card. The Tapaya Terminal app opens, the customer taps their card, and your app gets the
    result.

    ```kotlin
    Accept.payments.pay(amount = 1500, currency = "CZK")
        .collect { event ->
            when (event) {
                PaymentEvent.Creating -> showStatus("Creating payment…")
                is PaymentEvent.Created -> saveToken(event.paymentToken)
                PaymentEvent.Launched -> showStatus("Waiting for the card…")
                is PaymentEvent.Result -> showResult(event.payResult)
                is PaymentEvent.CreationFailed -> showError(event.cause)
            }
        }
    ```

    **Good to know:**

    * `pay()` never throws. Problems arrive as a `CreationFailed` event.
    * A declined or cancelled card is a `Result`, not an error.
    * Your app needs location permission (`ACCESS_FINE_LOCATION`) before you call it.
    * Only one payment can run at a time.

    **Parameters:**

    | Parameter                                                       | Description                                                                           |
    | --------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
    | `amount`                                                        | Required. Amount in minor units.                                                      |
    | `currency`                                                      | Required. Three-letter code, such as `CZK`. Must be one of the merchant's currencies. |
    | `tip`                                                           | A fixed tip, added to `amount`. Without it, the terminal asks the customer.           |
    | `metadata`                                                      | Your own key-value data, such as an order ID. Returned on the result when available.  |
    | `paymentToken`                                                  | Resume an interrupted payment instead of starting a new one.                          |
    | `receiptConfig`, `nfcPosition`, `transactionTimeout`, `display` | Override the [payment defaults](#set-payment-defaults) for this payment only.         |

    **Result:** `event.payResult` is one of:

    | `PayResult` | Meaning                                                         |
    | ----------- | --------------------------------------------------------------- |
    | `Success`   | Paid. Carries `paymentToken`, `authCode`, and `receiptDetails`. |
    | `Declined`  | The bank declined the card.                                     |
    | `Canceled`  | The customer or merchant cancelled.                             |
    | `Failed`    | The payment did not run. `reason` says why.                     |
  </Accordion>

  <Accordion title="Set payment defaults" id="set-payment-defaults">
    **Use it to** set how every payment behaves on this device, once at app start.

    ```kotlin
    Accept.payments.setOptions(
        receiptConfig = PaymentReceiptConfig.Show(
            dismissBehavior = DismissBehavior.Delayed(30.seconds),
            printBehavior = ReceiptPrintBehavior.Automatic,
        ),
        transactionTimeout = 90.seconds,
    )
    ```

    **Good to know:**

    * Only the options you pass change. The others keep their current value.
    * Any `pay()` call can override them for one payment.

    **Options:**

    | Option               | Description                                                                                                                      |
    | -------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
    | `receiptConfig`      | The receipt screen after an approved payment: `Show(...)` or `DismissImmediately`. Choose the QR code, auto-close, and printing. |
    | `transactionTimeout` | How long to wait for a card tap, up to 120 seconds.                                                                              |
    | `nfcPosition`        | Where the "tap here" animation points, when the terminal app gets it wrong.                                                      |
    | `display`            | Which screen shows the payment: `Default`, `CustomerFacing`, or `Specific(displayId)`.                                           |
  </Accordion>

  <Accordion title="Get a payment" id="get-a-payment">
    **Use it to** check a payment's final state, and get its receipt link.

    ```kotlin
    val status = Accept.payments.status(paymentToken)
    if (status.state == PaymentState.SUCCESS) showReceipt(status.receiptUrl)
    ```

    **Good to know:**

    * Use it when a payment timed out or your app was closed during it.
    * Throws `PaymentNotFound` for an unknown token.

    **Returns:**

    | Field                  | Description                                                                  |
    | ---------------------- | ---------------------------------------------------------------------------- |
    | `state`                | `PENDING`, `SUCCESS`, `CANCELLED`, `REFUNDED`, `FAILED`, or `ACTION_NEEDED`. |
    | `receiptUrl`           | A link to the receipt, to show or share.                                     |
    | Amounts and timestamps | What was requested and settled, and when.                                    |
  </Accordion>

  <Accordion title="Cancel a payment" id="cancel-a-payment">
    **Use it to** stop a payment that has not finished yet.

    ```kotlin
    val state = Accept.payments.cancel(paymentToken)
    ```

    **Good to know:**

    * Returns the payment's new `PaymentState`.
  </Accordion>

  <Accordion title="Refund a payment" id="refund-a-payment">
    **Use it to** give a customer their money back.

    ```kotlin
    val state = Accept.payments.refund(paymentToken, RefundReason.CUSTOMER_REQUEST)
    ```

    **Good to know:**

    * `RefundReason` is `CUSTOMER_REQUEST`, `DUPLICATE`, `FRAUDULENT`, or `EXPIRED_CHARGE`.
    * Returns the payment's new `PaymentState`.
  </Accordion>
</Accordions>

## Terminal app [#terminal-app]

Every card payment runs in the Tapaya Terminal app. Install and activate it once per device.

<Accordions type="multiple">
  <Accordion title="Install the terminal app" id="install-the-terminal-app">
    **Use it to** make sure Tapaya Terminal is on the device before the first payment.

    ```kotlin
    if (!Accept.plugin.isInstalled()) {
        Accept.plugin.install() // opens the store page
    }
    ```

    **Good to know:**

    * Without the app, payments fail with `PluginUnavailable`.
  </Accordion>

  <Accordion title="Activate the terminal" id="activate-the-terminal">
    **Use it to** link this device to the signed-in merchant. Do it once per device.

    ```kotlin
    when (val result = Accept.plugin.activateTerminal()) {
        ActivateTerminalResult.Success -> showPaymentScreen()
        ActivateTerminalResult.Canceled -> Unit // the merchant backed out
        is ActivateTerminalResult.Failed -> showError(result.reason)
    }
    ```

    **Good to know:**

    * Throws `NoTidsAvailableForMerchant` if the merchant has no free terminal left.
    * `Failed` reasons include `MERCHANT_NOT_ONBOARDED`.
  </Accordion>

  <Accordion title="Check the terminal app" id="check-the-terminal-app">
    **Use it to** enable your Pay button only when the terminal can take payments.

    ```kotlin
    val status = Accept.plugin.status()
    ```

    **Good to know:**

    * Paying while the terminal is not ready fails with `PluginNotReadyForPayments`.
  </Accordion>

  <Accordion title="Check for an update" id="check-for-an-update">
    **Use it to** ask the merchant to update the terminal app before it causes a failed payment.

    ```kotlin
    when (val info = Accept.plugin.updateInfo()) {
        PluginUpdateInfo.UpToDate -> Unit
        is PluginUpdateInfo.UpdateAvailable -> promptUpdate(info.priority) // higher is more urgent
        PluginUpdateInfo.Unknown -> Unit // not installed, or too old to tell
    }
    ```
  </Accordion>

  <Accordion title="Sign out of the terminal app" id="sign-out-of-the-terminal-app">
    **Use it to** sign the merchant out of Tapaya Terminal, for example before another merchant uses the device.

    ```kotlin
    Accept.plugin.logout()
    ```

    **Good to know:**

    * Needed when the terminal app is signed in as a different merchant (`PluginMerchantMismatch`).
  </Accordion>
</Accordions>

## Merchant [#merchant]

Read the signed-in merchant's details. Every call here needs a signed-in merchant.

<Accordions type="multiple">
  <Accordion title="Get the merchant profile" id="get-the-merchant-profile">
    **Use it to** show the merchant's business name and details in your app.

    ```kotlin
    val info = Accept.merchant.info()
    info?.legalName
    ```

    **Good to know:**

    * Returns `null` until the profile is available.

    **Returns:**

    | Field                                             | Description                                                                               |
    | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
    | `merchantId`, `email`                             | Who the merchant is.                                                                      |
    | `legalName`, `businessType`, `registrationNumber` | The registered business.                                                                  |
    | `addressLine1`, `city`, `country`                 | The registered address.                                                                   |
    | Other fields                                      | Optional details the merchant gave, such as `vatNumber` and `phone`. `null` when missing. |
  </Accordion>

  <Accordion title="Get the merchant currencies" id="get-the-merchant-currencies">
    **Use it to** offer only the currencies the merchant can accept.

    ```kotlin
    val currencies = Accept.merchant.availableCurrencies() // ["CZK", "EUR"]
    val defaultCurrency = Accept.merchant.config().currency
    ```

    **Good to know:**

    * Paying in any other currency fails with `CurrencyNotAvailableForMerchant`.
  </Accordion>

  <Accordion title="Check onboarding" id="check-onboarding">
    **Use it to** tell the merchant what to finish before they can take payments.

    ```kotlin
    when (val status = Accept.merchant.onboardingStatus()) {
        OnboardingStatus.ReadyForPayments -> showPaymentScreen()
        is OnboardingStatus.RequiresAction -> showOnboardingHint(status.state)
    }
    ```

    **Good to know:**

    * Onboarding happens outside the SDK. See [Merchant Onboarding](/merchants/onboarding).
  </Accordion>
</Accordions>

## Device and SDK [#device-and-sdk]

Read facts about this device and the SDK.

<Accordions type="multiple">
  <Accordion title="Get SDK and device details" id="get-sdk-and-device-details">
    **Use it to** show the environment, check minimum amounts, and give support your device ID.

    ```kotlin
    Accept.sdk.isProduction           // true in production
    Accept.sdk.deviceId()             // this device's ID, for support
    Accept.sdk.minimumAmounts()       // the smallest amount per currency
    ```

    **Good to know:**

    * `deviceId()` is `null` until the first sign-in.
    * Paying below the minimum fails with `AmountBelowMinimum`.
  </Accordion>

  <Accordion title="Use a customer screen" id="use-a-customer-screen">
    **Use it to** show the payment on the customer's side of a two-screen terminal.

    ```kotlin
    if (Accept.displays.isDualScreen) {
        Accept.payments.setOptions(display = PaymentDisplay.CustomerFacing)
    }
    ```

    **Good to know:**

    * `Accept.displays.customerFacing()` returns the customer screen, or `null` on one-screen devices.
    * `Accept.displays.all()` lists every screen, for `PaymentDisplay.Specific(displayId)`.
    * Set the screen before signing in, so the terminal warm-up uses it too.
  </Accordion>
</Accordions>

## NFC tags [#nfc-tags]

Read and write NFC tags, such as loyalty cards or access badges, with the same reader. Add
`com.tapaya:accept-nfc` and import `com.tapaya.accept.nfc.nfc`. See [NFC Tags](/in-store/integration/nfc_tags) for
the full guide.

<Accordions type="multiple">
  <Accordion title="Check NFC support" id="check-nfc-support">
    **Use it to** show your tag feature only on devices that can read tags.

    ```kotlin
    if (Accept.nfc.isSupported()) showScanTagButton()
    ```

    **Good to know:**

    * It does not touch the reader, so it is safe to call during a payment.
  </Accordion>

  <Accordion title="Read a tag" id="read-a-tag">
    **Use it to** wait for a tag and start a session with it.

    ```kotlin
    val session = Accept.nfc.openSession(activity)
    try {
        showTag(session.info.uidHex, session.info.family)
    } finally {
        session.close()
    }
    ```

    **Good to know:**

    * Waits up to 30 seconds for a tap. Show a "Tap your card" prompt meanwhile.
    * Pass a resumed, foreground activity.
    * Failures throw `TagSessionException`. Its `reason` says what to do, such as `TIMEOUT` or `NFC_DISABLED`.
    * Change the waits with `TagTimeouts(tapWait = 15.seconds)`.

    **Returns:** a session. `session.info` has the tag's `uidHex`, its `family`, and other details.
  </Accordion>

  <Accordion title="Tag commands" id="tag-commands">
    **Use it to** read and write the tag. The commands depend on `session.info.family`.

    ```kotlin
    // NTAG and MIFARE Ultralight
    val pages = session.readPages(startPage = 4)

    // MIFARE Classic: authenticate the sector first
    session.authenticateClassic(block = 4, keyType = MifareKeyType.A, key = sectorKey)
    val block = session.readBlock(4)

    // Smart cards (ISO-DEP)
    val response = session.transmitApdu(selectApdu)
    ```

    **Commands:**

    | Tag              | Commands                                                                                          |
    | ---------------- | ------------------------------------------------------------------------------------------------- |
    | NTAG, Ultralight | `readPages`, `writePage`, `passwordAuth`, `ultralightCAuth`, `transceiveType2`                    |
    | MIFARE Classic   | `authenticateClassic`, `readBlock`, `writeBlock`, `increment`, `decrement`, `restore`, `transfer` |
    | Smart cards      | `transmitApdu`                                                                                    |

    **Good to know:**

    * A command the tag does not support fails with `NOT_SUPPORTED`, and the session stays open.
  </Accordion>

  <Accordion title="End a tag session" id="end-a-tag-session">
    **Use it to** free the reader when you are done, and learn why a session ended.

    ```kotlin
    session.close()

    val reason = session.ended.filterNotNull().first() // e.g. CARD_REMOVED or PAYMENT
    ```

    **Good to know:**

    * Always close the session. Until then, nothing else can use the reader.
    * A payment always takes the reader and ends the session with `PAYMENT`.
  </Accordion>
</Accordions>

## Errors [#errors]

**Use it to** tell what went wrong and react.

```kotlin
try {
    val status = Accept.payments.status(paymentToken)
} catch (e: SessionExpired) {
    reauthenticate()
} catch (e: NoInternetConnection) {
    showOfflineMessage()
} catch (e: AcceptException) {
    showError(e)
}
```

**Good to know:**

* Every SDK error extends `AcceptException`.
* `pay()` never throws. The same errors arrive as `PaymentEvent.CreationFailed`.
* NFC tag errors are `TagSessionException`, not `AcceptException`.

**Errors:**

| Error                                                                  | When                                                                    |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `NotInitialized`, `NotAuthenticated`                                   | Call `initialize()` or `authenticate()` first.                          |
| `SessionExpired`                                                       | Sign in again.                                                          |
| `PaymentInProgress`                                                    | Another payment is still running.                                       |
| `CurrencyNotAvailableForMerchant`, `UnsupportedCurrency`               | The merchant cannot accept this currency.                               |
| `AmountBelowMinimum`                                                   | The amount is below the currency's minimum.                             |
| `TransactionTimeoutOutOfRange`                                         | `transactionTimeout` is over 120 seconds.                               |
| `PaymentNotFound`                                                      | The payment token is unknown.                                           |
| `LocationPermissionRequired`, `LocationUnavailable`, `LocationTimeout` | The app has no location permission, or no location fix.                 |
| `PluginUnavailable`, `PluginTimeout`                                   | The terminal app is missing or not responding.                          |
| `PluginNotReadyForPayments`                                            | The terminal is not ready. Check [its status](#check-the-terminal-app). |
| `PluginMerchantMismatch`, `PluginAlreadyAuthenticated`                 | The terminal app is signed in already, maybe as another merchant.       |
| `ActivationInProgress`, `NoTidsAvailableForMerchant`                   | Activation is running, or the merchant has no free terminal.            |
| `MerchantOnboardingIncomplete`                                         | The merchant has not finished onboarding.                               |
| `NoInternetConnection`                                                 | The device is offline.                                                  |
| `PaymentCreationFailed`, `Unknown`                                     | Anything else. Check `cause`.                                           |
