# GlomoPay Flutter SDK

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

> **ℹ️ Note:** The Flutter SDK supports LRS (Liberalised Remittance Scheme) and NRI payment flows.


## Prerequisites

Before using this SDK, you need:

- API credentials (Public Key) from your GlomoPay dashboard
- Flutter >= 3.7.0
- Dart SDK >= 3.0.0


## Installation

### 1. Add Dependency

Add to your `pubspec.yaml`:


```yaml
dependencies:
  flutter:
    sdk: flutter
  glomopay_sdk: ^0.0.3
```

Or run:


```bash
flutter pub add glomopay_sdk
```

### 2. Import


```dart
import 'package:glomopay_sdk/glomopay_sdk.dart';
```

## Platform Setup

### Android Permissions

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


```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="29" />
</manifest>
```

### iOS Permissions

Add the following to `ios/Runner/Info.plist`:


```xml
<dict>
    <key>NSCameraUsageDescription</key>
    <string>This app requires access to the camera to upload documents required
    for payment verification.</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>This app requires access to the photo library to select documents
    for payment verification.</string>
</dict>
```

## Quick Start

Before starting the checkout flow, you'll need to create an LRS order and obtain the Order ID (starts with `order_`).


```dart
import 'package:flutter/material.dart';
import 'package:glomopay_sdk/glomopay_sdk.dart';

class PaymentScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Complete Payment')),
      body: GlomoPayCheckout(
        config: const GlomoPayConfig(
          publicKey: 'YOUR_PUBLIC_KEY',
          orderId: 'order_abc123',
        ),
        onPaymentSuccess: (GlomoPayPayload payload) {
          print('Payment succeeded! Payment ID: ${payload.paymentId}');
        },
        onPaymentFailure: (GlomoPayPayload payload) {
          print('Payment failed with Order ID: ${payload.orderId}');
        },
        onSdkError: (List<SdkError> errors) {
          print('SDK Error: ${errors.first.message}');
        },
        onConnectionError: (ConnectionError error) {
          print('Connection error: ${error.message}');
        },
        onPaymentTerminate: (TerminationSource source) {
          print('User cancelled checkout via $source');
          Navigator.pop(context);
        },
      ),
    );
  }
}
```

## API Reference

### GlomoPayCheckout Widget

#### Props

| Prop | Type | Required | Description |
|  --- | --- | --- | --- |
| `config` | `GlomoPayConfig` | Yes | Configuration details for the checkout session |
| `onPaymentSuccess` | `Function(GlomoPayPayload)` | Yes | Called when payment completes successfully |
| `onPaymentFailure` | `Function(GlomoPayPayload)` | Yes | Called when the transaction declines or fails |
| `onSdkError` | `Function(List<SdkError>)` | Yes | Called on SDK-level validation or configuration errors |
| `onConnectionError` | `Function(ConnectionError)` | Yes | Called on internet drops, DNS failures, or HTTP errors |
| `onPaymentTerminate` | `Function(TerminationSource)?` | No | Called when the user dismisses the modal or presses back |
| `onEvent` | `Function(String, Map)?` | No | Generic listener for telemetry events |
| `autoCloseOnConnectionError` | `bool` | No | Auto-close widget on connection error (default: `true`) |


### GlomoPayConfig

| Property | Type | Default | Description |
|  --- | --- | --- | --- |
| `publicKey` | `String` | — | Your GlomoPay public key. If it starts with `test_` or `mock_`, mock mode is enabled automatically |
| `orderId` | `String` | — | The order ID for this transaction. Must start with `order_` |
| `server` | `String?` | `null` | Custom LRS checkout server URL. Defaults to the production URL if not provided |
| `devMode` | `bool` | `false` | Enable debug logging (default: `false`) |


### GlomoPayPayload

Returned via `onPaymentSuccess` and `onPaymentFailure`:


```dart
class GlomoPayPayload {
  final String orderId;      // The order ID (e.g., "order_abc123")
  final String? paymentId;   // The transaction reference, if generated
  final String? signature;   // Validation signature for backend verification
}
```

### SdkError

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


```dart
class SdkError {
  final SdkErrorType type;   // validationError, deviceForbidden, networkError, or unknown
  final String message;      // Human-readable description of the error
  final String? field;       // Field name that caused the error (e.g., "orderId")
}
```

**Error Types:**

- `validationError`: Input validation failed (invalid `publicKey`, `orderId`, or `server`)
- `deviceForbidden`: Device does not meet compliance requirements (rooted or jailbroken devices are not permitted)


### ConnectionError


```dart
class ConnectionError {
  final ConnectionErrorType type;  // noInternet, timeout, dnsFailure, sslError, etc.
  final String message;            // Error description or HTTP status phrase
  final int? errorCode;            // Internal WebKit/Android error code
  final int? statusCode;           // HTTP status code, if applicable
  final bool isRecoverable;        // Whether it is safe to offer a retry option
}
```

### Checkout Status System

The SDK tracks the checkout lifecycle through the following states:

| Status | Description |
|  --- | --- |
| `validating` | Input keys and device compliance are being checked |
| `ready` | Validation passed; loading the checkout UI |
| `paymentInProgress` | User is actively completing the payment |
| `paymentSuccessful` | Payment completed successfully |
| `paymentFailed` | Payment was declined or failed |
| `paymentCancelled` | User dismissed or cancelled the checkout |


## Platform-Specific Behavior

### iOS

- Checkout appears inside a modal
- Users can dismiss by swiping down, which triggers `onPaymentTerminate` with `TerminationSource.userDismiss`


### Android

- Checkout appears in full-screen mode
- Pressing the hardware back button triggers `onPaymentTerminate` with `TerminationSource.backButton`


## Troubleshooting

### Common Issues

#### Invalid Order ID format

Ensure `orderId` starts with `"order_"` and meets the minimum length requirement.

#### SDK errors on launch

Verify `config.publicKey` is set correctly and starts with the expected prefix (`live_` for production or `test_` for mock mode).

#### File upload buttons not working

Run `flutter clean` and ensure Camera and Storage permissions are granted in `AndroidManifest.xml` and `Info.plist`.

#### Device Forbidden error

Rooted or jailbroken devices trigger `onSdkError` with a `deviceForbidden` error. Use an emulator or a non-rooted/jailbroken device for testing.

### Mock Mode Testing

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

- If `publicKey` starts with `test_` or `mock_` (case-insensitive), mock mode is enabled
- Otherwise, live mode is used


**Example:**


```dart
// Mock mode
GlomoPayConfig(
  publicKey: 'test_pk_12345',
  orderId: 'order_abc123',
)

// Live mode
GlomoPayConfig(
  publicKey: 'live_pk_xyz789',
  orderId: 'order_abc123',
)
```

**Note:** `devMode` is separate and only controls debug logging, not the payment mode.