# Glomo Flutter SDK v1 (Archived)

> **Archived** - This documentation is for Flutter SDK **v1.x**, frozen at the final v1 release, **v1.11.2**. v1 is no longer the latest version.
For the latest version, see [Flutter SDK v2](/platform/sdk/flutter-sdk/v2).
To upgrade, see the [Migration Guide](/platform/sdk/flutter-sdk/migration).


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

> Full [Changelog](/platform/sdk/flutter-sdk/changelog) is also available.


## Prerequisites

Before using this SDK, you need:

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


## System Requirements

| Requirement | Version |
|  --- | --- |
| Flutter | >= 3.7.0 |
| Dart SDK | >= 3.0.0 |


## Installation

Add the dependency to your `pubspec.yaml`:

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

Or install via the CLI:

```bash
flutter pub add glomopay_sdk
```

Then import the package:

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

## Platform Setup

### Android

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

```xml
<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" />
```

### iOS

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

```xml
<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>
```

## Quick Start

```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: 'test_pk_12345',
          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);
        },
      ),
    );
  }
}
```

## Subscriptions Checkout

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

```dart
GlomoPayCheckout(
  config: const GlomoPayConfig(
    publicKey: 'live_pk_abc123',
    subscriptionId: 'sub_xyz789',
  ),
  onPaymentSuccess: (GlomoPayPayload payload) {
    print('Subscription payment success: ${payload.paymentId}');
  },
  onPaymentFailure: (GlomoPayPayload payload) {
    print('Subscription payment failed: ${payload.orderId}');
  },
  onSdkError: (List<SdkError> errors) {
    errors.forEach((e) => print('${e.type}: ${e.message}'));
  },
  onConnectionError: (ConnectionError error) {
    print('Connection error: ${error.message}');
  },
)
```

When `subscriptionId` is provided:

- The SDK skips order detection API calls
- The `subscriptionId` must start with `sub_`
- LRS-specific UI elements and flow logic are not applied
- Do not pass both `orderId` and `subscriptionId` - the SDK will fire `onSdkError`
- Existing order-based integrations remain backward compatible


## Features

- **Glomo Payment Stack Support** - handles standard checkout flows and overlay redirects (3DS, bank pages)
- **Robust Security** - built-in jailbreak and root detection
- **Error Monitoring** - built-in error tracking and diagnostics
- **Comprehensive Error Handling** - gracefully manages connection drops, DNS issues, HTTP errors, validation mistakes
- **Native Support** - full Android/iOS native features (camera, file pickers)
- **Mock Mode** - easy testing with `test_` and `mock_` prefixed keys


## API Reference

### GlomoPayCheckout Widget

The checkout widget. Place it in your widget tree to render the payment checkout.

```dart
GlomoPayCheckout(
  config: config,
  onPaymentSuccess: ...,
  onPaymentFailure: ...,
  onSdkError: ...,
  onConnectionError: ...,
)
```

#### 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 transaction declines or fails |
| `onSdkError` | `Function(List<SdkError>)` | Yes | Called on SDK-level errors (validation, forbidden device) |
| `onConnectionError` | `Function(ConnectionError)` | Yes | Called on internet drop, DNS failure, HTTP error |
| `onPaymentTerminate` | `Function(TerminationSource)?` | No | Called if user dismisses modal or hits back |
| `onUserRefusedDevicePermissions` | `Function()?` | No | Called when user denies camera/storage permissions during file/document uploads or selfie verification requests |
| `autoCloseOnConnectionError` | `bool` | No | Auto-call onPaymentTerminate on critical connection error. Default: true |


### GlomoPayConfig

| Property | Type | Default | Description |
|  --- | --- | --- | --- |
| `publicKey` | `String` | - | Your Glomo public key (must start with `live_`, `mock_`, or `test_`) |
| `orderId` | `String` | - | Unique tracking ID generated for transaction on server |
| `subscriptionId` | `String` | - | Subscription checkout ID; use instead of orderId for subscriptions |
| `server` | `String?` | `null` | Custom LRS checkout URL; leave unset to use the official environment URL |


Exactly one of `orderId` or `subscriptionId` must be provided. If both or neither are set, `onSdkError` fires.

### GlomoPayPayload

```dart
class GlomoPayPayload {
  final String orderId;       // System ID of the order
  final String? paymentId;    // Transaction reference, if generated
  final String? signature;    // Validation signature hash for backend verification
  final Map<String, dynamic>? rawResponse; // Page message exactly as it arrived
}
```

### SdkError

```dart
class SdkError {
  final SdkErrorType type;   // Error category
  final String message;       // Human-readable description
  final String? field;        // Field name (e.g. "orderId") causing validationError
}
```

#### SdkErrorType

| Value | Description |
|  --- | --- |
| `validationError` | Input validation failed |
| `deviceForbidden` | Rooted or jailbroken device detected |
| `networkError` | Network-level error |
| `unknown` | Uncategorized error |


### ConnectionError

```dart
class ConnectionError {
  final ConnectionErrorType type;  // Error category
  final String message;            // Extracted 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;        // Suggests if safe to offer a "Retry" button
}
```

#### ConnectionErrorType

| Value | Description |
|  --- | --- |
| `noInternet` | Device is offline |
| `timeout` | Request timed out |
| `dnsFailure` | DNS resolution failed |
| `sslError` | SSL/TLS handshake error |
| `httpClientError` | HTTP 4xx response |
| `httpServerError` | HTTP 5xx response |
| `webResourceError` | WebView resource loading error |
| `unknown` | Uncategorized connection error |


Use `isRecoverable` to decide whether to show a "Retry" button to the user.

### TerminationSource

| Value | Description |
|  --- | --- |
| `userDismiss` | User swiped down to dismiss the payment sheet |
| `backButton` | User pressed the hardware/software back button |
| `programmatic` | The checkout was closed programmatically |
| `connectionError` | A connection error closed the checkout |


### Checkout Status

`CheckoutStatus` represents the current state of the checkout flow.

| Status | Description |
|  --- | --- |
| `validating` | Input keys and devices securely checked |
| `ready` | Verified; loading UI |
| `paymentInProgress` | User typing card details or authorizing |
| `paymentSuccessful` | Payment clear |
| `paymentFailed` | Processing declined |
| `paymentCancelled` | User bounced |


## Platform-Specific Behavior

- **iOS**: SDK intercepts downward swipes to dismiss the payment sheet and triggers `onPaymentTerminate` with `TerminationSource.userDismiss`.
- **Android**: Overrides standard pop; checks if the Flow WebView overlay can go back. Returns `TerminationSource.backButton` until the modal is closed.


## 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 heuristics allow mock traffic
- Simulate fake transactions without real money movement


## Troubleshooting

### Invalid Order ID format

Ensure `orderId` starts with `order_` and has appropriate length.

### Invalid Subscription ID format

Ensure `subscriptionId` starts with `sub_` and has appropriate length.

### Mutually exclusive identifiers

Provide either `orderId` or `subscriptionId`, not both. The SDK fires `onSdkError` if both are set.

### SDK crashes immediately on open

Ensure `config.publicKey` is correctly set with an expected prefix (`live_`, `mock_`, or `test_`).

### File upload buttons do nothing

Run `flutter clean` and rebuild. Ensure Camera and Storage permissions are explicitly granted in the platform config.

### Device Forbidden Error

Rooted or jailbroken devices trigger `onSdkError` with `SdkErrorType.deviceForbidden` unless testing in an emulator.

## Security

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

Built-in jailbreak and root detection prevents checkout on compromised devices.

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

## Exports

```dart
/**
 * All public exports from package:glomopay_sdk/glomopay_sdk.dart
 */

// Widget
GlomoPayCheckout

// Controller
GlomoPayController

// Configuration
GlomoPayConfig

// Payload
GlomoPayPayload

// Errors
SdkError
SdkErrorType
ConnectionError
ConnectionErrorType

// Enums
TerminationSource
CheckoutStatus
```

## Related

- [Flutter SDK v2 (Latest)](/platform/sdk/flutter-sdk/v2) - current version documentation
- [Migration Guide (v1.11.x to v2.0.0)](/platform/sdk/flutter-sdk/migration) - step-by-step upgrade instructions with before/after code
- [Changelog](/platform/sdk/flutter-sdk/changelog) - all release notes
- [Flutter SDK v0.0.15 (Deprecated)](/platform/sdk/flutter-sdk/v0.0.15)
- [Flutter SDK v0.0.13 (Deprecated)](/platform/sdk/flutter-sdk/v0.0.13)
- [Flutter SDK v0.0.3 (Deprecated)](/platform/sdk/flutter-sdk/v0.0.3)
- [React Native SDK](/platform/sdk/react-native-sdk) - Glomo SDK for React Native apps
- [Unified SDK (Web)](/platform/sdk/unified-sdk) - Glomo SDK for web apps
- [Checkout overview](/payin/checkout) - server-side checkout integration and signature verification