npm package: @glomopay/react-native-sdk
Description: The React Native SDK for GlomoPay
Author: Glomo Payments IFSC Private Limited
Latest version: 1.3.5

# GlomoPay React Native SDK 💳

[![npm version](https://img.shields.io/npm/v/@glomopay/react-native-sdk.svg)](https://www.npmjs.com/package/@glomopay/react-native-sdk)
[![License](https://img.shields.io/npm/l/@glomopay/react-native-sdk.svg)](LICENSE)

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

## ✨ Features

- 📱 **Cross-Platform** - Works seamlessly on both iOS and Android
- 🔷 **TypeScript Support** - Full type definitions included
- ⚡ **Simple Integration** - Minimal configuration required
- 🔒 **Secure** - WebView-based checkout with signature verification
- 🛡️ **Device Security Compliance** - Prevents unsafe/non-compliant devices from initiating checkouts as per regulatory policies
- 💰 **Flexible** - Support for multiple payment methods through GlomoPay

## 📋 Prerequisites

Before using this SDK, you need:

- API credentials (Public Key) from your GlomoPay dashboard

## 🛠️ System Requirements

- React Native >= 0.68.0
- React >= 17.0.0
- Node.js >= 16.0.0
- npm >= 8.0.0

## 📦 Installation

### 📲 1. Standard React Native CLI project

For standard installations, this SDK requires `react-native-webview` as a peer dependency. Install it first:

```bash
npm install react-native-webview
```

Then install the SDK

```bash
npm install @glomopay/react-native-sdk
```

**🔒 Recommended: Enhanced Security Compliance**

For enhanced device security compliance (rooted/jailbroken device detection), we HIGHLY recommend installing the peer dependency `jail-monkey`:

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

**Note:** The SDK works without `jail-monkey`, but installing it enables automatic device security compliance checks that help meet regulatory requirements. See [Device Security Compliance](#device-security-compliance-) section for more details.

### 🔧 2. Expo Projects

This SDK is compatible with Expo projects. Install with:

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

**Note**: Requires custom dev client or EAS Build. Not compatible with Expo Go app.

For Expo Go limitations, see [Expo documentation](https://docs.expo.dev/workflow/customizing/).

## 🚀 Quick Start

Before start the checkout flow, you'll need to create an LRS order using other Glomo SDKs and obtain the Order ID (Alphanumeric, starts with `order_`).

### 1. Import the SDK

```tsx
import {
  GlomoLrsCheckout,
  type GlomoLrsCheckoutRef,
  type SdkError,
} from '@glomopay/react-native-sdk';
```

### 2. Add the Component to Your App

```tsx
import React, { useState, useRef } from 'react';
import { View } from 'react-native';
import {
  GlomoLrsCheckout,
  type GlomoLrsCheckoutRef,
} from '@glomopay/react-native-sdk';

function CheckoutScreen()
{  
  const [orderId, setOrderId] = useState('YOUR_ORDER_ID');
  const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);

  const startLrsCheckout = () => {
    const started = checkoutRef.current?.start();
    if (!started) {
      const status = checkoutRef.current?.getStatus();
      console.log('Checkout could not be started. Current status:', status);
    }
  };

  return (
    <View>
      <GlomoLrsCheckout
        ref={checkoutRef}
        publicKey={'YOUR_PUBLIC_KEY'}
        orderId={orderId}
        onPaymentSuccess={(payload) => {
          console.log('Payment successful!', payload);
          // Handle successful payment
        }}
        onPaymentFailure={(payload) => {
          console.log('Payment failed!', payload);
          // Handle failed payment
        }}
        onConnectionError={(error) => {
          console.log('Could not open LRS checkout!', error);
          // Handle connection/network errors
        }}
        onSdkError={(errors) => {
          errors.forEach((error) => {
            console.error('SDK Error:', error.message);
            // Handle validation errors
          });
        }}
      />
    </View>
  );
}
```

## 📚 API Reference

### `GlomoLrsCheckout` Component

#### Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `server` | `string` | No | The base LRS checkout server URL. If not provided, defaults to the production URL (`https://lrs-checkout-page-prod.web.app`). Only override this for localhost or staging setups. Must be a valid HTTP or HTTPS URL. |
| `publicKey` | `string` | Yes | Your public key. If it starts with `test_`, mock mode will be enabled automatically. Otherwise, live mode is used. |
| `orderId` | `string` | Yes | The order ID for this transaction. Must start with `order_` |
| `onPaymentSuccess` | `(payload: GlomoLrsCheckoutPayload) => void` | Yes | Callback function called when the payment is successful |
| `onPaymentFailure` | `(payload: GlomoLrsCheckoutPayload) => void` | Yes | Callback function called when the payment fails |
| `onConnectionError` | `(error: unknown) => void` | No | Will be called on network connection problems. The checkout modal will automatically close before this is triggered. |
| `onPaymentTerminate` | `() => void` | No | Callback called when checkout is terminated. Triggered when the `checkout.closed` event is received from the WebView or when the user dismisses the modal (iOS swipe down) or presses the back button (Android) |
| `onSdkError` | `(errors: SdkError[]) => void` | No | Callback for SDK validation errors and configuration issues. Receives an array of `SdkError` objects when validation fails. |
| `devMode` | `boolean` | No | Enable debug logging (default: `false`) |
| `visible` | `boolean` | No | Control modal visibility manually (advanced usage only). It is HIGHLY recommended to not use this prop directly. |

### Ref Methods

```tsx
interface GlomoLrsCheckoutRef {
  start: () => boolean;  // Starts the checkout flow. Returns true if started, false if it cannot be started.
  getStatus: () => LrsCheckoutStatus;  // Returns the current checkout status
}
```

Usage:
```tsx
const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);

// Start checkout - returns true if successful, false otherwise
const started = checkoutRef.current?.start();
if (started) {
  console.log('Checkout started successfully');
} else {
  console.log('Checkout could not be started. Check the status.');
}

// Check status
const currentStatus = checkoutRef.current?.getStatus();
```

**Note:**
  - The `start()` method returns `true` if the checkout was started successfully, `false` otherwise
  - The `start()` method performs device compliance checks first (before any other validation) **if `jail-monkey` is installed**.
    - If the device is rooted or jailbroken and `jail-monkey` is available, it will return `false` and trigger the `onSdkError` callback with a `device_forbidden` error.
    - If `jail-monkey` is not installed, compliance checks are skipped and checkout proceeds normally.
  - The `start()` method may be used to restart an LRS checkout for an existing order,
    - If the user cancelled the payment midway (`"payment_cancelled"` status) by pressing the back button on Android, or dismissing the modal on iOS
    - Or if the payment failed or timed-out (`"payment_failed"` status)
  - After an LRS checkout for an `orderId` is successful, further calls to the `start()` method will return false, and will not re-trigger an LRS checkout (`"payment_successful"` status)
  - Changing the `orderId`/`publicKey` props resets the flow, and `start()` can be triggered again

#### `GlomoLrsCheckoutPayload`


```typescript
interface GlomoLrsCheckoutPayload {
  orderId: string;    // Order identifier (e.g., "order_abc123")
  paymentId: string;  // Payment id from GlomoPay
  signature: string;  // Signature for verification
}
```

The payload is returned for both successful and failed LRS payments.

#### `SdkError`

The SDK provides validation and error reporting through the `onSdkError` callback:

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

**Error Types:**
- `validation_error`: Input validation failed (invalid publicKey, orderId, or server/baseCheckoutUrl)
- `device_forbidden`: Device does not meet compliance requirements (LRS checkout is not permitted on compromised/rooted devices per regulatory policies).

**Example:**
```tsx
<GlomoLrsCheckout
  onSdkError={(errors) => {
    errors.forEach((error) => {
      console.error(`SDK Error [${error.type}]:`, error.message);
      if (error.field) {
        console.error(`Field: ${error.field}`);
      }
    });
    // Handle validation errors appropriately
  }}
  // ... other props
/>
```

**Note:** The SDK validates all inputs when `start()` is called. Validation errors are reported through `onSdkError` and `start()` will return `false` if validation fails.

##### Checkout Status System 📊

The SDK provides a status system to track the checkout lifecycle. Access the current status using the `getStatus()` method on the component ref:

```tsx
const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);
const currentStatus = checkoutRef.current?.getStatus();
```

#### Status Values

The `LrsCheckoutStatus` type includes the following values:

| Status | Description |
|--------|-------------|
| `"ready"` | Checkout is ready to be started |
| `"payment_in_progress"` | Checkout flow is active and ongoing |
| `"payment_successful"` | Payment completed successfully |
| `"payment_failed"` | Payment failed (`glomoLrsCheckoutRef.current?.start()` can be reused with the same `orderId`) |
| `"payment_cancelled"` | User cancelled the checkout midway (`glomoLrsCheckoutRef.current?.start()` can be reused with the same `orderId`) |

#### Status Lifecycle

```
ready → payment_in_progress → payment_successful (order complete)
         ↓                           ↑                    ↑
  payment_cancelled (can call start() again to restart)   |
         ↓                           ↑                    ↑
  payment_failed (can call start() again to retry) → _____⌟
```

## 📱 Platform-Specific Behavior

### 🍎 iOS
- Checkout appears inside a modal within a `pageSheet`
- Users can dismiss `GlomoLrsCheckout` component by swiping down
- `onPaymentTerminate` is called when modal is dismissed

### 🤖 Android
- Checkout appears in full-screen mode
- Users can press the hardware back button to close the full-screen `GlomoLrsCheckout` component
- Back button triggers `onPaymentTerminate` and closes checkout

## 🔧 Troubleshooting

### Common Issues

#### 1. Checkout not appearing
**Solution**: 
- Ensure `start()` is called via ref and check its return value
- If `start()` returns `false`, check the current status using `getStatus()`
- The checkout status must be `"ready"`, `"payment_cancelled"`, or `"payment_failed"` for `start()` to succeed
- The checkout status must NOT be `"payment_successful"` (successful payments cannot be restarted)
- **Device Security Compliance**: If peer dependency `jail-monkey` is installed and the device does not meet compliance requirements (the device is rooted/jailbroken), `start()` will return `false`. Check `onSdkError` callback for `device_forbidden` errors.
  - However, if `jail-monkey` has not been installed, security compliance checks will be skipped.
- Check that `orderId` is provided and valid (must start with `order_`)
- If you're providing `server`, verify it is accessible and a valid HTTP/HTTPS URL (note: `server` is optional and defaults to production)
- Ensure `publicKey` is valid (must start with `live_`)
- Implement `onSdkError` callback to receive validation and device compliance error details

#### 2. Expo Go "Invariant Violation" error
**Solution**:
- Expo Go doesn't support native modules
- Use custom dev client: `npx expo prebuild`
- Or use EAS Build for testing


### Debugging Mode 🛠️

Enable detailed logging:

```tsx
<GlomoLrsCheckout
  devMode={true}
  // ... other props
/>
```
Remember to disable this in production.

### Mock Mode Testing 🧪

Mock mode is automatically enabled based on your `publicKey`:

- If your `publicKey` starts with `test_` (case-insensitive), mock mode is automatically enabled and the checkout URL will include `mode=mock`
- Otherwise, live mode is used and the checkout URL will include `mode=live`

**Example:**
```tsx
// Mock mode (publicKey starts with "test_")
<GlomoLrsCheckout
  publicKey="test_abc123..."
  // ... other props
/>

// Live mode (publicKey does not start with "test_")
<GlomoLrsCheckout
  publicKey="live_xyz789..."
  // ... other props
/>
```

Note that `devMode` is separate and only controls console logging, not the payment mode.

### Connection Handling 🚨

The SDK provides an (optional) `onConnectionError` callback for connection error events. The checkout modal/page will be dismissed/closed, before this callback is triggered.

**Scenarios:**
- Connection failures
- Internet unavailability
- DNS resolution failures

**Note:** HTTP `4xx`/`5xx` errors will not be captured as connection errors.

**Example:**
```tsx
<GlomoLrsCheckout
  onConnectionError={(error) => {
    // Handle connection/network errors
    // The modal will be automatically closed before this callback is triggered
    Alert.alert('Connection Error', 'Unable to connect to the GlomoPay servers. Please check your internet connection.');
  }}
  // ... other props
/>
```

**Note:** `onConnectionError` is for network/connection errors only. Payment-specific failures should be handled by `onPaymentFailure`.

### Device Security Compliance 🛡️

**⚠️ Important:** The SDK provides automatic device security compliance checking via the `jail-monkey` library. For enhanced security compliance and to meet regulatory requirements, we **strongly recommend** installing the optional peer dependency `jail-monkey`.

#### Installation

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

#### How It Works

- **With `jail-monkey` installed:** The SDK automatically performs device security compliance checks before allowing an LRS checkout to start. Rooted (Android) or jailbroken (iOS) devices are prevented from starting checkouts.
- **Without `jail-monkey`:** The SDK skips automatic compliance checks, and allows checkout to proceed normally. Regulatory compliance would have to be enforced manually.

#### Features

An automatic device security compliance check:
- Runs synchronously as the **first validation step** in the `start()` method
- Blocks checkout on non-compliant devices to meet regulatory requirements
- Works on both iOS and Android platforms
- Triggers the `onSdkError` callback with a `device_forbidden` error if a non-compliant device is detected

**Example:**
```tsx
<GlomoLrsCheckout
  onSdkError={(errors) => {
    errors.forEach((error) => {
      if (error.type === 'device_forbidden') {
        Alert.alert(
          'Device Unsafe',
          'LRS checkout is not permitted on rooted or jailbroken devices per regulatory compliance requirements.'
        );
      }
    });
  }}
  // ... other props
/>
```


### Input Validation 🔍

The SDK automatically validates all inputs:

- **`publicKey`**: Must start with `live_` and have a minimum length of 6 characters
- **`orderId`**: Must start with `order_` and have a minimum length of 7 characters
- **`server`**: Must be a valid HTTP or HTTPS URL (optional, defaults to production URL if not provided)

Validation errors are reported through the `onSdkError` callback. The SDK validates inputs when `start()` is called:
- Device security compliance check (first, before any other validation)
- Input validation (publicKey, orderId, server)
- Checkout URL validation (before building the final URL)

**Example:**
```tsx
<GlomoLrsCheckout
  onSdkError={(errors) => {
    if (errors.length > 0) {
      // Handle validation errors
      Alert.alert(
        'Configuration Error',
        errors.map(e => e.message).join('\n')
      );
    }
  }}
  // ... other props
/>
```

## 💬 Support

### Documentation
- 📖 API Documentation: https://docs.glomopay.com
- 🎛️ Dashboard: https://dashboard.glomopay.com

### Contact Us
- ✉️ Email: developer@glomopay.com
- 🎟️ GitHub Issues: https://github.com/glomopay/glomopay-rn-sdk/issues
- 🌐 Website: https://glomopay.com

## License 📄

This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.