# GlomoPay React Native SDK v3 (Archived)

> **Archived** - This documentation is for React Native SDK **v3.x**. v3 is no longer the latest version.
For the latest version, see [React Native SDK v4](/product-guide/sdk/react-native-sdk/v4).
To upgrade, see the [Migration Guide](/product-guide/sdk/react-native-sdk/migration).


Official React Native SDK for integrating GlomoPay payment checkout flows into your mobile applications.

## Prerequisites

Before using this SDK, you need:

- API credentials (Public Key) from your GlomoPay dashboard
- An order ID created via the GlomoPay API (or a subscription ID for subscription payments)


## System Requirements

| Requirement | Version |
|  --- | --- |
| Node.js | >= 16.0.0 |
| npm | >= 8.0.0 |
| React | >= 17.0.0 |
| React Native | >= 0.68.0 |
| react-native-webview | ^13.0.0 |
| jail-monkey (optional) | ^2.6.0 |


## Installation

### React Native CLI

```bash
npm install @glomopay/react-native-sdk@3.1.0 react-native-webview
cd ios && pod install
```

### Expo

```bash
npx expo install @glomopay/react-native-sdk@3.1.0 react-native-webview
```

### Recommended: Device Security Compliance

For rooted/jailbroken device detection (strongly recommended for regulated flows):

```bash
npm install jail-monkey
```

The SDK works without `jail-monkey`, but installing it enables automatic device security checks. Without it, the SDK logs a warning on every `start()` call.

## Quick Start

```tsx
import React, { useRef } from "react";
import { View, Button } from "react-native";
import {
  GlomoCheckout,
  type GlomoCheckoutRef,
  type GlomoCheckoutPayload,
  type SdkError,
} from "@glomopay/react-native-sdk";

export default function PaymentScreen() {
  const checkoutRef = useRef<GlomoCheckoutRef>(null);

  const handlePay = async () => {
    const started = await checkoutRef.current?.start();
    if (!started) {
      console.log("Checkout could not start - check onSdkError for details");
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <Button title="Pay Now" onPress={handlePay} />

      <GlomoCheckout
        ref={checkoutRef}
        publicKey="live_pk_abc123"
        orderId="order_xyz789"
        onPaymentSuccess={(payload: GlomoCheckoutPayload) => {
          console.log("Payment success:", payload.paymentId);
        }}
        onPaymentFailure={(payload: GlomoCheckoutPayload) => {
          console.log("Payment failed:", payload.paymentId);
        }}
        onPaymentTerminate={() => {
          console.log("User dismissed checkout");
        }}
        onConnectionError={(error) => {
          console.log("Connection error:", error);
        }}
        onBankTransferSubmitted={(payload) => {
          console.log("Bank transfer submitted:", payload?.transactionReference);
        }}
        onPayViaBankCompleted={(payload) => {
          console.log("Pay via bank completed:", payload.status);
        }}
        onPayViaBankBankConnectionSuccessful={(payload) => {
          console.log("Bank connected:", payload?.bankName);
        }}
        onUserRefusedCameraPermissions={() => {
          console.log("User refused camera - cannot proceed with bank authentication");
        }}
        onSdkError={(errors: SdkError[]) => {
          errors.forEach((e) => console.error(e.type, e.message, e.field));
        }}
      />
    </View>
  );
}
```

## Subscriptions Checkout

To process subscription payments, pass a `subscriptionId` instead of an `orderId`:

```tsx
<GlomoCheckout
  ref={checkoutRef}
  publicKey="live_pk_abc123"
  subscriptionId="sub_xyz789"
  onPaymentSuccess={(payload) => {
    console.log("Subscription payment success:", payload.paymentId);
  }}
  onPaymentFailure={(payload) => {
    console.log("Subscription payment failed:", payload.paymentId);
  }}
  onSdkError={(errors) => {
    errors.forEach((e) => console.error(e.type, e.message));
  }}
/>
```

When `subscriptionId` is provided:

- The SDK skips order type detection (no API call)
- The `subscriptionId` must start with `sub_`
- Bank transfer callbacks (`onBankTransferSubmitted`, `onPayViaBankCompleted`) are not applicable - subscriptions are card-only
- Do not pass both `orderId` and `subscriptionId` - the SDK will fire `onSdkError`
- The `detecting_order_type` status is not emitted for subscription flows


## Features

- **Cross-platform** - works on both iOS and Android
- **TypeScript** - full type definitions for all exports
- **Unified checkout** - renders the correct checkout flow automatically based on your order
- **Bank transfer support** - callback for bank transfer submission events
- **Pay via bank** - bank payment flow completion and connection callbacks
- **Camera permissions** - built-in handling for bank authentication
- **Device security** - optional **(but strongly recommended)** `jail-monkey` integration for rooted/jailbroken device detection
- **Input validation** - publicKey and orderId format enforcement before checkout starts
- **Mock mode** - test with `test_` / `mock_` prefixed keys without hitting production


## API Reference

### GlomoCheckout Component

The unified checkout component. Place it in your render tree and control it via a ref.

```tsx
<GlomoCheckout ref={checkoutRef} {...props} />
```

#### Props (`GlomoCheckoutProps`)

| Prop | Type | Required | Description |
|  --- | --- | --- | --- |
| `publicKey` | `string` | Yes | Your GlomoPay public key (must start with `live_`, `mock_`, or `test_`) |
| `orderId` | `string` | No* | Order ID from the GlomoPay API (must start with `order_`) |
| `subscriptionId` | `string` | No* | Subscription ID (must start with `sub_`). Bypasses order type detection. |
| `onPaymentSuccess` | `(payload: GlomoCheckoutPayload) => void` | Yes | Called when payment succeeds |
| `onPaymentFailure` | `(payload: GlomoCheckoutPayload) => void` | Yes | Called when payment fails |
| `onConnectionError` | `(error: unknown) => void` | No | Called on network/connection errors |
| `onPaymentTerminate` | `() => void` | No | Called when user dismisses checkout (back button or swipe) |
| `onSdkError` | `(errors: SdkError[]) => void` | No | Called on validation errors or device compliance failures |
| `onBankTransferSubmitted` | `(payload: GlomoBankTransferPayload | null | undefined) => void` | No | Called when user submits bank transfer details |
| `onPayViaBankCompleted` | `(payload: { status: string }) => void` | No | Called when pay via bank flow completes |
| `onPayViaBankBankConnectionSuccessful` | `(payload: GlomoPayViaBankConnectionPayload | null | undefined) => void` | No | Called when bank connection is established during pay via bank flow |
| `onUserRefusedCameraPermissions` | `() => void` | No | Called when user denies camera access needed for bank authentication |


*Exactly one of `orderId` or `subscriptionId` must be provided. If both or neither are set, `onSdkError` fires and `start()` returns `false`.

#### Ref Methods (`GlomoCheckoutRef`)

| Method | Signature | Description |
|  --- | --- | --- |
| `start()` | `() => Promise<boolean>` | Validates inputs, and opens the checkout modal. Resolves `true` if successful, `false` otherwise. |
| `getStatus()` | `() => CheckoutStatus` | Returns the current checkout status. |


#### CheckoutStatus

| Status | Description |
|  --- | --- |
| `ready` | Initial state - checkout can be started |
| `detecting_order_type` | Order type detection in progress (after `start()`, before checkout opens) |
| `payment_in_progress` | Checkout modal is open, user is interacting |
| `payment_successful` | Payment completed successfully. Cannot restart with same order |
| `payment_failed` | Payment failed. Can retry with same order |
| `payment_cancelled` | User dismissed checkout mid-flow. Can retry |
| `bank_transfer_submitted` | User submitted bank transfer details |
| `pay_via_bank_completed` | Pay via bank flow completed |


### Type Definitions

#### GlomoCheckoutPayload

```ts
interface GlomoCheckoutPayload {
  orderId: string;
  paymentId: string;
  signature: string;
}
```

#### GlomoBankTransferPayload

```ts
interface GlomoBankTransferPayload {
  orderId: string;
  senderAccountNumber: string;
  transactionReference: string;
}
```

#### GlomoPayViaBankConnectionPayload

```ts
interface GlomoPayViaBankConnectionPayload {
  bankIdentifier: string;
  cooldownPeriodInMinutes: number;
  bankName: string;
  bankImageSrc: string;
  bankImageAlt: string;
}
```

#### SdkError

```ts
interface SdkError {
  type: "validation_error" | "device_forbidden";
  message: string;
  field?: "publicKey" | "orderId" | "subscriptionId" | "baseCheckoutUrl" | "generatedCheckoutUrl";
}
```

## Bank Transfer Support

When the checkout flow includes a bank transfer option, the user submits transfer details (account number, reference) through the checkout UI. The SDK fires `onBankTransferSubmitted` with a `GlomoBankTransferPayload`:

```tsx
onBankTransferSubmitted={(payload) => {
  // payload may be null/undefined if the checkout page omits it
  console.log("Transfer ref:", payload?.transactionReference);
}}
```

The checkout status transitions to `bank_transfer_submitted`.

## Pay via Bank Support

The SDK fires `onPayViaBankCompleted` when the pay-via-bank journey completes:

```tsx
onPayViaBankCompleted={(payload) => {
  // payload.status - e.g. "success", "failed", "unknown"
  console.log("Pay via bank status:", payload.status);
}}
```

The checkout status transitions to `pay_via_bank_completed`. The SDK deduplicates this event internally - the callback fires only once per checkout session.

Additionally, `onPayViaBankBankConnectionSuccessful` fires when a bank account is successfully connected when initiating a pay-via-bank checkout, before the actual payment completes. This is informational only - it does not change the checkout status. Can be used to show a "bank connected" confirmation UI if desirable, while the payment continues in the background:

```tsx
onPayViaBankBankConnectionSuccessful={(payload) => {
  // payload may be null/undefined if the checkout page omits it
  console.log("Connected to:", payload?.bankName);
  console.log("Cooldown:", payload?.cooldownPeriodInMinutes, "minutes");
}}
```

## Camera Permissions

Some checkout flows may require camera access for bank authentication. The SDK handles permission prompts automatically, but you must declare the permissions in your native project config.

### Android

Add to `android/app/src/main/AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.CAMERA" />
```

### iOS

Add to `ios/<YourApp>/Info.plist`:

```xml
<key>NSCameraUsageDescription</key>
<string>Camera access is required for identity verification during checkout</string>
```

### Behavior

- **Android**: SDK prompts the user via a native permission dialog. If denied, checkout closes and `onUserRefusedCameraPermissions` fires.
- **iOS**: SDK grants the WebView permission request; iOS shows its own system prompt. If the user denies at the system level, the WebView handles the denial.


## Platform Behavior

- **iOS**: Checkout opens as a `pageSheet` modal (swipe-down to dismiss). Dismissing fires `onPaymentTerminate`.
- **Android**: Checkout opens fullscreen. The hardware back button dismisses it and fires `onPaymentTerminate`.


## Device Security Compliance

The SDK optionally integrates with `jail-monkey` to detect rooted (Android) or jailbroken (iOS) devices.

- If `jail-monkey` is installed and the device is compromised: `start()` returns `false` and `onSdkError` fires with `type: "device_forbidden"`.
- If `jail-monkey` is installed and the device is clean: checkout proceeds normally.
- If `jail-monkey` is not installed: SDK logs a warning and proceeds without checking. This is not recommended for production deployments handling regulated transactions.


## Mock Mode

The SDK infers mock mode from the `publicKey` prefix:

| Prefix | Mode | Environment |
|  --- | --- | --- |
| `live_` | Live | Production |
| `test_` | Mock | Test/sandbox |
| `mock_` | Mock | Test/sandbox |


Mock mode keys route to the sandbox backend. No real transactions are created.

## Connection Handling

The SDK detects connection errors from the WebView and fires `onConnectionError`:

- **iOS**: NSURLErrorDomain codes (-1001 timeout, -1003 host not found, -1004 connection refused, -1009 offline)
- **Android**: ERR_EMPTY_RESPONSE, ERR_CONNECTION_REFUSED, ERR_NAME_NOT_RESOLVED, ERR_INTERNET_DISCONNECTED, ERR_CONNECTION_TIMED_OUT, ERR_NETWORK_CHANGED


The checkout modal is automatically dismissed on connection errors.

## Input Validation

The SDK validates inputs before starting the checkout:

| Field | Rule |
|  --- | --- |
| `publicKey` | Must start with `live_`, `mock_`, or `test_`. Min 6 characters. |
| `orderId` | Must start with `order_`. Min 7 characters. Required when `subscriptionId` is absent. |
| `subscriptionId` | Must start with `sub_`. Trimmed and checked for emptiness. Required when `orderId` is absent. |


Validation failures fire `onSdkError` with `type: "validation_error"` and the relevant `field` name. `start()` returns `false`.

Providing both `orderId` and `subscriptionId` (or neither) also fires `onSdkError`.

## useGlomoCheckout Hook (Deprecated)

> **Deprecated** - Legacy hook, will be removed in a future major version.


`useGlomoCheckout` is a legacy placeholder from the v1.x hook-based API. In v1.x, the equivalent
hook (`useLrsCheckout`) provided reactive WebView state and rendering primitives that merchants used
to build custom checkout UIs. In v3, the inner checkout components are no longer exported, making
this hook ineffective for custom rendering.

The hook's public return type (`UseGlomoCheckoutReturn`) exposes:

- `start()` - identical to `GlomoCheckoutRef.start()`. Returns `Promise<boolean>`.
- `getStatus()` - returns a point-in-time `CheckoutStatus` snapshot. **Not reactive** - does not
trigger re-renders when status changes.


**Use the `GlomoCheckout` component with a ref instead:**

```tsx
import React, { useRef } from "react";
import { GlomoCheckout, type GlomoCheckoutRef } from "@glomopay/react-native-sdk";

const checkoutRef = useRef<GlomoCheckoutRef>(null);

// Start checkout
const started = await checkoutRef.current?.start();

// Check status (point-in-time, same as hook)
const status = checkoutRef.current?.getStatus();
```

The component-based API provides the same functionality with proper lifecycle management.

## Troubleshooting

### `start()` returns `false`

Check `onSdkError` for details. Common causes:

- Invalid `publicKey` format (must start with `live_`, `mock_`, or `test_`)
- Invalid `orderId` format (must start with `order_`)
- Invalid `subscriptionId` format (must start with `sub_`, non-empty after trimming)
- Both `orderId` and `subscriptionId` provided (or neither)
- Device is rooted/jailbroken (when `jail-monkey` is installed)


### Checkout opens but shows a blank screen

- Verify network connectivity
- Check that the `publicKey` and `orderId` are valid


### Camera permission denied

- Ensure `AndroidManifest.xml` and `Info.plist` include camera permission declarations
- The `onUserRefusedCameraPermissions` callback will fire when the user denies


### `onPayViaBankCompleted` not firing

- Ensure you are passing `onPayViaBankCompleted` as a prop to `GlomoCheckout`


## Exports

```ts
// Components
export { GlomoCheckout } from "@glomopay/react-native-sdk";

// Hooks (deprecated - use GlomoCheckout component with ref instead)
export { useGlomoCheckout } from "@glomopay/react-native-sdk";

// Types
export type {
  GlomoCheckoutRef,
  GlomoCheckoutProps,
  GlomoCheckoutPayload,
  CheckoutStatus,
  GlomoBankTransferPayload,
  GlomoPayViaBankConnectionPayload,
  UseGlomoCheckoutReturn,  // deprecated
  SdkError,
} from "@glomopay/react-native-sdk";
```

## Security

The SDK loads checkout pages in an isolated WebView. No PAN, CVV, or sensitive payment data passes through the React Native bridge - all sensitive input is handled within the WebView's sandboxed context.

Device integrity checking is available via optional `jail-monkey` integration (see [Device Security Compliance](#device-security-compliance)).

To report a security vulnerability, email security@glomopay.com. Do not open a public GitHub issue for security reports.

## Related

- [React Native SDK v4 (Latest)](/product-guide/sdk/react-native-sdk/v4) - current version documentation
- [Migration Guide (v1 to v4)](/product-guide/sdk/react-native-sdk/migration) - step-by-step upgrade instructions with before/after code
- [Changelog](/product-guide/sdk/react-native-sdk/changelog) - all release notes
- [React Native SDK v1 (Archived)](/product-guide/sdk/react-native-sdk/v1) - previous version documentation
- [Flutter SDK](/product-guide/sdk/flutter-sdk) - GlomoPay SDK for Flutter apps
- [Unified SDK (Web)](/product-guide/sdk/unified-sdk) - GlomoPay SDK for web apps
- [Checkout overview](/product-guide/payin/checkout) - server-side checkout integration and signature verification