# Integration des mobilen SDK (/de/in-store/integration/sdk_integration)





Das Tapaya Accept SDK bettet die Verarbeitung von Kartenzahlungen direkt in Ihre App ein. Es steht für &#x2A;*Android
(Kotlin)** und für **React Native / Expo** zur Verfügung, und beide Varianten zielen auf Android-Geräte. Das React-Native-Paket ist ein
schlanker Wrapper um das Android SDK, daher sind die unten beschriebenen Schnittstellen, Typen und Fehlerfälle in beiden Varianten gleich.

Jedes Codebeispiel auf dieser Seite ist nach Sprache in Tabs gegliedert. Wählen Sie eine Sprache aus, und die gesamte Seite passt sich an.

## 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:** Fügen Sie die Abhängigkeit zur `build.gradle.kts` auf Modulebene hinzu und synchronisieren Sie dann das Projekt.

**React Native:** Installieren Sie das Paket mit `npx expo install @tapayadot/accept-react-native`, fügen Sie das Config-Plugin wie
gezeigt hinzu, erzeugen Sie dann das native Projekt mit `npx expo prebuild --clean` neu und starten Sie es mit
`npx expo run:android`.

## Initialisierung [#initialization]

`Accept` ist der Einstiegspunkt für alle Funktionen des SDK. Initialisieren Sie es einmal beim Start der App (unter Android
typischerweise in Ihrer `Application`-Klasse) und authentifizieren Sie sich anschließend separat mit einem Händler-Token.

### Schritt 1: Initialisieren [#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>

Unter React Native gibt es keinen `context`; das native Modul hält ihn für Sie.

### Schritt 2: Authentifizieren [#step-2-authenticate]

Rufen Sie nach der Initialisierung `Accept.auth.authenticate()` auf, um einen Händler mit einem Token anzumelden, das Sie von Ihrem
Backend erhalten. Der Aufruf ist asynchron und schlägt mit einem SDK-Fehler fehl. Bei Erfolg wechselt der SDK-Zustand zu *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>

Beobachten Sie den Lebenszyklus, um auf diese Übergänge zu reagieren: `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>

## Grundkonzepte [#core-concepts]

Das Objekt `Accept` stellt das SDK über einige wenige Schnittstellen bereit:

| Schnittstelle     | Zweck                                                                                                              |
| :---------------- | :----------------------------------------------------------------------------------------------------------------- |
| `Accept.auth`     | Authentifizierung einer Händler-Session.                                                                           |
| `Accept.merchant` | Händlerprofil, Konfiguration, Onboarding-Status.                                                                   |
| `Accept.payments` | Erstellung und Verwaltung von Kartenzahlungen.                                                                     |
| `Accept.plugin`   | Installation und Aktivierung des Terminals (Plugin-App).                                                           |
| `Accept.displays` | Informationen zu den Displays des Geräts für beidseitige Terminals („double-sided“).                               |
| `Accept.sdk`      | SDK-Version, Umgebung, Geräte-ID, Mindestbeträge.                                                                  |
| `Accept.state`    | Lebenszyklus-Zustand: `StateFlow<SdkState>` unter Kotlin, ein Getter plus `addStateListener()` unter React Native. |

### Zahlung annehmen [#taking-a-payment]

Rufen Sie `Accept.payments.pay()` mit dem Betrag (in der kleinsten Einheit der Währung) und einem Währungscode nach ISO 4217 auf und
beobachten Sie dann den Strom von `PaymentEvent`s, den die Methode meldet: zuerst den Fortschritt, dann das endgültige Ergebnis. `pay()` wirft
nie eine Exception; ein Fehler beim Erstellen der Zahlung kommt stattdessen als Ereignis `CreationFailed` an.

Unterschiedlich ist nur, wie Sie diesen Strom beobachten: Kotlin gibt einen `Flow<PaymentEvent>` zurück, den Sie
in einer Coroutine sammeln, während React Native einen Listener entgegennimmt und ein Abonnement zurückgibt, das Sie mit `remove()` beenden können.

`amount` und `currency` sind erforderlich. Die optionalen Parameter (`paymentToken`, `receiptConfig`, `nfcPosition`,
`metadata`, `tip`, `transactionTimeout`, `display`) finden Sie unter [Zahlung erstellen](./card_terminal#create-a-payment).

<Callout title="Unter React Native" type="info">
  Dieselben Parameter werden als ein einzelnes `PaymentRequest`-Objekt übergeben, `pay({ amount, currency, tip, … })`, mit
  `number` anstelle von `Long` und `Record<string, string>` anstelle von `Map<String, String>`. Eine Umbenennung: Das
  Timeout heißt `transactionTimeoutMs` und erwartet einfache Millisekunden (`0`…`120000`) statt einer `Duration`.
</Callout>

<div className="bg-background relative h-auto w-full overflow-hidden rounded-lg border px-10">
    <img alt="Zahlungsablauf" 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>

Das abschließende Ergebnisereignis enthält ein `PayResult`: Erfolg (mit `paymentToken`, `metadata`, `authCode`,
`receiptDetails`), Ablehnung (`metadata`, `receiptDetails`), Abbruch (`metadata`) oder Fehlschlag (`reason`,
`metadata`). Kotlin bildet diese als Unterklassen `PayResult.Success` / `Declined` / `Canceled` / `Failed` ab,
React Native als Discriminated Union, in der Sie mit `payResult.type === 'success'` verzweigen. Die vollständige
Aufschlüsselung finden Sie unter [Ergebnis der Zahlung](./card_terminal#payment-outcome). Fragen Sie eine Zahlung später mit
`Accept.payments.status(paymentToken)` ab, stoppen Sie sie mit `Accept.payments.cancel(paymentToken)` oder erstatten Sie sie mit
`Accept.payments.refund(paymentToken, reason)`.

#### Nur das Ergebnis (React Native) [#just-the-outcome-react-native]

Wenn Ihre Oberfläche die Zwischenzustände nicht darstellt, reduziert `payAsync()` den gesamten Strom auf sein abschließendes
`PayResult`; das Promise wird mit einem `AcceptError` zurückgewiesen (rejected), wenn `pay()` den Fall als
`creationFailed` gemeldet hätte. Unter Kotlin gibt es kein Gegenstück; sammeln Sie dort den `Flow` oder verwenden Sie nur sein letztes Ereignis.

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

## Händler- und SDK-Informationen [#merchant--sdk-info]

`Accept.merchant` stellt das Profil und die Zahlungskonfiguration des angemeldeten Händlers bereit. `Accept.sdk` liefert
Angaben zum SDK-Build und zu diesem Gerät. Jedes der unten aufgeführten Member setzt zuvor `Accept.initialize()` voraus (außer
`Accept.sdk.version`), und alles auf `Accept.merchant` erfordert zusätzlich ein abgeschlossenes
`Accept.auth.authenticate()`, andernfalls wirft der Aufruf `NotInitialized` oder `NotAuthenticated`.

### Händler [#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>

| Member                  | Rückgabe               | Beschreibung                                                                                        |
| :---------------------- | :--------------------- | :-------------------------------------------------------------------------------------------------- |
| `info()`                | `MerchantInformation?` | Das registrierte Unternehmensprofil des Händlers. `null`, wenn das Profil noch nicht verfügbar ist. |
| `config()`              | `MerchantConfig`       | Die Zahlungskonfiguration des Händlers.                                                             |
| `availableCurrencies()` | `List<String>`         | ISO-4217-Codes, die der Händler akzeptieren kann. Kurzform für `config().availableCurrencies`.      |
| `onboardingStatus()`    | `OnboardingStatus`     | Ob der Händler bereits Zahlungen annehmen darf.                                                     |

Alle vier sind `suspend` und werfen bei einem Fehler `NotAuthenticated`, `NoInternetConnection` oder `Unknown`.

**`MerchantInformation`** enthält das registrierte Unternehmensprofil. Immer vorhanden: `merchantId` (`UUID`),
`email`, `businessType` (`BusinessType`), `legalName`, `registrationNumber`, `mcc` und die registrierte Adresse
(`addressLine1`, `city`, `country`). Optional (`null`, sofern der Händler sie nicht angegeben hat): `vatNumber`,
`incorporationDate`, `addressLine2`, `postalCode`, `state`, `phone`, `averageItemValue`,
`expectedMonthlyTurnover`, `businessModelDescription`, `numberOfEmployees`, `annualTurnover`,
`balanceSheetTotal`, `statementDescriptor`, `termsVersion`.

`BusinessType` ist einer der Werte `INDIVIDUAL`, `COMPANY`, `NONPROFIT_ORGANIZATION`, `GOVERNMENT_ENTITY` oder
`PARTNERSHIP`.

**`MerchantConfig`** enthält `availableCurrencies: List<String>` und die Standardwährung des Händlers `currency: String?`.

**`OnboardingStatus`** ist ein Sealed Interface: entweder `ReadyForPayments` oder `RequiresAction(state)`, wobei
`state` ein `OnboardingState` ist: `NOT_STARTED`, `PENDING`, `ACTIVE`, `ATTENTION_NEEDED`, `ACTION_REQUIRED`,
`BLOCKED`, `WAITING_FOR_KYB`, `WAITING_FOR_STAKEHOLDERS` oder `PENDING_ACQUIRER_APPROVAL`. Was die einzelnen Zustände
bedeuten, erfahren Sie unter [Händler-Onboarding](/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>

| Member             | Rückgabe              | Beschreibung                                                                                                                                                                          |
| :----------------- | :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `version`          | `String`              | Die Version des SDK. Schon vor `initialize()` lesbar.                                                                                                                                 |
| `isProduction`     | `Boolean`             | Ob `initialize()` auf die Produktion (`true`) oder die Sandbox (`false`) ausgerichtet wurde.                                                                                          |
| `deviceId()`       | `String?`             | Die stabile ID dieses Geräts, vergeben beim ersten erfolgreichen `authenticate()` und beibehalten, bis die App deinstalliert wird. Davor `null`. Geben Sie sie in Supportanfragen an. |
| `minimumAmounts()` | `List<MinimumAmount>` | Der zahlbare Mindestbetrag je unterstützter Währung. Jeder Eintrag ist `currency: String, amount: Long` in der kleinsten Einheit der Währung.                                         |

## Plugin-App [#plugin-app]

Jede Kartenzahlung wird an **Tapaya Terminal** übergeben, die Plugin-App von Tapaya; sie ist immer erforderlich, es gibt
keinen Weg für Kartenzahlungen, der sie umgeht. Prüfen Sie, ob sie installiert ist, und aktivieren Sie dann das Terminal, oder öffnen Sie den Store-Eintrag,
damit der Händler sie installieren kann.

Verwenden Sie dafür `Accept.plugin.isInstalled()`, `Accept.plugin.activateTerminal()` und `Accept.plugin.install()`. Den Code und alle
möglichen Ergebnisse der Aktivierung finden Sie unter [Terminal installieren und aktivieren](./card_terminal#install-and-activate-the-terminal).

Den aktuellen Zustand des Plugins lesen Sie mit `Accept.plugin.status()` aus, und mit
`Accept.plugin.logout()` melden Sie den Händler vom Plugin ab.

## Berechtigungen [#permissions]

Für Kartenzahlungen muss die Host-App die Standortberechtigung (`ACCESS_FINE_LOCATION`) besitzen. Das SDK
fordert sie nicht für Sie an; erteilen Sie sie mit den Standard-APIs für Android-Berechtigungen, bevor Sie `pay()` aufrufen.

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

Fehlt der Standort oder lässt er sich nicht ermitteln, wenn `pay()` ausgeführt wird, gibt der Ablauf `PaymentEvent.CreationFailed`
mit `LocationPermissionRequired`, `LocationUnavailable` oder `LocationTimeout` als Ursache aus.

## Fehlerbehandlung [#error-handling]

Jeder vom SDK gemeldete Fehler trägt einen der unten aufgeführten Namen. Unter Kotlin ist jeder davon eine Unterklasse der Sealed Class
`AcceptException`; unter React Native handelt es sich immer um eine einzige Klasse `AcceptError`, deren `code` den Namen enthält, und die
Payload-Felder (`minimum`, `currency`, `state`, …) hängen direkt am selben Objekt.

Die asynchronen Aufrufe (`authenticate`, `merchant.*`, `payments.status`/`cancel`/`refund`,
`plugin.activateTerminal`/`status`/`logout`/`updateInfo`, `clear`) schlagen mit einem davon fehl. `payments.pay()` ist die
Ausnahme: Es wirft nie, sondern meldet dieselben Fehler als Ereignis `CreationFailed` mit der Ursache.

### Exception-Typen [#exception-types]

| Exception                                          | Beschreibung                                                                                                                                       |
| :------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Lebenszyklus**                                   |                                                                                                                                                    |
| `NotInitialized`                                   | Ein Aufruf erfordert zuvor `Accept.initialize()`.                                                                                                  |
| `NotAuthenticated`                                 | Ein Aufruf erfordert zuvor `Accept.auth.authenticate()`.                                                                                           |
| `SessionExpired`                                   | Die authentifizierte Session ist abgelaufen; authentifizieren Sie sich erneut.                                                                     |
| `UnknownEnvironment(key)`                          | Umgebungsschlüssel nicht erkannt (interne Überladung von initialize).                                                                              |
| **Zahlungen**                                      |                                                                                                                                                    |
| `PaymentInProgress`                                | Ein vorheriges `pay()` wartet noch auf ein Ergebnis.                                                                                               |
| `CurrencyNotAvailableForMerchant(code)`            | Die Währung ist für den Händler nicht konfiguriert.                                                                                                |
| `UnsupportedCurrency(code)`                        | Die Währung wird vom SDK nicht erkannt.                                                                                                            |
| `AmountBelowMinimum(minimum, currency)`            | Der Betrag liegt unter dem konfigurierten Minimum.                                                                                                 |
| `TransactionTimeoutOutOfRange(transactionTimeout)` | `transactionTimeout` liegt außerhalb des Bereichs von 0 bis 120 Sekunden.                                                                          |
| `PaymentCreationFailed(cause)`                     | Jeder andere Fehler beim Erstellen einer Zahlung.                                                                                                  |
| `PaymentNotFound`                                  | Das Token für `status()`/`cancel()`/`refund()` ist dem Backend unbekannt.                                                                          |
| **Standort**                                       |                                                                                                                                                    |
| `LocationPermissionRequired`                       | Der Host-App fehlt die Standortberechtigung.                                                                                                       |
| `LocationUnavailable`                              | Kein Anbieter konnte eine Standortbestimmung liefern.                                                                                              |
| `LocationTimeout`                                  | Der Standort wurde nicht rechtzeitig ermittelt.                                                                                                    |
| **Plugin / Terminal**                              |                                                                                                                                                    |
| `PluginUnavailable`                                | Die Plugin-App ist nicht installiert, oder ihr Dienst konnte nicht gebunden werden.                                                                |
| `PluginTimeout`                                    | Das Plugin hat nicht rechtzeitig geantwortet.                                                                                                      |
| `ActivationInProgress`                             | Ein vorheriges `activateTerminal()` wartet noch auf ein Ergebnis.                                                                                  |
| `NoTidsAvailableForMerchant`                       | Der Händler hat kein nicht zugewiesenes Terminal (TID) mehr, das aktiviert werden könnte.                                                          |
| `PluginAlreadyAuthenticated`                       | Das Plugin ist für diesen Händler bereits authentifiziert.                                                                                         |
| `PluginMerchantMismatch`                           | Das Plugin ist unter einem anderen Händler authentifiziert; rufen Sie zuerst `plugin.logout()` auf.                                                |
| `PluginNotReadyForPayments(status)`                | `pay()` wurde ausgeführt, während sich das Plugin nicht im Zustand `PluginStatus.ReadyForPayments` befand; `status` enthält den aktuellen Zustand. |
| `MerchantOnboardingIncomplete(state)`              | Der Händler hat das Onboarding nicht abgeschlossen.                                                                                                |
| **System**                                         |                                                                                                                                                    |
| `NoInternetConnection`                             | Das Gerät hat keine Netzwerkverbindung.                                                                                                            |
| `Unknown(cause)`                                   | Jeder Fehler, den das SDK nicht als einen seiner eigenen erkennt.                                                                                  |

<Callout title="Ergebnis vs. Exception" type="info">
  Eine Zahlung, die das Terminal erreicht, aber nicht erfolgreich ist, ist **keine** Exception; sie kommt als
  `PaymentEvent.Result` mit `PayResult.Declined`, `Canceled` oder `Failed(reason)` an. Ebenso meldet die
  Aktivierung des Terminals `ActivateTerminalResult.Failed(reason)`.
</Callout>

### Exceptions behandeln [#handling-exceptions]

Umschließen Sie den Aufruf mit `try`/`catch` und verzweigen Sie nach den konkreten Fällen, die Sie behandeln, mit einem allgemeinen catch als Rückfallebene.
Kotlin verzweigt nach der Exception-Unterklasse; React Native prüft mit `AcceptError.is()` und verzweigt per switch nach `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]

Aktivieren Sie während der Entwicklung das Debug-Logging, um Probleme zu beheben.

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

### Abmelden [#logging-out]

Löschen Sie den gesamten lokal gespeicherten SDK-Zustand (Auth-Token, Geräte-ID, zwischengespeicherte Konfiguration) und setzen Sie den SDK-Zustand auf
*idle* zurück. Rufen Sie dies auf, wenn sich der Benutzer abmeldet. Um den Händler auch von der App Tapaya Terminal abzumelden, rufen Sie
zuerst `Accept.plugin.logout()` auf.

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