> ## Documentation Index
> Fetch the complete documentation index at: https://terminal-docs.xendit.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Xen BRI SDK to Terminal H2H SDK

> Complete guide for migrating from Xen BRI SDK to Terminal H2H SDK with step-by-step instructions and code examples

This comprehensive guide walks you through migrating your Android application from the standalone Xen BRI SDK (version 0.3.1) to the new Terminal H2H SDK (version 0.4.0) and Terminal API (H2H) (version 0.4.1). The new architecture provides better integration with the Xendit In-Person Payment platform and supports multiple terminal providers.

<Info>
  This migration involves significant architectural changes. We recommend testing thoroughly in your development environment before deploying to production.
</Info>

## Overview of Changes

The new architecture separates the concerns of direct terminal communication (handled by the Terminal H2H SDK) and payment session management (handled by the Terminal API (H2H)). This provides a more unified approach for different terminal providers and better integration with the Xendit In-Person Payment platform.

**Key Changes:**

* **SDK Consolidation:** The `XenBriTerminal` SDK is replaced by the `Terminal H2H SDK`, which acts as a common interface for various terminal providers (e.g., `TerminalBRI`).
* **API for Payment Sessions:** Instead of direct `saleIntent` calls from the SDK, payment sessions are now managed via the Terminal API (H2H).
* **Simplified Connection Management:** Device registration and connection state observation are now handled more uniformly through `TerminalH2H`.
* **Unified Error Handling:** Error codes are standardized across the Terminal H2H SDK.

## Migration Steps

<Steps>
  <Step title="Update SDK Dependencies">
    Remove the old `Xen BRI SDK` dependency and add the new `Terminal H2H SDK` dependencies in your module's `build.gradle` file.

    **Old Dependency (to remove):**

    ```kotlin theme={null}
    implementation("co.xendit:xen_edc_sdk-android:0.3.0")
    ```

    **New Dependencies (to add):**

    ```kotlin theme={null}
    implementation("co.xendit.terminal:h2h-android:<latest_version>")
    implementation("co.xendit.terminal:core-android:<latest_version>")
    implementation("co.xendit.terminal:id-bri-android:<latest_version>") // For BRI terminals
    // If you support NTT, also add:
    // implementation("co.xendit.terminal:th-ntt-android:<latest_version>")
    ```

    Also, ensure your project's `build.gradle` or `settings.gradle` has the maven local repository:

    ```kotlin theme={null}
    repositories {
      ...
      maven("./repository") // in the project's settings.gradle, or
      // maven("../repository") // in project's build.gradle
      ...
    }
    ```
  </Step>

  <Step title="Initialize the SDK">
    The initialization process changes from `XenBriTerminal.initialize()` to `TerminalApp.initialize()` and `TerminalH2H.addProvider()`.

    **Old Initialization:**

    ```kotlin theme={null}
    override fun onCreate() {
        super.onCreate()
        XenBriTerminal.initialize(this, TEST_CLIENT_KEY,
            XenTerminalMode.INTEGRATION)
        // ...
    }
    ```

    **New Initialization:**

    ```kotlin theme={null}
    override fun onCreate() {
        super.onCreate()
          TerminalApp.initialize(this, TEST_CLIENT_KEY,
            TerminalMode.INTEGRATION) // Use TerminalMode from new SDK
          TerminalH2H.addProvider(TerminalBRI) // Add the BRI provider
          // If you support NTT, also add:
          // TerminalH2H.addProvider(TerminalNTT)
        // ...
    }
    ```

    <Note>
      **Credentials:** For this integration, `API_KEY` and `CLIENT_KEY` refer to the same credential from the Xendit In-Person Payment team. Use the same key when calling the Terminal API (H2H) and when initializing `TerminalApp`.
    </Note>

    <Note>
      **TerminalMode:** The `XenTerminalMode` enum is replaced by `TerminalMode`. Use `TerminalMode.INTEGRATION` for testing with physical terminals and `TerminalMode.LIVE` for production. `TerminalMode.SIMULATION` is no longer available directly in the `TerminalApp.initialize` method; instead, you would create payment sessions with appropriate simulation parameters via the Terminal API (H2H) if needed.
    </Note>
  </Step>

  <Step title="Register Terminal Devices">
    Instead of `XenBriTerminal.useWifi()` or `XenBriTerminal.useBluetooth()`, you now register devices using `TerminalH2H.registerDevices()`.

    **Old Device Connection (Example for WiFi):**

    ```kotlin theme={null}
    XenBriTerminal.useWifi(TID, "127.0.0.1")
    ```

    **New Device Registration:**

    ```kotlin theme={null}
    // Replace with your TID (Terminal ID) and IP address.
    val devices = listOf(
        TerminalDevice(id = Terminal_ID_1, ipAddress = Terminal_IP_1, active = true),
        TerminalDevice(id = Terminal_ID_2, ipAddress = Terminal_IP_2, active = true),
        TerminalDevice(id = Terminal_ID_3, ipAddress = Terminal_IP_3, active = true)
    )

    TerminalH2H.registerDevices(
        devices = devices,
        restart = true // restart to apply the refreshed list immediately
    )
    ```

    Registration errors (such as authentication failures) are emitted through `observeError`. For obtaining TID and IP address for BRI terminals, continue using the BRI FMS App for TID and the ECRLink app for IP address.
  </Step>

  <Step title="Create Payment Transactions">
    The `saleIntent` method is replaced by a two-step process:

    1. **Create a Payment Session via Terminal API (H2H):** Your backend (or a direct API call from your app if applicable) initiates a payment session with the Xendit's Payment Terminal API (H2H).
    2. **The SDK will then handle the interaction with the physical terminal** to process the payment based on the created session.

    **Old Payment Creation:**

    ```kotlin theme={null}
    val payment = PaymentIntentParametersBuilder(
        transactionId = "123456",
        amount = 1000,
        method = SaleMethod.PURCHASE // Or other SaleMethod enums
    ).build()
    XenBriTerminal.saleIntent(payment = payment) { result, error ->
        // handle result & error
    }
    ```

    **New Payment Creation (High-Level Flow):**

    1. **Your Application/Backend (using Terminal API (H2H)):**
       * Make a POST request to `/v1/terminal/sessions` to create a payment session.
       * **Endpoint:** `https://terminal-dev.xendit.co` (Development) or `https://terminal.xendit.co` (Live)
       * **Headers:**
         * `Content-Type: application/json`
         * `Authorization: Basic <Base64Encode(API_KEY:)>`
         * `Idempotency-key`: A unique key for preventing duplicate requests.
       * **Request Body Example:**

    ```json theme={null}
    {
      "reference_id": "your-transaction-ref-123",
      "session_type": "PAY",
      "country": "ID",
      "currency": "IDR",
      "amount": 10000,
      "mode": "TERMINAL",
      "channel_properties": {
        "terminal_id": "YOUR_TERMINAL_ID",
        "order_id": "your-order-id-abc", // Required for IDR
        "payment_methods": ["ID_INSERT_CARD"] // Or other valid methods
      },
      "description": "Payment for goods",
      "metadata": {
        "key": "value"
      }
    }
    ```

    * The API will return a `payment_session_id`. The Terminal H2H SDK on the terminal device, observing the commands from the API, will then initiate the payment process on the physical terminal.

    2. **Terminal H2H SDK (Observing Connection and Error States):**\
       The Terminal H2H SDK will automatically process the payment command received from the API for the registered terminal. Your app can observe the connection and error states to react to the payment flow.
  </Step>

  <Step title="Handle Optional Methods">
    The `Terminal H2H SDK` provides new methods for these operations, often correlating with the Terminal API (H2H)'s "Push Operation Command" functionality.

    ### Reprint Receipt

    **Old:**

    ```kotlin theme={null}
    XenBriTerminal.printReceiptIntent(result = result) { result, error ->
        // handle result & error
    }
    // or by using trace number
    XenBriTerminal.printReceiptIntent(method = SaleMethod.PURCHASE, traceNumber = "A001") { result, error ->
        // handle result & error
    }
    ```

    **New (using Terminal API (H2H)'s Push Operation Command - only supported for Indonesia's BRI terminals):**

    Your application/backend would make a POST request to `/v1/terminal/commands`.

    ```json theme={null}
    {
      "terminal_id": "YOUR_TERMINAL_ID",
      "command": "PRINT_RECEIPT",
      "payment_id": "OPTIONAL_PAYMENT_ID_TO_REPRINT_SPECIFIC_RECEIPT"
      // For reprint last, payment_id might be omitted based on API spec
    }
    ```

    The Terminal H2H SDK would then receive this command and execute the print operation.

    ### Settlement

    **Old:**

    ```kotlin theme={null}
    XenBriTerminal.settlementIntent(method = SaleMethod.PURCHASE) { result, error ->
        // handle result & error
    }
    ```

    **New (using Terminal API (H2H)'s Push Operation Command - only supported for Indonesia's BRI terminals):**

    Your application/backend would make a POST request to `/v1/terminal/commands`.

    ```json theme={null}
    {
      "terminal_id": "YOUR_TERMINAL_ID",
      "command": "SETTLE"
    }
    ```

    ### Cancel Payment (Void Transaction)

    **Old:**

    ```kotlin theme={null}
    XenBriTerminal.cancelPaymentIntent(result = result) { result, error ->
        // handle result & error
    }
    // or by using trace number
    XenBriTerminal.cancelPaymentIntent(method = SaleMethod.PURCHASE, traceNumber = "A001") { result, error ->
        // handle result & error
    }
    ```

    **New (using Terminal API (H2H)'s Void a Payment):**

    Your application/backend would make a POST request to `/v1/terminal/payments/:payment_id/void`.

    **Path:** `/v1/terminal/payments/:payment_id/void`\
    **Method:** POST\
    **Headers:**

    * `Content-Type: application/json`
    * `Authorization: Basic <Base64Encode(API_KEY:)>`

    The `payment_id` would be obtained from the response of the "Create Payment Session" or "Get Payment Session Detail" API calls.
  </Step>

  <Step title="Observe Connection and Error States">
    The methods for observing connection and error states have been updated in the Terminal H2H SDK.

    ### Observing Connection State

    **Old:**

    ```kotlin theme={null}
    XenBriTerminal.observeConnection(CoroutineScope(Dispatchers.IO)) { state ->
       // handle state event
    }
    // or, using flow
    val flow = XenBriTerminal.connectionState
    ```

    **New:**

    ```kotlin theme={null}
    TerminalH2H.observeConnection(
      CoroutineScope(Dispatchers.IO),
      terminalDevice // Pass the specific TerminalDevice instance
    ) { state ->
       // handle state event
    }
    // Or with Flow,
    val flow = terminalDevice.connectionState
    ```

    The connection states (`CONNECTED`, `DISCONNECTED`, `UNKNOWN`, `CONNECTING`, `CONNECTING_FAILED`, `UNSUPPORTED`, `UNREACHABLE`) are similar but are now part of `TerminalH2H` and tied to a specific `TerminalDevice`.

    ### Observing Error State

    **Old:** Error handling was integrated into the `saleIntent` callback.

    **New:** A dedicated `observeError` method is available.

    ```kotlin theme={null}
    TerminalH2H.observeError(
      CoroutineScope(Dispatchers.IO)
    ) { device, error ->
       // handle state event
    }
    // Or with Flow,
    val flow = TerminalH2H.errorState(terminalDevice)
    // or
    val flow = terminalDevice.error
    ```

    The `Error Data Structure` and `Error Codes` have been standardized and are detailed in the `Terminal H2H SDK for Android (Kotlin)` documentation. Review these to update your error handling logic accordingly.
  </Step>

  <Step title="Troubleshooting and Kiosk Mode">
    The troubleshooting section regarding "Unresponsive EDC Machine" and "No Response from SDK on EDC payment completion" remains relevant and similar in concept.

    For **Kiosk mode**, the recommendation to enable "POS only mode" by providing Terminal IDs to the Xendit EDC team remains valid. This ensures transactions are initiated via the SDK/API and not directly on the terminal.
  </Step>
</Steps>

## Summary of Key Changes for BRI Terminals

| Feature / Method         | Old Xen BRI SDK (0.3.1)                                                            | New Terminal H2H SDK (1.0.0) + Terminal API (H2H)                                                                                                                                                                         |
| :----------------------- | :--------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| SDK Dependency           | `implementation("co.xendit:xen_edc_sdk-android:0.3.0")`                            | `implementation("co.xendit.terminal:h2h-android:<latest_version>")`<br />`implementation("co.xendit.terminal:core-android:<latest_version>")`<br />`implementation("co.xendit.terminal:id-bri-android:<latest_version>")` |
| SDK Initialization       | `XenBriTerminal.initialize(context, CLIENT_KEY, XenTerminalMode.MODE)`             | `TerminalApp.initialize(context, CLIENT_KEY, TerminalMode.MODE)`<br />`TerminalH2H.addProvider(TerminalBRI)`                                                                                                              |
| Device Connection        | `XenBriTerminal.useWifi(TID, IP)`<br />`XenBriTerminal.useBluetooth(context, TID)` | `TerminalH2H.registerDevices(devices = listOf(TerminalDevice(id = TID, ipAddress = IP, active = true)), restart = true)`                                                                                                  |
| Create Payment           | `XenBriTerminal.saleIntent(...)`                                                   | **API Call:** `POST /v1/terminal/sessions` to create a payment session.<br />**SDK:** Handles the initiated session automatically.                                                                                        |
| Void Payment             | `XenBriTerminal.cancelPaymentIntent(...)`                                          | **API Call:** `POST /v1/terminal/payments/:payment_id/void`                                                                                                                                                               |
| Reprint Receipt          | `XenBriTerminal.printReceiptIntent(...)`                                           | **API Call:** `POST /v1/terminal/commands` with `command: PRINT_RECEIPT` (Indonesia only)                                                                                                                                 |
| Settlement               | `XenBriTerminal.settlementIntent(...)`                                             | **API Call:** `POST /v1/terminal/commands` with `command: SETTLE` (Indonesia only)                                                                                                                                        |
| Observe Connection State | `XenBriTerminal.observeConnection(...)`                                            | `TerminalH2H.observeConnection(..., terminalDevice)`                                                                                                                                                                      |
| Observe Error State      | Part of `saleIntent` callback                                                      | `TerminalH2H.observeError(...)`                                                                                                                                                                                           |
| Simulation Mode          | `XenTerminalMode.SIMULATION`                                                       | Not directly in `initialize`. Use Terminal API (H2H) for testing with real terminals in test mode.                                                                                                                        |

<Warning>
  This migration involves significant architectural changes. Make sure to test thoroughly in your development environment before deploying to production.
</Warning>

<Tip>
  For additional support during migration, contact the Xendit In-Person Payment team at [inpersonpayments@xendit.co](mailto:inpersonpayments@xendit.co).
</Tip>
