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

# iOS SDK (Swift)

> Integrate payment processing with physical terminals using the Terminal H2H SDK for iOS (Swift)

# Terminal H2H SDK for iOS (Swift)

The Terminal H2H SDK for iOS enables you to integrate secure payment processing directly into your iOS applications. Connect to physical payment terminals and process transactions seamlessly using our comprehensive Swift SDK.

<Info>
  This SDK works alongside the Terminal API to provide a complete in-person payment solution. You'll use the Terminal API to create payment sessions and the Terminal H2H SDK to interact with physical payment devices.
</Info>

## Version information

<AccordionGroup>
  <Accordion title="v1.2.0 — 8-May-2026">
    What's new:

    * **Core Stability**: Fixed activity tracking bug in TerminalApplication where paused activities were not properly removed from internal tracking list
  </Accordion>

  <Accordion title="v1.1.3 — 26-Apr-2026">
    What's new:

    * Fixed casting issue on C2C request payload to improve compatibility and prevent runtime errors.
  </Accordion>

  <Accordion title="v1.1.1 — 23-Apr-2026">
    What's new:

    * Added Cashup provider support for Indonesian terminals
  </Accordion>

  <Accordion title="View all versions">
    <Accordion title="v1.0.0 — 19-Feb-2026">
      What's new:

      * Renamed class name `TerminalGateway` to `TerminalH2H` for better consistency

      <Warning>
        **Breaking Change**: Class name changed from `TerminalGateway` to `TerminalH2H`. Update your imports and references accordingly.
      </Warning>
    </Accordion>

    <Accordion title="v0.7.0 — 5-Dec-2025">
      What's new:

      * Fixed NTT payment method value mapping to ensure correct provider selection
      * Updated BRI payment flow to validate transaction data before executing terminal actions
      * Added timeout configuration for card and QR transactions to auto-cancel and retry stalled requests
      * Added support to handle retry requests via <a href="/api-reference/payments-terminal-api/retry-terminal-payment-session">`/v1/terminal/sessions/{id}/retry`</a> endpoint
    </Accordion>

    <Accordion title="v0.6.0 — 20-Nov-2025">
      What's new:

      * Added support for multiple concurrent device connections, enabling simultaneous transactions across different terminals
      * \[BRI] Fixed status value handling in void and cancel API responses for improved transaction status accuracy
    </Accordion>

    <Accordion title="v0.5.0 — 30-Oct-2025">
      What's new:

      * Introduced command ID handling for settlement operations
      * Enhanced retry logic with configurable attempt counts
      * Improved error handling and logging throughout the gateway service
    </Accordion>

    <Accordion title="v0.4.1 — 7-Oct-2025">
      Bug fixes and improvements:

      * Fix data mapping for terminal responses
      * \[BRI] Enhanced status verification after transaction timeout for improved reliability
    </Accordion>

    <Accordion title="v0.4.0 — 13-May-2025">
      XenTerminal is the companion SDK to In-Person Payment Sessions API. This version provides core functionality for connecting to payment terminals and processing transactions.
    </Accordion>
  </Accordion>
</AccordionGroup>

<Note>
  The SDK follows semantic versioning. Breaking changes will bump the major version number.
</Note>

## Installation

Install the Terminal SDK using Swift Package Manager (SPM) in Xcode:

<Steps>
  <Step title="Open package dependencies in Xcode">
    In Xcode, open your project and choose **File → Add Package Dependencies...**.

    <Frame>
      <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/ios/add-package.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=9495dc9ef09827ebcfd84a9953c57a99" alt="Opening the Add Package Dependencies menu in Xcode" width="1084" height="608" data-path="images/ios/add-package.png" />
    </Frame>
  </Step>

  <Step title="Add Xendit package URL">
    Enter this repository URL in the package search field:

    ```text theme={null}
    https://github.com/xendit/xendit-terminal-ios
    ```

    Then click **Add Package**.
  </Step>

  <Step title="Select version and target">
    Choose your dependency rule (recommended: **Up to Next Major Version**) and make sure your app target is selected before confirming.
  </Step>

  <Step title="Configure build settings">
    Go to **Build Settings** and make the following changes:

    * Search for `ENABLE_USER_SCRIPT_SANDBOXING` and set it to `NO`
    * Search for `Other Linker Flags` and add `-lsqlite3`

    <Frame>
      <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/ios/enable-sandbox-no.png?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=7ddf005efb4ea0761bb51cc5f4e441d5" alt="Setting ENABLE_USER_SCRIPT_SANDBOXING to NO in Xcode Build Settings" width="1562" height="482" data-path="images/ios/enable-sandbox-no.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/ios/add-lsqlite3.png?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=7614cf23ace4156a7d06b98098c4110a" alt="Adding -lsqlite3 to Other Linker Flags in Xcode Build Settings" width="1588" height="858" data-path="images/ios/add-lsqlite3.png" />
    </Frame>
  </Step>
</Steps>

## Getting Started

Before starting, you'll need an In-Person Payment CLIENT\_KEY from the Xendit In-Person Payment team. You will also need the terminal <a href="#finding-terminal-information">IP address</a>.

<Warning>
  Terminal H2H requires physical payment devices to function. Contact the Xendit team to obtain compatible terminal devices and configuration details.
</Warning>

### Step 1: Initialize SDK

Import the SDK module and call `TerminalApp.shared.initialize` from your application entry point:

```swift AppDelegate.swift theme={null}
import TerminalH2H

TerminalApp.shared.initialize(
  clientKey: TEST_CLIENT_KEY,
  mode: TerminalMode.integration // switch to TerminalMode.live for production builds
)
```

The SDK supports two modes:

<Tabs>
  <Tab title="Integration Mode">
    Use `TerminalMode.integration` for development and testing with physical terminals. Transactions are sent to Test Mode on the Xendit Dashboard.
  </Tab>

  <Tab title="Live Mode">
    Use `TerminalMode.live` for production builds. Data is pushed to your Live Xendit Dashboard and requires a LIVE\_CLIENT\_KEY.
  </Tab>
</Tabs>

### Step 2: Add Terminal Providers

Add the specific terminal providers you need for your integration:

<Note>
  For Share Commerce (SHC), Cashup, and Atom terminals, you do not need to add a Terminal H2H provider. Those devices run terminal logic through the Gateway app installed on the hardware. If the app is missing, install it from the <a href="/sdk/gateway/app-configuration#download-the-app">Gateway download page</a> or contact <a href="mailto:inpersonpayments@xendit.co">[inpersonpayments@xendit.co](mailto:inpersonpayments@xendit.co)</a> for help.
</Note>

<Tabs>
  <Tab title="BRI Provider (Indonesia)">
    ```swift theme={null}
    // Add BRI provider for Indonesian terminals
    TerminalH2H.shared.addProvider(provider: TerminalBRI.shared)
    ```

    <Info>
      BRI provider supports timeout configuration for card and QR transactions, and provides enhanced transaction retry capabilities.
    </Info>
  </Tab>

  <Tab title="NTT Provider (Thailand)">
    ```swift theme={null}
    // Add NTT provider for Thai terminals
    TerminalH2H.shared.addProvider(provider: TerminalNTT.shared)
    ```

    <Info>
      NTT provider supports multi-function terminals with card payments and QR code transactions.
    </Info>
  </Tab>

  <Tab title="Cashup (Indonesia)">
    ```swift theme={null}
    // Cashup terminals use the Gateway app flow.
    // No TerminalH2H.shared.addProvider(...) call is required.
    ```

    <Info>
      Cashup terminals run terminal logic through the Gateway app on the device. Ensure the Gateway app is installed and your terminal is registered before processing payments.
    </Info>
  </Tab>

  <Tab title="Multiple Providers">
    ```swift theme={null}
    // Add multiple providers for supporting different terminal types
    TerminalH2H.shared.addProvider(provider: TerminalBRI.shared)
    TerminalH2H.shared.addProvider(provider: TerminalNTT.shared)
    ```

    <Warning>
      Only add providers for terminal types you actually plan to use. Each provider adds to your app's size and initialization time.
    </Warning>
  </Tab>
</Tabs>

<Check>
  After adding providers, they will be available for use when registering terminal devices in the next step.
</Check>

### Step 3: Register Terminal Device

Create terminal device entries using `TerminalDevice.companion.create` and register them with the gateway:

```swift theme={null}
let devices = [
  TerminalDevice.companion.create(id: "BRI12345", ipAddress: "192.168.1.10"),
  TerminalDevice.companion.create(id: "BRI67890", ipAddress: "192.168.1.11")
]

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

<Tip>
  For detailed instructions on finding <a href="#finding-terminal-information">Terminal ID</a> and <a href="#finding-terminal-information">IP address</a> for different terminal providers, see our [Finding Terminal Information guide](#finding-terminal-information).
</Tip>

### Step 4: Calling Terminal API

With Terminal H2H SDK configured, you can now process payments using the Terminal API. The SDK handles communication with physical terminals through the local gateway service.

```bash theme={null}
# Example: Create a payment session
curl -X POST 'https://terminal-dev.xendit.co/v1/terminal/sessions' \
  -u 'API_KEY:' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-key: unique-session-123' \
  -d '{
    "terminal_id": "TERMINAL_ID",
    "amount": 10000,
    "currency": "IDR",
    "external_id": "payment-123",
    "payment_method": "card"
  }'
```

<Info>
  For complete API documentation including request/response formats, error handling, and advanced features, see the [Terminal API (H2H)](/api-reference/terminal-api/introduction) documentation.
</Info>

<Tip>
  The Terminal H2H SDK automatically manages the connection to your registered terminal devices and handles communication protocols for different providers.
</Tip>

<Check>
  You're now ready to process payments using the Terminal H2H SDK integrated with Terminal API.
</Check>

## Optional Methods

### Set Operation Timeout

Configure the maximum allowed time for operations to complete before the service cancels and retries the transaction:

```swift theme={null}
TerminalH2H.shared.setOperationTimeout(minutes: 5) // default value is 5 minutes

// Set provider-specific timeouts
TerminalH2H.shared.setOperationTimeout(type: TimeoutType.card, minutes: 10)
TerminalH2H.shared.setOperationTimeout(type: TimeoutType.qr, minutes: 10)
```

### Restart Terminal Connection

Manage and restart terminal service connections:

<Tabs>
  <Tab title="Restart All Connections">
    Call the method without parameters to restart all connections and tasks:

    ```swift theme={null}
    // This restarts all connections
    TerminalH2H.shared.restart(terminalID: nil)
    ```
  </Tab>

  <Tab title="Restart Single Connection">
    Provide the <a href="#finding-terminal-information">terminal ID</a> to restart a specific terminal connection:

    ```swift theme={null}
    // This restarts the connection to a specific Terminal
    TerminalH2H.shared.restart(terminalID: TERMINAL_ID)
    ```
  </Tab>
</Tabs>

### Observing Connection State

Monitor Terminal connection status using the `observeEDCConnection` method:

```swift theme={null}
let device = TerminalDevice.companion.create(id: "BRI12345", ipAddress: "192.168.1.10")

TerminalH2H.shared.observeConnection(device: device) { state in
  // Handle connection state transitions
}
```

The SDK handles the following connection states:

| Code               | Description                                                     |
| ------------------ | --------------------------------------------------------------- |
| `connected`        | Device connected to Terminal                                    |
| `disconnected`     | Device disconnected to Terminal                                 |
| `unknown`          | When no connection has been established yet                     |
| `connecting`       | Device requesting connection to Terminal                        |
| `connectingFailed` | Device unable to connect with Terminal                          |
| `unsupported`      | Connection not supported                                        |
| `unreachable`      | Ping failed; gateway marks device unreachable until it recovers |

### Observing Error State

Monitor Terminal error states using the `observeError` method:

```swift theme={null}
TerminalH2H.shared.observeError { device, error in
  // Use device?.id to correlate errors with specific terminals
}
```

## Error Handling

### Error Data Structure

All errors returned by the Terminal H2H SDK follow this structure:

```swift theme={null}
struct TerminalError {
    let code: ErrorCode
    let message: String
}
```

### Error Codes Reference

| Error Code              | HTTP Status | Description                                                         |
| ----------------------- | ----------- | ------------------------------------------------------------------- |
| INVALID\_CREDENTIAL     | 401         | Provided credentials are invalid or expired                         |
| INVALID\_REQUEST        | 400         | Request format or parameters are invalid                            |
| INTERNAL\_SERVER\_ERROR | 500         | Server-side error occurred during processing                        |
| UNKNOWN\_ERROR          | -           | Unexpected error that does not map to a specific category           |
| KEY\_INVALID            | -1          | API key is invalid or not authorized                                |
| AUTHENTICATION\_FAILED  | -21         | Terminal authentication failed - verify terminal ID and credentials |
| FAILED\_TO\_CONNECT     | -4          | Unable to establish connection to terminal                          |
| NOT\_CONNECTED          | -3          | No active connection to any terminal device                         |
| TERMINAL\_BUSY          | -6          | Terminal is processing another transaction                          |
| SEND\_FAILED            | -2          | Failed to send data to the terminal device                          |
| UNSUPPORTED             | -5          | Operation or platform not supported                                 |
| ENCRYPTION\_FAILED      | -7          | Encryption key invalid or encryption process failed                 |
| DECLINED\_BY\_READER    | N/A         | Card or reader rejected the transaction; prompt customer to retry   |
| PAYMENT\_UNPAID         | N/A         | Payment still pending on terminal; confirm status before retrying   |
| DUPLICATED              | N/A         | Duplicate command detected; generate a new order ID before retrying |
| CANCELLED               | N/A         | Action cancelled on the terminal or by the operator                 |
| TIMEOUT                 | N/A         | Operation exceeded configured timeout window                        |
| NO\_DATA\_FOUND         | N/A         | Terminal cannot find the referenced transaction data                |
| TID\_NOT\_SET           | N/A         | Terminal ID is missing in the gateway configuration                 |
| TID\_NOT\_MATCH         | N/A         | Terminal ID does not match the registered device                    |

### Error Handling Best Practices

Implement comprehensive error handling for robust payment processing:

```swift theme={null}
func handleTerminalError(_ error: TerminalError?) {
  guard let error = error else { return }

  switch error.code {
  case ErrorCode.authenticationFailed:
    // Verify API key and <a href="#finding-terminal-information">terminal ID</a>
    print("Authentication failed: \(error.message)")
    // Show user-friendly message and retry with correct credentials
        
  case ErrorCode.terminalBusy:
    // Terminal is processing another transaction
    print("Terminal busy: \(error.message)")
    // Wait and retry after a delay
    retryAfterDelay(5.0) // 5 seconds
        
  case ErrorCode.failedToConnect, ErrorCode.notConnected:
    // Network connectivity issues
    print("Connection failed: \(error.message)")
    // Check network connection and terminal <a href="#finding-terminal-information">IP address</a>
    checkNetworkConnectivity()

  case ErrorCode.declinedByReader:
    // Terminal rejected the card tap/insert
    print("Declined by reader: \(error.message)")
    promptCustomerToRetry()

  case ErrorCode.paymentUnpaid:
    // Payment still pending on the terminal
    print("Payment unpaid: \(error.message)")
    confirmStatusWithBackend()

  case ErrorCode.timeout:
    // Gateway timed out while waiting for terminal response
    print("Command timeout: \(error.message)")
    TerminalH2H.shared.restart(terminalID: nil)

  case ErrorCode.duplicated:
    // Duplicate command detected by the gateway
    print("Duplicate command detected: \(error.message)")
    regenerateOrderID()
        
  case ErrorCode.keyInvalid, ErrorCode.invalidCredential:
    // Credential issues
    print("Invalid credentials: \(error.message)")
    // Rotate or refresh API credentials
    refreshCredentials()
        
  case ErrorCode.encryptionFailed:
    // Encryption key issues
    print("Encryption failed: \(error.message)")
    // Re-initialize SDK with correct encryption keys
    reinitializeSDK()

  case ErrorCode.cancelled:
    // Operator cancelled the command on the terminal
    print("Operation cancelled: \(error.message)")
    notifyCashier()
        
  default:
    // Log and escalate unknown errors
    print("Unknown error: \(error.message)")
    // Report to monitoring system
    reportError(error)
  }
}
```

<Tip>
  Always implement retry logic for transient errors like `TERMINAL_BUSY` and `FAILED_TO_CONNECT`. Use exponential backoff to avoid overwhelming the terminal.
</Tip>

## Troubleshooting

<Tip>
  For more recovery scenarios across H2H and C2C terminal flows, see the [SDK Troubleshooting Guide](/sdk/troubleshooting).
</Tip>

### Common Issues and Solutions

<AccordionGroup>
  <Accordion title="Unresponsive EDC Machine">
    **Problem**: The EDC (Electronic Data Capture) machine becomes unresponsive or stops processing transactions.

    **Solution**:

    1. Restart the EDC machine by holding the power button and selecting "Restart"
    2. Wait for the device to fully boot up and reconnect
    3. Verify the terminal is back online using the connection monitoring features

    <Warning>
      Always ensure the EDC is properly restarted before attempting new transactions to avoid data corruption.
    </Warning>
  </Accordion>

  <Accordion title="Kiosk Mode Configuration">
    **Problem**: Unexpected behaviors or unauthorized access to terminal functions.

    **Solution**:

    1. Ensure all transactions are initiated only through the SDK
    2. Contact the Xendit EDC team to enable POS-only mode for your <a href="#finding-terminal-information">Terminal IDs</a>
    3. Configure terminal settings to disable manual transaction entry

    <Tip>
      POS-only mode prevents manual transaction entry and ensures all operations go through your application.
    </Tip>
  </Accordion>

  <Accordion title="No Response After Payment Completion">
    **Problem**: EDC fails to send transaction results to the SDK after payment completion.

    **Solution**:

    1. Query the Payment Session using the Terminal API to retrieve the latest status
    2. Check network connectivity between the EDC and your application
    3. Verify the callback URL configuration in your payment session
    4. Implement retry logic for failed status updates

    ```swift theme={null}
    // Example: Query payment session status
    let paymentSession = terminalApi.getPaymentSession(sessionId)
    switch paymentSession.status {
    case PaymentStatus.completed:
        // Process successful payment
    case PaymentStatus.failed:
        // Handle failed payment
    case PaymentStatus.pending:
        // Payment still in progress
    }
    ```
  </Accordion>

  <Accordion title="Transaction Stuck or Missing Callback After Receipt Printed">
    **Problem**: Transaction appears stuck or you don't receive a callback after the terminal prints a receipt, indicating the transaction may be incomplete.

    <Note>
      This troubleshooting section applies only to BRI terminals.
    </Note>

    **Solution**:
    Call the Terminal API retry endpoint to request the app check the transaction status and redo the transaction if it's incomplete:

    ```swift theme={null}
    // Retry transaction via Terminal API
    let response = try await terminalApi.retrySession(sessionId: sessionId)
    // The app will check transaction status and redo if incomplete
    ```

    <Info>
      The retry endpoint <a href="/api-reference/payments-terminal-api/retry-terminal-payment-session">`/v1/terminal/sessions/{id}/retry`</a> instructs the app to verify the current transaction status with the terminal and automatically redo the transaction if it's found to be incomplete.
    </Info>

    <Tip>
      Use this retry mechanism when you see a receipt printed but haven't received a callback, as it may indicate the transaction didn't complete successfully on the terminal side.
    </Tip>
  </Accordion>

  <Accordion title="Connection Issues">
    **Problem**: Unable to establish or maintain connection with terminal devices.

    **Solutions**:

    * **Check network connectivity**: Ensure both devices are on the same network
    * **Verify IP addresses**: Confirm terminal <a href="#finding-terminal-information">IP addresses</a> are correct and accessible
    * **Firewall settings**: Check if firewall is blocking the connection ports
    * **Terminal status**: Ensure the terminal is powered on and in ready state
    * **SDK initialization**: Verify client key and terminal configuration

    <Note>
      Use the connection monitoring features to diagnose specific connection issues.
    </Note>
  </Accordion>
</AccordionGroup>

## Finding Terminal Information

<Tabs>
  <Tab title="BRI Terminals">
    <Steps>
      <Step title="Find Terminal ID (TID)">
        Open the BRI FMS app on the terminal device and locate the Terminal ID in the device information section.

        <Frame>
          <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/bri/bri-tid.png?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=60410d91d34e864135c485e6df2901a6" alt="BRI terminal showing Terminal ID in FMS app" width="450" height="885" data-path="images/bri/bri-tid.png" />
        </Frame>
      </Step>

      <Step title="Find IP Address">
        Open the ECRLink app on the terminal and check the network settings for the IP address.

        <Frame>
          <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/bri/bri-ip.png?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=34eeb360fc42d6c7ab5c633ba7a05371" alt="BRI terminal showing IP address in ECRLink app" width="480" height="878" data-path="images/bri/bri-ip.png" />
        </Frame>
      </Step>
    </Steps>
  </Tab>

  <Tab title="NTT Terminals">
    <Steps>
      <Step title="Find Terminal ID (TID)">
        Look for the Terminal ID on the physical sticker attached to the device.

        <Frame>
          <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/ghl/ghl-tid.jpg?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=88d3ff4da303a2d35eecd432ed4fa9c4" alt="NTT terminal showing Terminal ID sticker on device" width="3024" height="4032" data-path="images/ghl/ghl-tid.jpg" />
        </Frame>
      </Step>

      <Step title="Find IP Address">
        Open the NTT LinkPOS app on the terminal and navigate to network settings to find the IP address.

        <Frame>
          <img src="https://mintcdn.com/xendit/79NehsWB8-Vpp9n7/images/ghl/ghl-ip.jpg?fit=max&auto=format&n=79NehsWB8-Vpp9n7&q=85&s=e05ef6b97d190aa59206ef5842d9a4a8" alt="NTT terminal showing IP address in LinkPOS app" width="3024" height="4032" data-path="images/ghl/ghl-ip.jpg" />
        </Frame>
      </Step>
    </Steps>
  </Tab>

  <Tab title="Cashup Terminals">
    <Steps>
      <Step title="Find Terminal ID (TID)">
        Open the Cashlez app and navigate to the User Account tab to locate the Terminal ID.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/cashup/cashup-tid.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=d75858971855c6badc35155cf5d417b7" alt="Cashup terminal showing Terminal ID in User Account tab" width="720" height="1600" data-path="images/cashup/cashup-tid.png" />
        </Frame>
      </Step>

      <Step title="Find IP Address">
        Open the Terminal Gateway app and check the device list for the terminal IP address.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/app/gateway-app-ip-address.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=06041514d4322321d4522600a8cdd921" alt="Terminal Gateway app showing device IP address" width="717" height="535" data-path="images/app/gateway-app-ip-address.png" />
        </Frame>
      </Step>
    </Steps>
  </Tab>

  <Tab title="Share Commerce Terminals">
    <Steps>
      <Step title="Find Terminal ID (TID)">
        Open the Xendit app on the device and review the terminal details screen to locate the Terminal ID.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/shc/shc-tid.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=1944ce5df286baabbab4b40b561f6bac" alt="Share Commerce terminal showing Terminal ID in Xendit app" width="720" height="1280" data-path="images/shc/shc-tid.png" />
        </Frame>
      </Step>

      <Step title="Find IP Address">
        Open the Terminal Gateway app and check the device list for the terminal IP address.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/app/gateway-app-ip-address.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=06041514d4322321d4522600a8cdd921" alt="Terminal Gateway app showing device IP address" width="717" height="535" data-path="images/app/gateway-app-ip-address.png" />
        </Frame>
      </Step>
    </Steps>
  </Tab>

  <Tab title="Atom Terminals">
    <Steps>
      <Step title="Find Terminal ID (TID)">
        Open the payment app on the Atom terminal, then go to <strong>Settings</strong> → <strong>Device Info</strong> to view the Terminal ID.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/atom/atom-tid.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=1e1df9098f060068525d853b569a714b" alt="Atom terminal showing Terminal ID in device settings" width="720" height="1280" data-path="images/atom/atom-tid.png" />
        </Frame>
      </Step>

      <Step title="Find IP Address">
        Open the Terminal Gateway app and check the device list for the terminal IP address.

        <Frame>
          <img src="https://mintcdn.com/xendit/iTqGX9_7zwXBWkal/images/app/gateway-app-ip-address.png?fit=max&auto=format&n=iTqGX9_7zwXBWkal&q=85&s=06041514d4322321d4522600a8cdd921" alt="Terminal Gateway app showing device IP address" width="717" height="535" data-path="images/app/gateway-app-ip-address.png" />
        </Frame>
      </Step>
    </Steps>
  </Tab>
</Tabs>

<Note>
  Screenshots and UI layouts may vary by firmware or app version. Refer to the latest vendor documentation if the interface differs from these instructions.
</Note>
