# Integrazione dell'SDK mobile (/it/in-store/integration/sdk_integration)





Tapaya Accept SDK integra l'elaborazione dei pagamenti con carta direttamente nella Sua app. È disponibile per &#x2A;*Android
(Kotlin)** e per **React Native / Expo**, ed entrambe le versioni sono destinate a dispositivi Android. Il pacchetto React Native è un
sottile wrapper dell'SDK Android, quindi le interfacce, i tipi e i casi di errore descritti di seguito sono gli stessi in entrambi.

Ogni esempio di codice in questa pagina è suddiviso in schede per linguaggio. Ne scelga uno e l'intera pagina si adegua.

## Installazione [#installation]

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin title="build.gradle.kts"
    dependencies {
        implementation("com.tapaya:accept:1.15.0")
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```json title="app.json"
    {
      "expo": {
        "plugins": ["@tapayadot/accept-react-native"]
      }
    }
    ```
  </CodeBlockTab>
</CodeBlockTabs>

**Android:** aggiunga la dipendenza al file `build.gradle.kts` a livello di modulo, quindi sincronizzi il progetto.

**React Native:** installi il pacchetto con `npx expo install @tapayadot/accept-react-native`, aggiunga il config plugin come
mostrato, quindi rigeneri il progetto nativo con `npx expo prebuild --clean` e lo avvii con
`npx expo run:android`.

## Inizializzazione [#initialization]

`Accept` è il punto di accesso a tutte le funzionalità dell'SDK. Lo inizializzi una sola volta all'avvio dell'app (su Android,
di solito nella classe `Application`), quindi esegua l'autenticazione separatamente con un token dell'esercente.

### Passaggio 1: inizializzazione [#step-1-initialize]

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    // Sandbox is the default (isProduction = false)
    Accept.initialize(context = this)

    // Target production explicitly
    Accept.initialize(context = this, isProduction = true)

    // Or drive it from your build type
    Accept.initialize(context = this, isProduction = !BuildConfig.DEBUG)
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    import Accept from '@tapayadot/accept-react-native';

    // Sandbox is the default
    Accept.initialize();

    // Target production explicitly
    Accept.initialize({ isProduction: true });

    // Or drive it from your build
    Accept.initialize({ isProduction: !__DEV__ });
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Su React Native non c'è alcun `context`: lo gestisce il modulo nativo.

### Passaggio 2: autenticazione [#step-2-authenticate]

Dopo l'inizializzazione, chiami `Accept.auth.authenticate()` per far accedere un esercente con un token ottenuto dal Suo
backend. La chiamata è asincrona e, in caso di errore, fallisce con un errore dell'SDK. In caso di successo, lo stato dell'SDK diventa *authenticated*.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    // suspend; call from a coroutine
    try {
        val sdkToken = myBackendApi.getSdkToken()
        Accept.auth.authenticate(sdkToken)
        // Accept.state now emits SdkState.Authenticated
    } catch (e: AcceptException) {
        // handle authentication failure
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    try {
        const sdkToken = await myBackendApi.getSdkToken();
        await Accept.auth.authenticate(sdkToken);
        // Accept.state is now 'authenticated'
    } catch (error) {
        // handle authentication failure
    }
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Osservi il ciclo di vita per reagire a queste transizioni: `idle → initialized → authenticated`.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    // Accept.state is a StateFlow<SdkState>
    Accept.state.collect { state ->
        if (state == SdkState.Authenticated) loadMerchant()
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    // Accept.state is a plain getter; subscribe for changes
    const subscription = Accept.addStateListener((state) => {
        if (state === 'authenticated') loadMerchant();
    });

    // later
    subscription.remove();
    ```
  </CodeBlockTab>
</CodeBlockTabs>

## Concetti fondamentali [#core-concepts]

L'oggetto `Accept` espone l'SDK tramite un piccolo insieme di interfacce:

| Interfaccia       | Scopo                                                                                                         |
| :---------------- | :------------------------------------------------------------------------------------------------------------ |
| `Accept.auth`     | Autenticare una sessione dell'esercente.                                                                      |
| `Accept.merchant` | Profilo dell'esercente, configurazione, stato dell'onboarding.                                                |
| `Accept.payments` | Creare e gestire i pagamenti con carta.                                                                       |
| `Accept.plugin`   | Installazione e attivazione del terminale (app plugin).                                                       |
| `Accept.displays` | Informazioni sui display del dispositivo per i terminali a doppia faccia (“double-sided”).                    |
| `Accept.sdk`      | Versione dell'SDK, ambiente, ID del dispositivo, importi minimi.                                              |
| `Accept.state`    | Stato del ciclo di vita: `StateFlow<SdkState>` in Kotlin, un getter più `addStateListener()` in React Native. |

### Accettare un pagamento [#taking-a-payment]

Chiami `Accept.payments.pay()` con l'importo (nell'unità minima della valuta) e un codice valuta ISO 4217, quindi
osservi il flusso di eventi `PaymentEvent` che restituisce: prima l'avanzamento, poi l'esito finale. `pay()` non genera mai
eccezioni; un errore nella creazione del pagamento arriva invece come evento `CreationFailed`.

L'unica differenza è il modo in cui si osserva il flusso: Kotlin restituisce un `Flow<PaymentEvent>` da raccogliere
in una coroutine, mentre React Native accetta un listener e restituisce una sottoscrizione che si può chiudere con `remove()`.

`amount` e `currency` sono obbligatori. Per i parametri facoltativi (`paymentToken`, `receiptConfig`, `nfcPosition`,
`metadata`, `tip`, `transactionTimeout`, `display`), consulti [Creare un pagamento](./card_terminal#create-a-payment).

<Callout title="In React Native" type="info">
  Gli stessi parametri arrivano come un unico oggetto `PaymentRequest`, `pay({ amount, currency, tip, … })`, con
  `number` al posto di `Long` e `Record<string, string>` al posto di `Map<String, String>`. Un solo nome cambia: il
  timeout è `transactionTimeoutMs` e accetta semplici millisecondi (`0`…`120000`) anziché una `Duration`.
</Callout>

<div className="bg-background relative h-auto w-full overflow-hidden rounded-lg border px-10">
    <img alt="Flusso di pagamento" src="__img0" />
</div>

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    Accept.payments.pay(amount = 15000, currency = "CZK") // 150.00 Kč
        .collect { event ->
            when (event) {
                PaymentEvent.Creating -> Log.d("pay", "creating")
                is PaymentEvent.Created -> Log.d("pay", "created ${event.paymentToken}")
                PaymentEvent.Launched -> Log.d("pay", "launched")
                is PaymentEvent.Result -> Log.d("pay", event.payResult.toString())
                is PaymentEvent.CreationFailed -> Log.e("pay", event.cause.toString())
            }
        }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    const subscription = Accept.payments.pay(
        { amount: 15000, currency: 'CZK' }, // 150.00 Kč
        (event) => {
            switch (event.type) {
                case 'creating':
                    setStatus('Creating payment…');
                    break;
                case 'created':
                    // The payment token and receipt URL exist before the plugin is launched.
                    setReceiptUrl(event.receiptUrl);
                    break;
                case 'launched':
                    setStatus('Waiting for the card…');
                    break;
                case 'result':
                    setResult(event.payResult);
                    break;
                case 'creationFailed':
                    setError(event.error); // the payment never started
                    break;
            }
        },
    );

    // The stream ends itself after `result` or `creationFailed`.
    // Call subscription.remove() only to stop listening early.
    ```
  </CodeBlockTab>
</CodeBlockTabs>

L'evento finale con il risultato contiene un `PayResult`: riuscito (con `paymentToken`, `metadata`, `authCode`,
`receiptDetails`), rifiutato (`metadata`, `receiptDetails`), annullato (`metadata`) o non riuscito (`reason`,
`metadata`). Kotlin li modella come sottoclassi `PayResult.Success` / `Declined` / `Canceled` / `Failed`;
React Native come unione discriminata su cui si dirama con `payResult.type === 'success'`. Il dettaglio completo è in
[Esito del pagamento](./card_terminal#payment-outcome). In seguito può interrogare un pagamento con
`Accept.payments.status(paymentToken)`, interromperlo con `Accept.payments.cancel(paymentToken)` o rimborsarlo con
`Accept.payments.refund(paymentToken, reason)`.

#### Solo l'esito (React Native) [#just-the-outcome-react-native]

Se la Sua interfaccia non mostra gli stati intermedi, `payAsync()` riduce l'intero flusso al `PayResult`
finale e viene rifiutata con un `AcceptError` per tutto ciò che `pay()` avrebbe segnalato come
`creationFailed`. Non ha un equivalente in Kotlin: lì raccolga il `Flow` oppure ne prenda solo l'ultimo evento.

```typescript
const result = await Accept.payments.payAsync({ amount: 15000, currency: 'CZK' });
if (result.type === 'success') {
    console.log(result.paymentToken, result.receiptUrl);
}
```

## Informazioni sull'esercente e sull'SDK [#merchant--sdk-info]

`Accept.merchant` espone il profilo e la configurazione di pagamento dell'esercente che ha effettuato l'accesso. `Accept.sdk` espone
informazioni sulla build dell'SDK e su questo dispositivo. Ogni membro descritto di seguito richiede prima `Accept.initialize()` (tranne
`Accept.sdk.version`), e tutto ciò che si trova su `Accept.merchant` richiede inoltre un
`Accept.auth.authenticate()` completato, altrimenti la chiamata genera `NotInitialized` o `NotAuthenticated`.

### Esercente [#merchant]

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    val info = Accept.merchant.info()                      // MerchantInformation?
    val config = Accept.merchant.config()                  // MerchantConfig
    val currencies = Accept.merchant.availableCurrencies() // List<String>
    val status = Accept.merchant.onboardingStatus()        // OnboardingStatus
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    const info = await Accept.merchant.info();                      // MerchantInformation | null
    const config = await Accept.merchant.config();                  // MerchantConfig
    const currencies = await Accept.merchant.availableCurrencies(); // string[]
    const status = await Accept.merchant.onboardingStatus();        // OnboardingStatus
    ```
  </CodeBlockTab>
</CodeBlockTabs>

| Membro                  | Restituisce            | Descrizione                                                                                        |
| :---------------------- | :--------------------- | :------------------------------------------------------------------------------------------------- |
| `info()`                | `MerchantInformation?` | Il profilo aziendale registrato dell'esercente. `null` se il profilo non è ancora disponibile.     |
| `config()`              | `MerchantConfig`       | La configurazione di pagamento dell'esercente.                                                     |
| `availableCurrencies()` | `List<String>`         | Codici ISO 4217 che l'esercente può accettare. Forma abbreviata di `config().availableCurrencies`. |
| `onboardingStatus()`    | `OnboardingStatus`     | Indica se l'esercente può già accettare pagamenti.                                                 |

Tutti e quattro sono `suspend` e in caso di errore generano `NotAuthenticated`, `NoInternetConnection` o `Unknown`.

**`MerchantInformation`** contiene il profilo aziendale registrato. Sempre presenti: `merchantId` (`UUID`),
`email`, `businessType` (`BusinessType`), `legalName`, `registrationNumber`, `mcc` e l'indirizzo registrato
(`addressLine1`, `city`, `country`). Facoltativi (`null` se l'esercente non li ha forniti): `vatNumber`,
`incorporationDate`, `addressLine2`, `postalCode`, `state`, `phone`, `averageItemValue`,
`expectedMonthlyTurnover`, `businessModelDescription`, `numberOfEmployees`, `annualTurnover`,
`balanceSheetTotal`, `statementDescriptor`, `termsVersion`.

`BusinessType` è uno tra `INDIVIDUAL`, `COMPANY`, `NONPROFIT_ORGANIZATION`, `GOVERNMENT_ENTITY` o
`PARTNERSHIP`.

**`MerchantConfig`** contiene `availableCurrencies: List<String>` e la valuta predefinita dell'esercente, `currency: String?`.

**`OnboardingStatus`** è un'interfaccia sealed: `ReadyForPayments` oppure `RequiresAction(state)`, dove
`state` è un `OnboardingState`: `NOT_STARTED`, `PENDING`, `ACTIVE`, `ATTENTION_NEEDED`, `ACTION_REQUIRED`,
`BLOCKED`, `WAITING_FOR_KYB`, `WAITING_FOR_STAKEHOLDERS` o `PENDING_ACQUIRER_APPROVAL`. Il significato di ogni stato è spiegato in
[Onboarding degli esercenti](/merchants/onboarding).

### SDK [#sdk]

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    Accept.sdk.version            // String, e.g. "1.15.0"
    Accept.sdk.isProduction       // Boolean
    Accept.sdk.deviceId()         // String?  (suspend)
    Accept.sdk.minimumAmounts()   // List<MinimumAmount>  (suspend)
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    Accept.sdk.version                  // string, e.g. "1.15.0"
    Accept.sdk.isProduction             // boolean
    await Accept.sdk.deviceId()         // string | null
    await Accept.sdk.minimumAmounts()   // MinimumAmount[]
    ```
  </CodeBlockTab>
</CodeBlockTabs>

| Membro             | Restituisce           | Descrizione                                                                                                                                                                                           |
| :----------------- | :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`          | `String`              | La versione dell'SDK. Leggibile prima di `initialize()`.                                                                                                                                              |
| `isProduction`     | `Boolean`             | Indica se `initialize()` ha impostato la produzione (`true`) o la sandbox (`false`).                                                                                                                  |
| `deviceId()`       | `String?`             | L'ID stabile di questo dispositivo, assegnato al primo `authenticate()` riuscito e conservato finché l'app non viene disinstallata. `null` prima di allora. Lo indichi nelle richieste di assistenza. |
| `minimumAmounts()` | `List<MinimumAmount>` | L'importo minimo pagabile per ogni valuta supportata. Ogni voce è `currency: String, amount: Long` nell'unità minore della valuta.                                                                    |

## App plugin [#plugin-app]

Ogni pagamento con carta passa a **Tapaya Terminal**, l'app plugin di Tapaya; è sempre obbligatoria e non esiste
alcun percorso di pagamento con carta che la salti. Verifichi se è installata, quindi attivi il terminale, oppure apra la scheda
nello store affinché l'esercente possa installarla.

A questo scopo usi `Accept.plugin.isInstalled()`, `Accept.plugin.activateTerminal()` e `Accept.plugin.install()`. Il codice e tutti
gli esiti dell'attivazione sono descritti in [Installare e attivare il terminale](./card_terminal#install-and-activate-the-terminal).

Legga lo stato attuale del plugin con `Accept.plugin.status()` oppure disconnetta l'esercente dal plugin con
`Accept.plugin.logout()`.

## Autorizzazioni [#permissions]

I pagamenti con carta richiedono che l'app host disponga dell'autorizzazione alla posizione (`ACCESS_FINE_LOCATION`). L'SDK non
la richiede al posto Suo: la ottenga con le API di autorizzazione standard di Android prima di chiamare `pay()`.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    class PaymentActivity : AppCompatActivity() {
        private val requestLocation = registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { granted ->
            if (granted) launchPaymentFlow() else showPermissionRationale()
        }

        fun startPayment() {
            requestLocation.launch(Manifest.permission.ACCESS_FINE_LOCATION)
        }
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    import { PermissionsAndroid } from 'react-native';

    const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
    );

    if (granted === PermissionsAndroid.RESULTS.GRANTED) launchPaymentFlow();
    else showPermissionRationale();
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Se, quando viene eseguito `pay()`, l'autorizzazione alla posizione manca o la posizione non può essere determinata, il flusso emette `PaymentEvent.CreationFailed`
con causa `LocationPermissionRequired`, `LocationUnavailable` o `LocationTimeout`.

## Gestione degli errori [#error-handling]

Ogni errore gestito porta uno dei nomi riportati di seguito. In Kotlin ciascuno è una sottoclasse della classe sealed
`AcceptException`; in React Native sono tutti un'unica classe `AcceptError` il cui `code` contiene il nome, mentre i
campi del payload (`minimum`, `currency`, `state`, …) si trovano sullo stesso oggetto.

Le chiamate asincrone (`authenticate`, `merchant.*`, `payments.status`/`cancel`/`refund`,
`plugin.activateTerminal`/`status`/`logout`/`updateInfo`, `clear`) falliscono con uno di questi. `payments.pay()` è
l'eccezione: non genera mai eccezioni e segnala gli stessi errori come evento `CreationFailed` che ne riporta la causa.

### Tipi di eccezione [#exception-types]

| Eccezione                                          | Descrizione                                                                                                              |
| :------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- |
| **Ciclo di vita**                                  |                                                                                                                          |
| `NotInitialized`                                   | Una chiamata richiede prima `Accept.initialize()`.                                                                       |
| `NotAuthenticated`                                 | Una chiamata richiede prima `Accept.auth.authenticate()`.                                                                |
| `SessionExpired`                                   | La sessione autenticata è scaduta; ripeta l'autenticazione.                                                              |
| `UnknownEnvironment(key)`                          | Chiave di ambiente non riconosciuta (overload interno di initialize).                                                    |
| **Pagamenti**                                      |                                                                                                                          |
| `PaymentInProgress`                                | Un `pay()` precedente è ancora in attesa di un risultato.                                                                |
| `CurrencyNotAvailableForMerchant(code)`            | Valuta non configurata per l'esercente.                                                                                  |
| `UnsupportedCurrency(code)`                        | Valuta non riconosciuta dall'SDK.                                                                                        |
| `AmountBelowMinimum(minimum, currency)`            | Importo inferiore al minimo configurato.                                                                                 |
| `TransactionTimeoutOutOfRange(transactionTimeout)` | `transactionTimeout` al di fuori dell'intervallo da 0 a 120 secondi.                                                     |
| `PaymentCreationFailed(cause)`                     | Qualsiasi altro errore durante la creazione di un pagamento.                                                             |
| `PaymentNotFound`                                  | Token di `status()`/`cancel()`/`refund()` sconosciuto al backend.                                                        |
| **Posizione**                                      |                                                                                                                          |
| `LocationPermissionRequired`                       | L'app host non dispone dell'autorizzazione alla posizione.                                                               |
| `LocationUnavailable`                              | Nessun provider è riuscito a determinare la posizione.                                                                   |
| `LocationTimeout`                                  | Posizione non determinata in tempo.                                                                                      |
| **Plugin / terminale**                             |                                                                                                                          |
| `PluginUnavailable`                                | App plugin non installata, oppure non è stato possibile collegarsi al suo servizio.                                      |
| `PluginTimeout`                                    | Il plugin non ha risposto in tempo.                                                                                      |
| `ActivationInProgress`                             | Un `activateTerminal()` precedente è ancora in attesa di un risultato.                                                   |
| `NoTidsAvailableForMerchant`                       | All'esercente non resta alcun terminale (TID) non assegnato da attivare.                                                 |
| `PluginAlreadyAuthenticated`                       | Plugin già autenticato per questo esercente.                                                                             |
| `PluginMerchantMismatch`                           | Plugin autenticato con un altro esercente; chiami prima `plugin.logout()`.                                               |
| `PluginNotReadyForPayments(status)`                | `pay()` è stato eseguito mentre il plugin non era in `PluginStatus.ReadyForPayments`; `status` riporta lo stato attuale. |
| `MerchantOnboardingIncomplete(state)`              | L'esercente non ha completato l'onboarding.                                                                              |
| **Sistema**                                        |                                                                                                                          |
| `NoInternetConnection`                             | Il dispositivo non ha connettività di rete.                                                                              |
| `Unknown(cause)`                                   | Qualsiasi errore che l'SDK non riconosce come proprio.                                                                   |

<Callout title="Risultato o eccezione" type="info">
  Un pagamento che raggiunge il terminale ma non va a buon fine **non** è un'eccezione: arriva come
  `PaymentEvent.Result` con `PayResult.Declined`, `Canceled` o `Failed(reason)`. Allo stesso modo, l'attivazione
  del terminale restituisce `ActivateTerminalResult.Failed(reason)`.
</Callout>

### Gestione delle eccezioni [#handling-exceptions]

Racchiuda la chiamata in un blocco `try`/`catch` e gestisca separatamente i casi specifici che Le interessano, ricorrendo a un catch generico per il resto.
Kotlin distingue in base alla sottoclasse dell'eccezione; React Native verifica con `AcceptError.is()` ed esegue uno switch su `code`.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    try {
        val status = Accept.payments.status(paymentToken)
    } catch (e: SessionExpired) {
        // Re-authenticate
    } catch (e: NoInternetConnection) {
        // Ask the user to check connectivity
    } catch (e: AcceptException) {
        // Handle any other SDK error
        Log.e("Payment", "Error: ${e.message}")
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    import Accept, { AcceptError } from '@tapayadot/accept-react-native';

    try {
        const status = await Accept.payments.status(paymentToken);
    } catch (error) {
        if (!AcceptError.is(error)) throw error;

        switch (error.code) {
            case 'SessionExpired':
                // Re-authenticate
                break;
            case 'NoInternetConnection':
                // Ask the user to check connectivity
                break;
            case 'AmountBelowMinimum':
                // Payload fields sit on the error itself
                alert(`Minimum is ${error.minimum} ${error.currency}`);
                break;
            default:
                throw error;
        }
    }
    ```
  </CodeBlockTab>
</CodeBlockTabs>

### Logging [#logging]

Durante lo sviluppo attivi il logging di debug per diagnosticare i problemi.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    Accept.setDebugLoggingEnabled(true)
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    Accept.setDebugLoggingEnabled(true);
    ```
  </CodeBlockTab>
</CodeBlockTabs>

### Disconnessione [#logging-out]

Cancelli tutto lo stato dell'SDK salvato localmente (token di autenticazione, ID del dispositivo, configurazione in cache) e riporti lo stato dell'SDK a
*idle*. Esegua questa operazione quando l'utente si disconnette. Per disconnettere l'esercente anche dall'app Tapaya Terminal, chiami prima
`Accept.plugin.logout()`.

<CodeBlockTabs defaultValue="kotlin" groupId="accept-language">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="kotlin">
      Android (Kotlin)
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="typescript">
      React Native (TypeScript)
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="kotlin">
    ```kotlin
    Accept.plugin.logout() // suspend; signs out of the Tapaya Terminal app
    Accept.clear()         // suspend; clears local SDK state
    ```
  </CodeBlockTab>

  <CodeBlockTab value="typescript">
    ```typescript
    await Accept.plugin.logout(); // signs out of the Tapaya Terminal app
    await Accept.clear();         // clears local SDK state
    ```
  </CodeBlockTab>
</CodeBlockTabs>
