apex_kyc 1.0.3 copy "apex_kyc: ^1.0.3" to clipboard
apex_kyc: ^1.0.3 copied to clipboard

A comprehensive Flutter SDK for KYC (Know Your Customer) verification featuring document capture, real-time liveness detection with randomized challenges, and seamless backend integration. Supports mu [...]

example/lib/main.dart

import 'package:apex_kyc/index.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ApexKYC Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _initialized = false;
  SdkVerificationService? _service;

  // Step 1: Applicant Management
  final _customerIdentifierController = TextEditingController();
  final _emailController = TextEditingController();
  final _fullNameController = TextEditingController();
  String? _currentApplicantId;
  String? _applicantStatusMessage;
  bool _isLoadingApplicant = false;

  // Step 2: Verification
  SdkVerificationResponse? _sdkVerificationResponse;
  String? _errorMessage;

  @override
  void initState() {
    super.initState();
    _initializeSDK();
  }

  @override
  void dispose() {
    _customerIdentifierController.dispose();
    _emailController.dispose();
    _fullNameController.dispose();
    super.dispose();
  }

  void _initializeSDK() async {
    // Initialize the SDK with your backend URL
    // Replace with your actual backend URL and API key
    ApexKycConfig.initialize(
      baseUrl:
          'https://api.apexkyc.com', // Replace with your NestJS Backend URL
      apiKey: 'your-api-key-here', // Replace with your SDK API Key
      enableLogging: true, // Enable for debugging
    );

    setState(() {
      _service = SdkVerificationService();
      _initialized = true;
    });
  }

  /// Step 1: Create or Find Applicant ID
  ///
  /// This method demonstrates:
  /// - Creating a new applicant with a unique identifier
  /// - If the same identifier is used, it returns the existing applicant ID (no duplicate)
  /// - Each user/customer has only one applicant ID per unique identifier
  Future<void> _createOrFindApplicant() async {
    if (_service == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('SDK not initialized yet. Please wait...'),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    if (_customerIdentifierController.text.trim().isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Please enter a customer identifier'),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    setState(() {
      _isLoadingApplicant = true;
      _applicantStatusMessage = null;
      _errorMessage = null;
    });

    try {
      final applicantId = await _service!.createApplicant(
        customerIdentifier: _customerIdentifierController.text.trim(),
        email: _emailController.text.trim().isEmpty
            ? null
            : _emailController.text.trim(),
        fullName: _fullNameController.text.trim().isEmpty
            ? null
            : _fullNameController.text.trim(),
      );

      if (!mounted) return;
      setState(() {
        _currentApplicantId = applicantId;
        _applicantStatusMessage =
            'Applicant ID: $applicantId\n\n'
            '✓ If this identifier was used before, the existing applicant ID was returned.\n'
            '✓ If this is a new identifier, a new applicant was created.\n'
            '✓ Each customer has only one applicant ID per unique identifier.';
        _isLoadingApplicant = false;
      });

      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Applicant created/found successfully!'),
          backgroundColor: Colors.green,
        ),
      );
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _applicantStatusMessage = 'Error: ${e.toString()}';
        _isLoadingApplicant = false;
        _errorMessage = e.toString();
      });

      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error: ${e.toString()}'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  /// Find Applicant by Identifier or Email
  ///
  /// This method demonstrates:
  /// - Finding an existing applicant by their identifier or email
  /// - Useful when you know the identifier/email but need the applicant ID
  Future<void> _findApplicant() async {
    if (_service == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('SDK not initialized yet. Please wait...'),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    final searchTerm = _customerIdentifierController.text.trim().isEmpty
        ? _emailController.text.trim()
        : _customerIdentifierController.text.trim();

    if (searchTerm.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
            'Please enter a customer identifier or email to search',
          ),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    setState(() {
      _isLoadingApplicant = true;
      _applicantStatusMessage = null;
      _errorMessage = null;
    });

    try {
      final applicantId = await _service!.findApplicantByIdentifier(searchTerm);

      if (applicantId != null) {
        if (!mounted) return;
        setState(() {
          _currentApplicantId = applicantId;
          _applicantStatusMessage =
              'Found Applicant ID: $applicantId\n\n'
              '✓ Applicant found using identifier/email: $searchTerm';
          _isLoadingApplicant = false;
        });

        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Applicant found!'),
            backgroundColor: Colors.green,
          ),
        );
      } else {
        if (!mounted) return;
        setState(() {
          _applicantStatusMessage =
              'No applicant found with identifier/email: $searchTerm\n\n'
              'Tip: Use "Create/Find Applicant" to create a new applicant.';
          _isLoadingApplicant = false;
        });

        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Applicant not found'),
            backgroundColor: Colors.orange,
          ),
        );
      }
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _applicantStatusMessage = 'Error: ${e.toString()}';
        _isLoadingApplicant = false;
        _errorMessage = e.toString();
      });

      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error: ${e.toString()}'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  /// Step 2: Start KYC Verification
  ///
  /// This method demonstrates:
  /// - Starting the KYC verification flow using the applicant ID from Step 1
  /// - The verification flow handles document capture and liveness detection
  void _startKycFlow() {
    if (_currentApplicantId == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Please create or find an applicant first (Step 1)'),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => ApexKycFlowWidget(
          applicantId: _currentApplicantId!,
          progressStyle: ProgressIndicatorStyle.steps,
          showTips: false,
          showProgress: true,
          onComplete: (verification) {
            setState(() {
              _sdkVerificationResponse = verification;
            });
            Navigator.pop(context);
            if (mounted) {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('KYC verification completed!'),
                  backgroundColor: Colors.green,
                ),
              );
            }
          },
          onError: (error) {
            if (!mounted) return;
            setState(() {
              _errorMessage = error;
            });
            Navigator.pop(context);
            if (!mounted) return;
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Error: $error'),
                backgroundColor: Colors.red,
              ),
            );
          },
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    if (!_initialized) {
      return const Scaffold(body: Center(child: CircularProgressIndicator()));
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text('ApexKYC Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const Text(
              'KYC Verification SDK - Complete Flow',
              style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            const Text(
              'Follow these 2 steps to start verification',
              style: TextStyle(fontSize: 16, color: Colors.grey),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 32),

            // Step 1: Create/Find Applicant
            Card(
              elevation: 2,
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Container(
                          width: 32,
                          height: 32,
                          decoration: const BoxDecoration(
                            color: Colors.blue,
                            shape: BoxShape.circle,
                          ),
                          child: const Center(
                            child: Text(
                              '1',
                              style: TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ),
                        ),
                        const SizedBox(width: 12),
                        const Expanded(
                          child: Text(
                            'Step 1: Create or Find Applicant ID',
                            style: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 16),
                    const Text(
                      'Each user/customer needs a unique identifier. If you create an applicant with the same identifier, you will get the same applicant ID (no duplicates).',
                      style: TextStyle(color: Colors.grey),
                    ),
                    const SizedBox(height: 16),
                    TextField(
                      controller: _customerIdentifierController,
                      decoration: const InputDecoration(
                        labelText: 'Customer Identifier *',
                        hintText: 'e.g., user_12345, customer_abc',
                        border: OutlineInputBorder(),
                        helperText:
                            'Unique identifier for your customer (required)',
                      ),
                    ),
                    const SizedBox(height: 16),
                    TextField(
                      controller: _emailController,
                      decoration: const InputDecoration(
                        labelText: 'Email (Optional)',
                        hintText: 'customer@example.com',
                        border: OutlineInputBorder(),
                        helperText: 'You can also search by email later',
                      ),
                      keyboardType: TextInputType.emailAddress,
                    ),
                    const SizedBox(height: 16),
                    TextField(
                      controller: _fullNameController,
                      decoration: const InputDecoration(
                        labelText: 'Full Name (Optional)',
                        hintText: 'John Doe',
                        border: OutlineInputBorder(),
                      ),
                    ),
                    const SizedBox(height: 16),
                    Column(
                      children: [
                        SizedBox(
                          width: double.infinity,
                          child: ElevatedButton.icon(
                            onPressed: _isLoadingApplicant
                                ? null
                                : _createOrFindApplicant,
                            icon: _isLoadingApplicant
                                ? const SizedBox(
                                    width: 16,
                                    height: 16,
                                    child: CircularProgressIndicator(
                                      strokeWidth: 2,
                                    ),
                                  )
                                : const Icon(Icons.person_add),
                            label: const Text('Create/Find Applicant'),
                            style: ElevatedButton.styleFrom(
                              padding: const EdgeInsets.symmetric(vertical: 16),
                              backgroundColor: Colors.blue,
                              foregroundColor: Colors.white,
                            ),
                          ),
                        ),
                        const SizedBox(height: 12),
                        SizedBox(
                          width: double.infinity,
                          child: OutlinedButton.icon(
                            onPressed: _isLoadingApplicant
                                ? null
                                : _findApplicant,
                            icon: const Icon(Icons.search),
                            label: const Text('Find by ID/Email'),
                            style: OutlinedButton.styleFrom(
                              padding: const EdgeInsets.symmetric(vertical: 16),
                            ),
                          ),
                        ),
                      ],
                    ),
                    if (_applicantStatusMessage != null) ...[
                      const SizedBox(height: 16),
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: _currentApplicantId != null
                              ? Colors.green.shade50
                              : Colors.orange.shade50,
                          borderRadius: BorderRadius.circular(8),
                          border: Border.all(
                            color: _currentApplicantId != null
                                ? Colors.green.shade200
                                : Colors.orange.shade200,
                          ),
                        ),
                        child: Text(
                          _applicantStatusMessage!,
                          style: TextStyle(
                            color: _currentApplicantId != null
                                ? Colors.green.shade900
                                : Colors.orange.shade900,
                            fontSize: 14,
                          ),
                        ),
                      ),
                    ],
                  ],
                ),
              ),
            ),

            const SizedBox(height: 24),

            // Step 2: Start Verification
            Card(
              elevation: 2,
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Container(
                          width: 32,
                          height: 32,
                          decoration: BoxDecoration(
                            color: _currentApplicantId != null
                                ? Colors.green
                                : Colors.grey,
                            shape: BoxShape.circle,
                          ),
                          child: const Center(
                            child: Text(
                              '2',
                              style: TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ),
                        ),
                        const SizedBox(width: 12),
                        const Expanded(
                          child: Text(
                            'Step 2: Start KYC Verification',
                            style: TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 16),
                    const Text(
                      'Once you have an applicant ID, you can start the verification process. The flow will guide you through document capture and liveness detection.',
                      style: TextStyle(color: Colors.grey),
                    ),
                    const SizedBox(height: 16),
                    ElevatedButton.icon(
                      onPressed: _currentApplicantId != null
                          ? _startKycFlow
                          : null,
                      icon: const Icon(Icons.verified_user),
                      label: const Text('Start KYC Verification'),
                      style: ElevatedButton.styleFrom(
                        padding: const EdgeInsets.symmetric(vertical: 16),
                        backgroundColor: Colors.green,
                        foregroundColor: Colors.white,
                        minimumSize: const Size(double.infinity, 50),
                      ),
                    ),
                    if (_currentApplicantId == null)
                      Padding(
                        padding: const EdgeInsets.only(top: 8),
                        child: Text(
                          'Complete Step 1 first',
                          style: TextStyle(
                            color: Colors.grey.shade600,
                            fontSize: 12,
                            fontStyle: FontStyle.italic,
                          ),
                        ),
                      ),
                  ],
                ),
              ),
            ),

            // Verification Results
            if (_sdkVerificationResponse != null) ...[
              const SizedBox(height: 32),
              const Divider(),
              const SizedBox(height: 16),
              const Text(
                'Last Verification Result',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Request ID: ${_sdkVerificationResponse!.requestId}',
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'Status: ${_sdkVerificationResponse!.verificationStatus}',
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'Document Type: ${_sdkVerificationResponse!.documentType}',
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'Completion: ${_sdkVerificationResponse!.completionStatus.completionPercentage}%',
                      ),
                      if (_sdkVerificationResponse!.livenessPassed != null) ...[
                        const SizedBox(height: 8),
                        Text(
                          'Liveness Passed: ${_sdkVerificationResponse!.livenessPassed}',
                        ),
                      ],
                    ],
                  ),
                ),
              ),
            ],

            // Error Display
            if (_errorMessage != null) ...[
              const SizedBox(height: 16),
              Card(
                color: Colors.red.shade50,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Error',
                        style: TextStyle(
                          fontWeight: FontWeight.bold,
                          color: Colors.red,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text(
                        _errorMessage!,
                        style: TextStyle(color: Colors.red.shade700),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}
1
likes
130
points
--
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter SDK for KYC (Know Your Customer) verification featuring document capture, real-time liveness detection with randomized challenges, and seamless backend integration. Supports multiple document types (passport, ID card, driving license), customizable themes, company branding, and cross-platform compatibility (iOS & Android).

Homepage
Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

camera, collection, equatable, flutter, google_mlkit_face_detection, http, http_parser, image, image_picker, lottie, path_provider, plugin_platform_interface, screen_brightness, shared_preferences

More

Packages that depend on apex_kyc

Packages that implement apex_kyc