# Intégration du SDK mobile (/fr/in-store/integration/sdk_integration)





Le Tapaya Accept SDK intègre le traitement des paiements par carte directement dans votre application. Il est disponible pour &#x2A;*Android
(Kotlin)** et pour **React Native / Expo**, et tous deux ciblent les appareils Android. Le package React Native est une
fine surcouche du SDK Android : les interfaces, les types et les cas d’échec décrits ci-dessous sont donc identiques sur les deux.

Chaque exemple de code de cette page est proposé dans des onglets par langage. Choisissez-en un et toute la page s’aligne sur ce choix.

## Installation [#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 :** ajoutez la dépendance au fichier `build.gradle.kts` de votre module, puis synchronisez le projet.

**React Native :** installez le package avec `npx expo install @tapayadot/accept-react-native`, ajoutez le plugin de configuration comme
indiqué, puis régénérez le projet natif avec `npx expo prebuild --clean` et lancez-le avec
`npx expo run:android`.

## Initialisation [#initialization]

`Accept` est le point d’entrée de toutes les fonctionnalités du SDK. Initialisez-le une seule fois au démarrage de l’application (sur Android,
généralement dans votre classe `Application`), puis authentifiez-vous séparément avec un jeton commerçant.

### Étape 1 : initialiser [#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>

Il n’y a pas de `context` sur React Native ; le module natif le conserve pour vous.

### Étape 2 : s’authentifier [#step-2-authenticate]

Appelez `Accept.auth.authenticate()` après l’initialisation pour connecter un commerçant avec un jeton obtenu depuis votre
backend. L’appel est asynchrone et échoue avec une erreur du SDK. En cas de succès, l’état du SDK passe à *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>

Observez le cycle de vie pour réagir à ces transitions : `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>

## Concepts clés [#core-concepts]

L’objet `Accept` expose le SDK au travers d’un petit nombre d’interfaces :

| Interface         | Rôle                                                                                                          |
| :---------------- | :------------------------------------------------------------------------------------------------------------ |
| `Accept.auth`     | Authentifier une session commerçant.                                                                          |
| `Accept.merchant` | Profil du commerçant, configuration, statut d’onboarding.                                                     |
| `Accept.payments` | Créer et gérer les paiements par carte.                                                                       |
| `Accept.plugin`   | Installation et activation du terminal (application plugin).                                                  |
| `Accept.displays` | Informations sur les écrans de l’appareil pour les terminaux à double face (« double-sided »).                |
| `Accept.sdk`      | Version du SDK, environnement, identifiant de l’appareil, montants minimaux.                                  |
| `Accept.state`    | État du cycle de vie : `StateFlow<SdkState>` en Kotlin, un getter plus `addStateListener()` sur React Native. |

### Accepter un paiement [#taking-a-payment]

Appelez `Accept.payments.pay()` avec le montant (dans la plus petite unité de la devise) et un code de devise ISO 4217, puis
observez le flux d’événements `PaymentEvent` qu’il émet : d’abord la progression, puis le résultat final. `pay()` ne lève jamais
d’exception ; un échec de création du paiement arrive à la place sous forme d’événement `CreationFailed`.

Seule la manière d’observer ce flux diffère : Kotlin renvoie un `Flow<PaymentEvent>` que vous collectez
depuis une coroutine, tandis que React Native prend un listener et renvoie un abonnement que vous pouvez résilier avec `remove()`.

`amount` et `currency` sont obligatoires. Pour les paramètres facultatifs (`paymentToken`, `receiptConfig`, `nfcPosition`,
`metadata`, `tip`, `transactionTimeout`, `display`), consultez [Créer un paiement](./card_terminal#create-a-payment).

<Callout title="Sur React Native" type="info">
  Les mêmes paramètres sont transmis dans un seul objet `PaymentRequest`, `pay({ amount, currency, tip, … })`, avec
  `number` à la place de `Long` et `Record<string, string>` à la place de `Map<String, String>`. Un seul renommage : le
  délai d’expiration s’appelle `transactionTimeoutMs` et prend de simples millisecondes (`0`…`120000`) au lieu d’une `Duration`.
</Callout>

<div className="bg-background relative h-auto w-full overflow-hidden rounded-lg border px-10">
     <img alt="Parcours de paiement" 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’événement de résultat final contient un `PayResult` : succès (avec `paymentToken`, `metadata`, `authCode`,
`receiptDetails`), refus (`metadata`, `receiptDetails`), annulation (`metadata`) ou échec (`reason`,
`metadata`). Kotlin les modélise sous forme de sous-classes `PayResult.Success` / `Declined` / `Canceled` / `Failed` ;
React Native sous forme d’union discriminée dont vous distinguez les cas avec `payResult.type === 'success'`. Consultez
[Résultat du paiement](./card_terminal#payment-outcome) pour le détail complet. Interrogez un paiement ultérieurement avec
`Accept.payments.status(paymentToken)`, arrêtez-le avec `Accept.payments.cancel(paymentToken)` ou remboursez-le avec
`Accept.payments.refund(paymentToken, reason)`.

#### Uniquement le résultat (React Native) [#just-the-outcome-react-native]

Si votre interface n’affiche pas les états intermédiaires, `payAsync()` réduit l’ensemble du flux à son `PayResult`
final, et sa promesse est rejetée avec une `AcceptError` dans tous les cas que `pay()` aurait signalés comme
`creationFailed`. Cette méthode n’a pas d’équivalent en Kotlin : côté Kotlin, collectez le `Flow`, ou ne prenez que son dernier événement.

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

## Informations sur le commerçant et le SDK [#merchant--sdk-info]

`Accept.merchant` expose le profil et la configuration de paiement du commerçant connecté. `Accept.sdk` expose
des informations sur le build du SDK et sur cet appareil. Chaque membre ci-dessous nécessite d’abord `Accept.initialize()` (sauf
`Accept.sdk.version`), et tout ce qui relève de `Accept.merchant` nécessite en outre un appel
`Accept.auth.authenticate()` abouti ; sinon, l’appel lève `NotInitialized` ou `NotAuthenticated`.

### Commerçant [#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>

| Membre                  | Renvoie                | Description                                                                                       |
| :---------------------- | :--------------------- | :------------------------------------------------------------------------------------------------ |
| `info()`                | `MerchantInformation?` | Le profil d’entreprise enregistré du commerçant. `null` si le profil n’est pas encore disponible. |
| `config()`              | `MerchantConfig`       | La configuration de paiement du commerçant.                                                       |
| `availableCurrencies()` | `List<String>`         | Codes ISO 4217 que le commerçant peut accepter. Raccourci pour `config().availableCurrencies`.    |
| `onboardingStatus()`    | `OnboardingStatus`     | Indique si le commerçant peut déjà accepter des paiements.                                        |

Ces quatre fonctions sont `suspend` et lèvent `NotAuthenticated`, `NoInternetConnection` ou `Unknown` en cas d’échec.

**`MerchantInformation`** contient le profil d’entreprise enregistré. Toujours présents : `merchantId` (`UUID`),
`email`, `businessType` (`BusinessType`), `legalName`, `registrationNumber`, `mcc` et l’adresse enregistrée
(`addressLine1`, `city`, `country`). Facultatifs (`null` sauf si le commerçant les a fournis) : `vatNumber`,
`incorporationDate`, `addressLine2`, `postalCode`, `state`, `phone`, `averageItemValue`,
`expectedMonthlyTurnover`, `businessModelDescription`, `numberOfEmployees`, `annualTurnover`,
`balanceSheetTotal`, `statementDescriptor`, `termsVersion`.

`BusinessType` prend l’une des valeurs `INDIVIDUAL`, `COMPANY`, `NONPROFIT_ORGANIZATION`, `GOVERNMENT_ENTITY` ou
`PARTNERSHIP`.

**`MerchantConfig`** contient `availableCurrencies: List<String>` et la devise par défaut du commerçant, `currency: String?`.

**`OnboardingStatus`** est une interface scellée : soit `ReadyForPayments`, soit `RequiresAction(state)`, où
`state` est un `OnboardingState` : `NOT_STARTED`, `PENDING`, `ACTIVE`, `ATTENTION_NEEDED`, `ACTION_REQUIRED`,
`BLOCKED`, `WAITING_FOR_KYB`, `WAITING_FOR_STAKEHOLDERS` ou `PENDING_ACQUIRER_APPROVAL`. Consultez
[Onboarding des commerçants](/merchants/onboarding) pour la signification de chaque état.

### 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>

| Membre             | Renvoie               | Description                                                                                                                                                                                                  |
| :----------------- | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`          | `String`              | La version du SDK. Lisible avant `initialize()`.                                                                                                                                                             |
| `isProduction`     | `Boolean`             | Indique si `initialize()` a ciblé la production (`true`) ou la sandbox (`false`).                                                                                                                            |
| `deviceId()`       | `String?`             | L’identifiant stable de cet appareil, attribué lors du premier `authenticate()` réussi et conservé jusqu’à la désinstallation de l’application. `null` avant cela. Indiquez-le dans vos demandes de support. |
| `minimumAmounts()` | `List<MinimumAmount>` | Le montant minimal payable par devise prise en charge. Chaque entrée est de la forme `currency: String, amount: Long`, dans la plus petite unité de la devise.                                               |

## Application plugin [#plugin-app]

Chaque paiement par carte est confié à **Tapaya Terminal**, l’application plugin de Tapaya ; elle est toujours requise, aucun
parcours de paiement par carte ne s’en passe. Vérifiez si elle est installée, puis activez le terminal, ou ouvrez sa fiche
dans le store pour que le commerçant puisse l’installer.

Utilisez pour cela `Accept.plugin.isInstalled()`, `Accept.plugin.activateTerminal()` et `Accept.plugin.install()`. Consultez
[Installer et activer le terminal](./card_terminal#install-and-activate-the-terminal) pour le code et tous les
résultats d’activation possibles.

Lisez l’état actuel du plugin avec `Accept.plugin.status()`, ou déconnectez le commerçant du plugin avec
`Accept.plugin.logout()`.

## Autorisations [#permissions]

Les paiements par carte exigent que l’application hôte dispose de l’autorisation de localisation (`ACCESS_FINE_LOCATION`). Le SDK ne la
demande pas à votre place ; accordez-la avec les API d’autorisation Android standard avant d’appeler `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>

Si la localisation est absente ou ne peut pas être déterminée lors de l’exécution de `pay()`, le flux émet `PaymentEvent.CreationFailed`
avec pour cause `LocationPermissionRequired`, `LocationUnavailable` ou `LocationTimeout`.

## Gestion des erreurs [#error-handling]

Chaque échec contrôlé porte l’un des noms ci-dessous. En Kotlin, chacun est une sous-classe de la classe scellée
`AcceptException` ; sur React Native, ils relèvent tous d’une seule classe `AcceptError` dont le `code` contient le nom, les
champs de payload (`minimum`, `currency`, `state`, …) étant rattachés au même objet.

Les appels asynchrones (`authenticate`, `merchant.*`, `payments.status`/`cancel`/`refund`,
`plugin.activateTerminal`/`status`/`logout`/`updateInfo`, `clear`) échouent en levant l’une de ces erreurs. `payments.pay()` fait
exception : il ne lève jamais d’exception et signale ces mêmes échecs sous forme d’événement `CreationFailed` portant la cause.

### Types d’exception [#exception-types]

| Exception                                          | Description                                                                                                                       |
| :------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| **Cycle de vie**                                   |                                                                                                                                   |
| `NotInitialized`                                   | Un appel nécessite d’abord `Accept.initialize()`.                                                                                 |
| `NotAuthenticated`                                 | Un appel nécessite d’abord `Accept.auth.authenticate()`.                                                                          |
| `SessionExpired`                                   | La session authentifiée a expiré ; authentifiez-vous de nouveau.                                                                  |
| `UnknownEnvironment(key)`                          | Clé d’environnement non reconnue (surcharge interne d’initialize).                                                                |
| **Paiements**                                      |                                                                                                                                   |
| `PaymentInProgress`                                | Un `pay()` précédent attend encore un résultat.                                                                                   |
| `CurrencyNotAvailableForMerchant(code)`            | Devise non configurée pour le commerçant.                                                                                         |
| `UnsupportedCurrency(code)`                        | Devise non reconnue par le SDK.                                                                                                   |
| `AmountBelowMinimum(minimum, currency)`            | Montant inférieur au minimum configuré.                                                                                           |
| `TransactionTimeoutOutOfRange(transactionTimeout)` | `transactionTimeout` hors de la plage de 0 à 120 secondes.                                                                        |
| `PaymentCreationFailed(cause)`                     | Tout autre échec lors de la création d’un paiement.                                                                               |
| `PaymentNotFound`                                  | Jeton de `status()`/`cancel()`/`refund()` inconnu du backend.                                                                     |
| **Localisation**                                   |                                                                                                                                   |
| `LocationPermissionRequired`                       | L’application hôte ne dispose pas de l’autorisation de localisation.                                                              |
| `LocationUnavailable`                              | Aucun fournisseur n’a pu déterminer la position.                                                                                  |
| `LocationTimeout`                                  | La position n’a pas été déterminée à temps.                                                                                       |
| **Plugin / terminal**                              |                                                                                                                                   |
| `PluginUnavailable`                                | Application plugin non installée, ou impossible de se lier à son service.                                                         |
| `PluginTimeout`                                    | Le plugin n’a pas répondu à temps.                                                                                                |
| `ActivationInProgress`                             | Un `activateTerminal()` précédent attend encore un résultat.                                                                      |
| `NoTidsAvailableForMerchant`                       | Le commerçant n’a plus de terminal (TID) non attribué à activer.                                                                  |
| `PluginAlreadyAuthenticated`                       | Plugin déjà authentifié pour ce commerçant.                                                                                       |
| `PluginMerchantMismatch`                           | Plugin authentifié pour un autre commerçant ; appelez d’abord `plugin.logout()`.                                                  |
| `PluginNotReadyForPayments(status)`                | `pay()` a été exécuté alors que le plugin n’était pas à l’état `PluginStatus.ReadyForPayments` ; `status` contient l’état actuel. |
| `MerchantOnboardingIncomplete(state)`              | Le commerçant n’a pas terminé l’onboarding.                                                                                       |
| **Système**                                        |                                                                                                                                   |
| `NoInternetConnection`                             | L’appareil n’a pas de connexion réseau.                                                                                           |
| `Unknown(cause)`                                   | Tout échec que le SDK ne reconnaît pas comme l’un des siens.                                                                      |

<Callout title="Résultat ou exception" type="info">
  Un paiement qui atteint le terminal mais n’aboutit pas n’est **pas** une exception ; il arrive sous forme de
  `PaymentEvent.Result` contenant `PayResult.Declined`, `Canceled` ou `Failed(reason)`. De même, l’activation
  du terminal renvoie `ActivateTerminalResult.Failed(reason)`.
</Callout>

### Gérer les exceptions [#handling-exceptions]

Encapsulez l’appel dans un `try`/`catch` et traitez séparément les cas que vous gérez, avec un catch générique en dernier recours.
Kotlin distingue les cas par sous-classe d’exception ; React Native vérifie avec `AcceptError.is()` puis fait un switch sur `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>

### Journalisation [#logging]

Activez la journalisation de débogage pendant le développement pour diagnostiquer les problèmes.

<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>

### Déconnexion [#logging-out]

Effacez tout l’état du SDK conservé localement (jeton d’authentification, identifiant de l’appareil, configuration en cache) et ramenez l’état du SDK à
*idle*. Appelez cette méthode lorsque l’utilisateur se déconnecte. Pour déconnecter également le commerçant de l’application Tapaya Terminal, appelez
d’abord `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>
