Init and connect

Initialize the SDK and connect the phone as a Tap to Pay reader.

1. Initialize the SDK

Call init() once, before mounting <LemonwayTerminalRoot>, for example at the top of your entry file.

import { LemonwayTerminal } from '@lemonway/terminal';

LemonwayTerminal.init({
  env: 'sandbox', // 'sandbox' | 'production'
  publicKey: 'pk_xxxxxxxxxxx',
  tokenProvider: () => myBackend.post('/terminal/connection-token'),
});
OptionRequiredDescription
envyessandbox or production. Must match your keys.
publicKeyyesYour public key (pk_…). init() rejects any other key, so a secret key can never end up in the app.
tokenProvideryesAsync function that calls your connection token endpoint. Resolves { secret, locationId, onBehalfOf }, or just the secret string.
shopIdnoYour shop id (sh_…). Attached to SDK diagnostics.
locationIdnoLocation (tml_…), if tokenProvider does not return it. Also settable with setLocationId().
onBehalfOfnoConnected account (acct_…), iPhone only, if tokenProvider does not return it.
logLevelnonone (default) or verbose for native debug logs.

init() throws a LemonwayTerminalError with code INVALID_CONFIG when an option is missing or invalid.

The SDK calls tokenProvider whenever it needs a connection token, and once before each connection to learn the location and the connected account. Values it returns override those passed to init(). If it fails, returns no secret or takes more than 15 seconds, the operation fails with CONNECTION_TOKEN_FAILED.


2. Mount LemonwayTerminalRoot

<LemonwayTerminalRoot> starts the terminal. Wrap every screen that uses the SDK:

import { LemonwayTerminalRoot } from '@lemonway/terminal';

export default function App() {
  return (
    <LemonwayTerminalRoot>
      <CheckoutScreen />
    </LemonwayTerminalRoot>
  );
}

When it mounts, it asks for the Android permissions, then initializes the terminal. It emits terminal.ready when done, or terminal.error when it fails.

🚧

Initialization failure

After terminal.error (for example, the merchant refused the location permission), every call throws INITIALIZATION_FAILED. Remount <LemonwayTerminalRoot> to retry, for example by changing its key.


3. Connect the phone

Once the terminal is ready, call connectTapToPay(). It discovers the phone and connects it as a Tap to Pay reader in one step, and resolves the connected reader.

import { useEffect, useState } from 'react';
import { LemonwayTerminal } from '@lemonway/terminal';

export function CheckoutScreen() {
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    const connect = () => {
      LemonwayTerminal.connectTapToPay()
        .then(() => setConnected(true))
        .catch((error) => showError(error.code, error.message));
    };
    const unsubscribe = LemonwayTerminal.on('terminal.ready', connect);
    // terminal.ready may have fired before this screen mounted
    if (LemonwayTerminal.isReady()) connect();
    return unsubscribe;
  }, []);

  // ...
}
  • Connect once and keep the connection between sales. Do not connect inside each payment.
  • If the connection drops, the SDK reconnects by itself: you receive reader.disconnected, then reader.connected.
  • On iPhone, the first connection shows Apple's Tap to Pay terms. A merchant admin accepts them once per account.
  • Call disconnectReader() when the merchant signs out. Update the UI when its promise resolves: reader.disconnected can arrive later.

To display the connection state, use status():

const { connectionStatus, connectedReader } = await LemonwayTerminal.status();
// connectionStatus: 'notConnected' | 'connecting' | 'connected' | ...
Advanced: discoverReaders() and connectReader()

connectTapToPay() covers every Tap to Pay case. The two-step API is still available:

await LemonwayTerminal.discoverReaders();
const [phone] = LemonwayTerminal.getDiscoveredReaders();
await LemonwayTerminal.connectReader(phone);

connectReader() throws INVALID_PARAMS if discoverReaders() was not called first.


Did this page help you?