# Getting Started

Learn how to integrate our SDK into your Android project by starting with the correct environment setup.

```admonition
icon: fas fa-video
title: Video Tutorial
content: |
    Prefer watching over reading? Check out our SDK integration videos:
    - [Add and Set-Up your SDK for Android using PosLink](https://www.youtube.com/watch?v=E-4q4BuHqEo&list=PLpW-6-ownc1_iSfEvp4TFk5J42J4QUYTk)
    - [Initiate Payment - PosLink Android SDK](https://www.youtube.com/watch?v=46KqFslO6gw&list=PLpW-6-ownc1_iSfEvp4TFk5J42J4QUYTk&index=2)
```

## Requirements

Our SDK is currently compatible with the following **minimum** versions:

| Component                 | Version(s) | Notes                                                         |
|---------------------------|------------|---------------------------------------------------------------|
| **minSdkVersion**         | 23         | If you need API 21 support, please contact us (see below how) |
| **compileSdkVersion**     | 37         |                                                               |
| **Android Gradle Plugin** | 8.13.2     | 8.13.2 or newer                                               |
| **Gradle**                | 8.13       |                                                               |
| **Kotlin**                | 2.3.0      | Required only if already using Kotlin                         |


### Using Older Versions?

If you're using older versions and cannot upgrade, please contact your partnership manager or email us at partnersupport@teya.com and make sure to include the below information.

- The current versions of your android tools (compile SDK, min SDK, AGP and Kotlin)
- Any more useful information for the reason for not upgrading to the supported versions.

Your input helps us better understand real-world constraints so we can keep improving accordingly.

## 1. Get the SDK

Make sure your `settings.gradle(.kts)` includes the appropriate repository:

```kotlin
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}
```

Then, to include our SDK in your Android project, add the dependency for your chosen API style to your `build.gradle(.kts)` file:

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        dependencies {
            // ...
            implementation("com.teya.epos:unified-sdk:<version>")
        }
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        dependencies {
            // ...
            implementation("com.teya.epos:unified-sdk-poslink-kt:<version>")
        }
        ```
```

Replacing `<version>` with this one:

[![Maven (stable)](https://img.shields.io/badge/dynamic/xml?label=maven-central&style=for-the-badge&color=rgb(222,224,99)&url=https%3A%2F%2Frepo1.maven.org%2Fmaven2%2Fcom%2Fteya%2Fepos%2Funified-sdk%2Fmaven-metadata.xml&query=%2F%2Fmetadata%2Fversioning%2Fversions%2Fversion%5Bnot(contains(text()%2C%27-%27))%5D%5Blast()%5D)](https://central.sonatype.com/artifact/com.teya.epos/unified-sdk)

## 2. Get Your Client Credentials

You will need your **Client ID** and **Client Secret**, which can be obtained from your developer portal. See [Setup & Authentication](/epos-sdk/setup-and-authentication#1-get-your-credentials) for what these credentials mean and where to get them.

## 3. Create the `TeyaPosLinkSDK` Instance

Initialize the SDK with your credentials and optional parameters:

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        val teyaPosLinkSDK = TeyaPosLinkSDK(
            isProductionEnv = false, // Set to true for production
            authConfig = PosLinkSDK.AuthConfig.Managed(
                clientId = "", // Replace with your Client ID
                clientSecret = "" // Replace with your Client Secret
            ),
            eposInstanceId = null, // Optional: identifier for your ePOS app instance
            logger = LoggerImpl()   // Optional: your custom logger implementation
        )
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        val teyaPosLinkSDK = initTeyaPosLinkSDK(
            authConfig = PosLinkAuthConfig.Managed(
                clientId = "", // Replace with your Client ID
                clientSecret = "" // Replace with your Client Secret
            ),
            isProductionEnv = false, // Set to true for production
            eposInstanceId = null, // Optional: identifier for your ePOS app instance
            logger = LoggerImpl()   // Optional: your custom logger implementation
        )
        ```

    tab:
      title: Java
      content:
        ```java
        // Create the authentication configuration
        PosLinkSDK.AuthConfig authConfig = new PosLinkSDK.AuthConfig.Managed(
                "", // Replace with your Client ID
                "" // Replace with your Client Secret
        );
        
        // Initialize the TeyaPosLinkSDK
        PosLinkSDK teyaPosLinkSDK = TeyaPosLinkSDK.init(
                authConfig, // Authentication config
                false, // isProductionEnv: set to true for production
                null, // Optional: ePOS instance ID
                new LoggerImpl() // Optional: your custom logger implementation
        );
        ```
```

```admonition
icon: fas fa-exclamation-triangle
content: |
    Make sure you are pointing to the **Development** environment when implementing the SDK. Only switch to **Production** once your integration is well tested
```

## 4. Add Custom Logging
To enable logging, you can pass a custom logger by implementing the Logger interface.

```tabs
    tab:
      title: Kotlin
      content:
        ```kotlin
        class LoggerImpl : Logger {
            override fun d(message: String) {
                Log.d("SDK", message)
            }
        
            override fun i(message: String) {
                Log.i("SDK", message)
            }
        
            override fun w(message: String) {
                Log.w("SDK", message)
            }
        
            override fun e(message: String) {
                Log.e("SDK", message)
            }
        }
        ```
    tab:
      title: Java
      content:
        ```java
        class LoggerImpl implements Logger {
            @Override
            public void d(@NonNull String message) {
                Log.d("SDK", message);
            }
        
            @Override
            public void i(@NonNull String message) {
                Log.i("SDK", message);
            }
        
            @Override
            public void w(@NonNull String message) {
                Log.w("SDK", message);
            }
        
            @Override
            public void e(@NonNull String message) {
                Log.e("SDK", message);
            }
        }
        ```
```

See [Debug, Info, Warning, Error](/epos-sdk/setup-and-authentication#managing-the-device-link-afterwards) for what each log level means.

## 5. Set up the SDK

Use `setup` to run the SDK's built-in authentication, store selection, and card machine selection UI (see [Setup & Authentication](/epos-sdk/setup-and-authentication) for what this covers). After successful setup, you can call functions on `transactionsApi` and `printingApi`.

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.setup(
            onFailure = {
                // Handle initialization failure
            },
            onSuccess = {
                // Initialization succeeded: you can now use the transactionsApi and printingApi APIs.

                teyaPosLinkSDK.transactionsApi. // Call functions on TeyaCommonTransactionsApi
                teyaPosLinkSDK.printingApi. // Call functions on TeyaCommonPrintingApi
            }
        )
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.setup()
            .onOk {
                // Setup succeeded: you can now use the transactions and printing APIs.

                teyaPosLinkSDK.transactions. // Call functions on PosLinkTransactions
                teyaPosLinkSDK.printing. // Call functions on TeyaPrinting
            }
            .onErr { failure ->
                // Handle setup failure - see PosLinkSetupFailure
                println("Setup failed: $failure ${failure.debugMessage}")
            }
        ```
    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.setup(
                failure -> {
                    // Handle initialization failure
                    return Unit.INSTANCE;
                },
                () -> {
                    // Initialization succeeded: you can now use the APIs.

                    teyaPosLinkSDK.getTransactionsApi(). // Call functions on TeyaCommonTransactionsApi
                    teyaPosLinkSDK.getPrintingApi(). // Call functions on TeyaCommonPrintingApi

                    return Unit.INSTANCE;
                }
        );
        ```
```

```admonition
icon: fas fa-warning-triangle
content: |
    This setup call is required every time you want to access the `TeyaCommonTransactionsApi` and `TeyaCommonPrintingApi`.
    If the user is already authenticated and linked, the SDK will skip any UI and automatically load credentials from disk.
```

## Managing the device link

### Set up without card machine linking

Use `setupAuthAndStore` to defer card machine selection (see [Setup & Authentication](/epos-sdk/setup-and-authentication#managing-the-device-link-afterwards)) and link one later with `linkTerminal`.

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.setupAuthAndStore(
            onFailure = {
                // Handle setup failure
            },
            onSuccess = {
                // Authentication and store linking succeeded.
                // Call linkTerminal before making payments.
            }
        )
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.setupAuthAndStore()
            .onOk {
                // Authentication and store linking succeeded.
                // Call linkTerminal before making payments.
            }
            .onErr { failure ->
                // Handle setup failure - see PosLinkSetupFailure
            }
        ```
    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.setupAuthAndStore(
                failure -> {
                    // Handle setup failure
                    return Unit.INSTANCE;
                },
                () -> {
                    // Authentication and store linking succeeded.
                    // Call linkTerminal before making payments.
                    return Unit.INSTANCE;
                }
        );
        ```
```

```admonition
icon: fas fa-info-circle
content: |
    After `setupAuthAndStore` succeeds, `linkedDeviceDetails` will be `null` (no terminal linked yet) but `linkedStore` will reflect the linked store.
    You must call `linkTerminal` before using `transactionsApi` or `printingApi`.
```

### Linked device details

To retrieve the currently linked device details, you can access the `LinkedDeviceDetails`, which contains the relevant information.

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.linkedDeviceDetails // non-null only when both store and terminal are linked
        teyaPosLinkSDK.linkedStore         // non-null when a store is linked
        teyaPosLinkSDK.linkedTerminal      // non-null when a terminal is linked
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.linkedStore.value    // non-null when a store is linked
        teyaPosLinkSDK.linkedTerminal.value // non-null when a terminal is linked

        teyaPosLinkSDK.linkedStore.collect { store ->
            // null until a store is linked, non-null afterwards
        }
        teyaPosLinkSDK.linkedTerminal.collect { terminal ->
            // null until a terminal is linked, non-null afterwards
        }
        ```
    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.getLinkedDeviceDetails(); // non-null only when both store and terminal are linked
        teyaPosLinkSDK.getLinkedStore();         // non-null when a store is linked
        teyaPosLinkSDK.getLinkedTerminal();      // non-null when a terminal is linked
        ```
```

The `LinkedDeviceDetails` contains information about your selected `Terminal` and `Store`. It is only non-null when both are linked.

```admonition
icon: fas fa-info-circle
content: |
    The coroutines API has no `linkedDeviceDetails`. Because `linkedStore` and `linkedTerminal` are `StateFlow`s you can observe them directly — the device is fully linked when both hold a non-null value.
```

### Get card machines

Retrieve the card machines for the currently linked store with `getTerminals`. Pass `forceRefresh = true` to bypass the cache and fetch from the network, or `forceRefresh = false` to use cached results.

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.getTerminals(
            forceRefresh = false,
            onFailure = { failure ->
                // Handle failure - check failure.reason and failure.debugErrorMessage
            },
            onSuccess = { terminals ->
                // list of terminals
            }
        )
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.getTerminals(forceRefresh = false)
            .onOk { terminals ->
                // list of terminals
            }
            .onErr {
                // Handle failure
            }
        ```

    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.getTerminals(
                failure -> {
                    // Handle failure - check failure.getReason() and failure.getDebugErrorMessage()
                    return Unit.INSTANCE;
                },
                terminals -> {
                    // list of terminals
                    return Unit.INSTANCE;
                },
                false // forceRefresh
        );
        ```
```

### Link card machine

Use `linkTerminal` to switch card machines (see [Setup & Authentication](/epos-sdk/setup-and-authentication#managing-the-device-link-afterwards)). Pass a specific card machine ID (e.g. one returned by `getTerminals`), or `null` to show the SDK's built-in selection UI.

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        // Option 1: Show the terminal selection UI
        teyaPosLinkSDK.linkTerminal(
            terminalId = null,
            onFailure = { failure ->
                // Handle failure - check failure.reason and failure.debugErrorMessage
            },
            onSuccess = { terminal ->
                // terminal - the newly linked terminal
            }
        )

        // Option 2: Link directly by terminal ID
        teyaPosLinkSDK.linkTerminal(
            terminalId = "terminal-id-from-getTerminals",
            onFailure = { failure ->
                // Handle failure
            },
            onSuccess = { terminal ->
                // terminal - the newly linked terminal
            }
        )
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        // Option 1: Show the terminal selection UI
        teyaPosLinkSDK.linkTerminal(terminalId = null)
            .onOk { terminal ->
                // terminal - the newly linked terminal
            }
            .onErr { failure ->
                println("Could not link terminal: $failure ${failure.debugMessage}")
            }

        // Option 2: Link directly by terminal ID
        teyaPosLinkSDK.linkTerminal(terminalId = "terminal-id-from-getTerminals")
            .onOk { terminal ->
                // terminal - the newly linked terminal
            }
            .onErr { failure ->
                // Handle failure
            }
        ```

    tab:
      title: Java
      content:
        ```java
        // Option 1: Show the terminal selection UI
        teyaPosLinkSDK.linkTerminal(
                null, // terminalId - null shows the selection UI
                terminal -> {
                    // terminal - the newly linked terminal
                    return Unit.INSTANCE;
                },
                failure -> {
                    // Handle failure - check failure.getReason() and failure.getDebugErrorMessage()
                    return Unit.INSTANCE;
                }
        );

        // Option 2: Link directly by terminal ID
        teyaPosLinkSDK.linkTerminal(
                "terminal-id-from-getTerminals",
                terminal -> {
                    // terminal - the newly linked terminal
                    return Unit.INSTANCE;
                },
                failure -> {
                    // Handle failure
                    return Unit.INSTANCE;
                }
        );
        ```
```

### Clearing auth and device details

`clearUserAuth` clears authentication and the device link (see [Setup & Authentication](/epos-sdk/setup-and-authentication#managing-the-device-link-afterwards)):

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.clearUserAuth()
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.clearUserAuth()
        ```
    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.clearUserAuth();
        ```
```

`clearDeviceLink` clears only the store and card machine link, preserving authentication:

```tabs
    tab:
      title: Kotlin (callbacks)
      content:
        ```kotlin
        teyaPosLinkSDK.clearDeviceLink()
        ```
    tab:
      title: Kotlin (coroutines)
      content:
        ```kotlin
        teyaPosLinkSDK.clearDeviceLink()
        ```
    tab:
      title: Java
      content:
        ```java
        teyaPosLinkSDK.clearDeviceLink();
        ```
```

```admonition
icon: fas fa-warning-triangle
title: Note
content: |
    After calling either `clearUserAuth` or `clearDeviceLink`, you must call `setup` again before performing any operations with the SDK.
```

## Sample app

A complete Android sample application demonstrating POSLink integration with the Teya Unified ePOS SDK. This app shows how to connect an Android ePOS application to a separate Teya payment card machine over the cloud.

```admonition
type: info
icon: fas fa-info-circle
content: This sample app is a reference implementation for learning and development purposes. It is not intended for production use.
```

[View on GitHub](https://github.com/teya-engineering/unified-epos-sdk/tree/main/android-samples/poslink/EposPosLinkExample)
