Sysmo Verification ๐Ÿ”

Version Flutter License

๐Ÿ“‹ Overview

Sysmo Verification is a Flutter package that simplifies KYC (Know Your Customer) document verification. It supports Aadhaar, PAN, Voter ID, Passport, and GST verification with a consistent UI and easy integration.

โœจ Key Features

Feature Description
๐ŸŽจ Unified UI Consistent interface across all verification types
๐Ÿ”ง Customizable Modify colors, styling, validation patterns, and API endpoints
โšก Reactive Forms Built on reactive_forms for seamless form management
๐Ÿ“ฑ Offline Support Works with both live APIs and local mock data
๐Ÿ”’ Type Safe Full null safety support

๐Ÿ“ฆ Installation

Step 1: Add dependency

Add to your pubspec.yaml:

dependencies:
  sysmo_verification: ^0.0.19

Step 2: Install packages

flutter pub get

Step 3: Platform Setup

Android โ€” Add to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

iOS โ€” Add to ios/Runner/Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
</dict>

๐Ÿš€ Quick Start

Step 1: Import the package

import 'package:sysmo_verification/kyc_validation.dart';

Step 2: Create a form with ReactiveFormBuilder

Wrap your verification widget inside a ReactiveFormBuilder to manage form state:

class MyVerificationScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ReactiveFormBuilder(
      form: () => FormGroup({
        'panNumber': FormControl<String>(
          validators: [Validators.required],
        ),
      }),
      builder: (context, form, child) {
        return Column(
          children: [
            // Add your KYCTextBox widget here
          ],
        );
      },
    );
  }
}

๐Ÿ“– Usage Examples

Example 1: PAN Card Verification (Simplest)

KYCTextBox(
  // Form configuration
  formProps: FormProps(
    formControlName: 'panNumber',
    label: 'PAN Number',
    mandatory: true,
    maxLength: 10,
  ),
  
  // Validation
  validationPattern: RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]$'),
  validationPatternErrorMessage: 'Enter valid PAN (e.g., ABCDE1234F)',
  verificationType: VerificationType.pan,
  
  // Styling
  styleProps: StyleProps(),
  buttonProps: ButtonProps(
    label: 'Verify',
    foregroundColor: Colors.white,
  ),
  
  // API Configuration
  isOffline: false,                                    // Set true for testing with mock data
  apiUrl: 'https://your-api.com/verify/pan',          // Your verification API endpoint
  token: 'your-auth-token',
  leadId: 'unique-lead-id',
  
  // Aadhaar-specific fields (required but can be empty for PAN)
  otpGendraassetApiurl: '',
  otpGendrateassetPath: '',
  aadhaarResponseApiurl: '',
  aadhaarResponseassetspath: '',
  aadharvaultassetpath: '',
  aadharvaultApiurl: '',
  aadharvaultlookupassetpath: '',
  aadharvaultlookupapiurl: '',
  
  // Callbacks
  onSuccess: (response) {
    print('Verification successful: ${response.data}');
  },
  onError: (error) {
    print('Verification failed: $error');
  },
)

Example 2: Aadhaar Verification (with OTP)

Aadhaar requires OTP verification. The widget automatically handles the OTP flow:

KYCTextBox(
  formProps: FormProps(
    formControlName: 'aadhaarNumber',
    label: 'Aadhaar Number',
    mandatory: true,
    maxLength: 12,
  ),
  
  validationPattern: RegExp(r'^\d{12}$'),
  validationPatternErrorMessage: 'Enter 12-digit Aadhaar number',
  verificationType: VerificationType.aadhaar,
  
  styleProps: StyleProps(),
  buttonProps: ButtonProps(
    label: 'Verify with OTP',
    foregroundColor: Colors.white,
  ),
  
  // Online API mode
  isOffline: false,
  apiUrl: 'https://your-api.com/verify/aadhaar',
  token: 'your-auth-token',
  leadId: 'unique-lead-id',
  
  // Aadhaar-specific API endpoints
  otpGendraassetApiurl: 'https://your-api.com/aadhaar/generate-otp',
  aadhaarResponseApiurl: 'https://your-api.com/aadhaar/verify-otp',
  aadharvaultApiurl: 'https://your-api.com/aadhaar/vault',
  aadharvaultlookupapiurl: 'https://your-api.com/aadhaar/vault-lookup',
  
  // Asset paths (empty when using online mode)
  otpGendrateassetPath: '',
  aadhaarResponseassetspath: '',
  aadharvaultassetpath: '',
  aadharvaultlookupassetpath: '',
  
  onSuccess: (response) {
    print('Aadhaar verified: ${response.data}');
  },
  onError: (error) {
    print('Aadhaar verification failed: $error');
  },
)

Example 3: Offline Testing Mode

For development and testing, use mock JSON responses:

KYCTextBox(
  formProps: FormProps(
    formControlName: 'voterId',
    label: 'Voter ID',
    mandatory: true,
    maxLength: 10,
  ),
  
  validationPattern: RegExp(r'^[A-Z]{3}\d{7}$'),
  validationPatternErrorMessage: 'Enter valid Voter ID (e.g., ABC1234567)',
  verificationType: VerificationType.voterId,
  
  styleProps: StyleProps(),
  buttonProps: ButtonProps(label: 'Verify'),
  
  // Offline mode - uses local asset files
  isOffline: true,
  assetPath: 'assets/mock_data/voter_response.json',
  
  // Empty API URLs for offline mode
  apiUrl: '',
  token: '',
  leadId: '',
  otpGendraassetApiurl: '',
  otpGendrateassetPath: '',
  aadhaarResponseApiurl: '',
  aadhaarResponseassetspath: '',
  aadharvaultassetpath: '',
  aadharvaultApiurl: '',
  aadharvaultlookupassetpath: '',
  aadharvaultlookupapiurl: '',
  
  onSuccess: (response) => print('Success: ${response.data}'),
  onError: (error) => print('Error: $error'),
)

Example 4: Complete Screen Implementation

import 'package:flutter/material.dart';
import 'package:sysmo_verification/kyc_validation.dart';

class KYCVerificationScreen extends StatelessWidget {
  const KYCVerificationScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('KYC Verification')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ReactiveFormBuilder(
          form: () => FormGroup({
            'panNumber': FormControl<String>(
              validators: [Validators.required],
            ),
          }),
          builder: (context, form, child) {
            return Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                // PAN Verification Widget
                KYCTextBox(
                  formProps: FormProps(
                    formControlName: 'panNumber',
                    label: 'PAN Number',
                    mandatory: true,
                    maxLength: 10,
                  ),
                  validationPattern: RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]$'),
                  validationPatternErrorMessage: 'Enter valid PAN',
                  verificationType: VerificationType.pan,
                  styleProps: StyleProps(),
                  buttonProps: ButtonProps(
                    label: 'Verify PAN',
                    foregroundColor: Colors.white,
                  ),
                  isOffline: true, // Change to false for production
                  assetPath: 'assets/mock_data/pan_response.json',
                  apiUrl: '',
                  token: '',
                  leadId: 'lead-123',
                  otpGendraassetApiurl: '',
                  otpGendrateassetPath: '',
                  aadhaarResponseApiurl: '',
                  aadhaarResponseassetspath: '',
                  aadharvaultassetpath: '',
                  aadharvaultApiurl: '',
                  aadharvaultlookupassetpath: '',
                  aadharvaultlookupapiurl: '',
                  onSuccess: (response) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('PAN Verified!')),
                    );
                  },
                  onError: (error) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Error: $error')),
                    );
                  },
                ),
                
                const SizedBox(height: 24),
                
                // Submit Button
                ElevatedButton(
                  onPressed: () {
                    if (form.valid) {
                      print('Form submitted: ${form.value}');
                    } else {
                      form.markAllAsTouched();
                    }
                  },
                  child: const Text('Submit'),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}


๐Ÿ“– Supported Verification Types

Type Validation Pattern Verification Method Example
๐Ÿ†” Aadhaar ^\d{12}$ OTP-based 123456789012
๐Ÿ’ณ PAN ^[A-Z]{5}[0-9]{4}[A-Z]$ Instant ABCDE1234F
๐Ÿ—ณ๏ธ Voter ID ^[A-Z]{3}\d{7}$ Instant ABC1234567
๐Ÿข GST ^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$ Instant 22ABCDE1234F1Z5
โœˆ๏ธ Passport ^[A-Z][1-9][0-9]{6}$ Instant A1234567

๐Ÿ”ง Configuration Reference

FormProps โ€” Input Field Settings

Property Type Required Description
formControlName String โœ… Unique name for form control
label String โœ… Input field label text
mandatory bool โŒ Show asterisk for required fields (default: false)
maxLength int? โŒ Maximum character limit
hint String? โŒ Placeholder text
FormProps(
  formControlName: 'panNumber',
  label: 'PAN Number',
  mandatory: true,
  maxLength: 10,
  hint: 'Enter your PAN',
)

ButtonProps โ€” Verify Button Settings

Property Type Required Description
label String โœ… Button text
foregroundColor Color? โŒ Text/icon color
backgroundColor Color? โŒ Button background color
borderRadius double? โŒ Corner radius
disabled bool โŒ Disable button (default: false)
ButtonProps(
  label: 'Verify',
  foregroundColor: Colors.white,
  backgroundColor: Colors.blue,
  borderRadius: 8.0,
)

StyleProps โ€” Visual Styling

Property Type Description
textStyle TextStyle? Input text styling
borderRadius double? Input field corner radius
padding EdgeInsets? Widget padding
inputDecoration InputDecoration? Custom input decoration
StyleProps(
  textStyle: TextStyle(fontSize: 16, color: Colors.black87),
  borderRadius: 8.0,
  padding: EdgeInsets.all(16),
)

๐Ÿ”„ Online vs Offline Mode

Online Mode (Production)

Set isOffline: false and provide API endpoints:

KYCTextBox(
  isOffline: false,
  apiUrl: 'https://your-api.com/verify/pan',
  token: 'Bearer your-auth-token',
  // ... other properties
)

Offline Mode (Testing/Development)

Set isOffline: true and provide asset paths:

KYCTextBox(
  isOffline: true,
  assetPath: 'assets/mock_data/pan_response.json',
  // ... other properties
)

Setup for Offline Mode:

  1. Create mock JSON files in your assets folder:
assets/
โ””โ”€โ”€ mock_data/
    โ”œโ”€โ”€ pan_response.json
    โ”œโ”€โ”€ aadhaar_response.json
    โ””โ”€โ”€ voter_response.json
  1. Add to pubspec.yaml:
flutter:
  assets:
    - assets/mock_data/
  1. Example mock response (pan_response.json):
{
  "Success": true,
  "PanValidation": {
    "success": true,
    "name": "John Doe",
    "panNumber": "ABCDE1234F"
  }
}

โš ๏ธ Error Handling

Handle verification results using callbacks:

KYCTextBox(
  onSuccess: (response) {
    // response.data contains the verification result
    final data = response.data;
    print('Verification successful!');
    print('Name: ${data['name']}');
  },
  onError: (error) {
    // Handle different error scenarios
    if (error.toString().contains('network')) {
      showDialog(/* Network error dialog */);
    } else if (error.toString().contains('invalid')) {
      showDialog(/* Invalid document dialog */);
    } else {
      showDialog(/* Generic error dialog */);
    }
  },
  // ... other properties
)

Error Types

Exception Description
NetworkException Network connectivity issues
ValidationException Invalid input format
AuthException Authentication/token errors
ConfigurationException Missing or invalid configuration
OtpException OTP verification failures

๐Ÿงช Testing

Widget Test Example

testWidgets('PAN verification widget renders correctly', (tester) async {
  await tester.pumpWidget(
    MaterialApp(
      home: Scaffold(
        body: ReactiveFormBuilder(
          form: () => FormGroup({
            'pan': FormControl<String>(),
          }),
          builder: (context, form, child) {
            return KYCTextBox(
              formProps: FormProps(
                formControlName: 'pan',
                label: 'PAN Number',
                mandatory: true,
              ),
              verificationType: VerificationType.pan,
              validationPattern: RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]$'),
              isOffline: true,
              assetPath: 'assets/mock_data/pan_response.json',
              // ... other required properties
            );
          },
        ),
      ),
    ),
  );

  expect(find.text('PAN Number'), findsOneWidget);
  expect(find.text('Verify'), findsOneWidget);
});

๐Ÿ“š API Quick Reference

Core Classes

Class Purpose
KYCTextBox Main verification widget (input + button)
KYCInputField Standalone input field only
VerifyButton Standalone verify button only
FormProps Input field configuration
ButtonProps Button configuration
StyleProps Visual styling configuration

Verification Types (Enum)

enum VerificationType {
  aadhaar,   // Aadhaar card (12 digits, OTP required)
  pan,       // PAN card (10 characters)
  voterId,   // Voter ID (10 characters)
  gst,       // GST number (15 characters)
  passport,  // Passport number (8 characters)
}

๐Ÿค Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

๐Ÿ“ License

MIT License โ€” see LICENSE for details.

๐Ÿ“ž Support


Made with โค๏ธ for the Mobile Development Team

Libraries

kyc_validation
main