kenal_ekyc_sdk 1.1.0 copy "kenal_ekyc_sdk: ^1.1.0" to clipboard
kenal_ekyc_sdk: ^1.1.0 copied to clipboard

Kenal eKYC SDK for Flutter applications

kenal_ekyc_sdk #

A Flutter SDK for integrating Kenal's eKYC solution in your applications.

Installation #

Add the SDK package to your pubspec.yaml:

dependencies:
  kenal_ekyc_sdk: ^1.1.0

Then run:

flutter pub get

Usage #

Initializing the SDK #

import 'package:kenal_ekyc_sdk/kenal_ekyc_sdk.dart';

await KenalClient.initialize(
  KenalClientConfig(
    apiKey: "YOUR_API_KEY",
    environment: "sandbox", // or 'production'
  ),
);

The Ekyc service provides a unified interface for all document types including Passport, MyKad, MyPR, MyTentera, and AML checks. This is the recommended approach for new integrations.

Starting Verification #

import 'package:flutter/material.dart';
import 'package:kenal_ekyc_sdk/kenal_ekyc_sdk.dart';

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

  @override
  State<EkycScreen> createState() => _EkycScreenState();
}

class _EkycScreenState extends State<EkycScreen> {
  String? verificationUrl;

  Future<void> startVerification() async {
    try {
      final result = await Ekyc.startVerification(
        EkycStartParams(
          refId: "customer-12345",
          name: "JOHN DOE",
          idNumber: "990101011234",
          // Add other optional parameters based on document type
        ),
      );

      setState(() {
        verificationUrl = result.fullURL;
      });

      print("Verification started: $result");
    } catch (error) {
      print("Verification error: $error");
      // Show error dialog
    }
  }

  @override
  Widget build(BuildContext context) {
    if (verificationUrl != null) {
      return KenalWebView(
        url: verificationUrl!,
        onComplete: (data) => print("Verification completed: $data"),
        onError: (error) => print("WebView error: $error"),
      );
    }

    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: startVerification,
          child: const Text('Start Verification'),
        ),
      ),
    );
  }
}

Parameters by Document Type #

Required for All Document Types

  • refId (String, required) - Your unique reference identifier for this verification

Passport Verification

await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "JOHN DOE",              // Required
    idNumber: "A12345678",         // Required (Passport number)
    docIssueCountry: "USA",        // Required (ISO 3166-1 alpha-3 code)
  ),
);

Required Fields:

  • name - Full name as on passport (always required)
  • idNumber - Passport number (always required)
  • docIssueCountry - Country that issued the passport (always required)

MyKad Verification

await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "AHMAD BIN ABDULLAH",    // Required if AutofillFromOCR disabled
    idNumber: "990101011234",      // Required if AutofillFromOCR disabled
  ),
);

Required Fields:

  • name - Full name as on MyKad (required only if AutofillFromOCR is disabled)
  • idNumber - 12-digit MyKad number (required only if AutofillFromOCR is disabled)

Note: If your workflow has AutofillFromOCR enabled, these fields are optional and will be extracted from the ID card.

MyPR Verification

await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "TAN AH KOW",            // Required if AutofillFromOCR disabled
    idNumber: "A1234567",          // Required if AutofillFromOCR disabled (MyPR number)
  ),
);

Required Fields:

  • name - Full name as on MyPR (required only if AutofillFromOCR is disabled)
  • idNumber - MyPR number (required only if AutofillFromOCR is disabled)

MyTentera Verification

await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "MOHD FAIZAL",           // Required if AutofillFromOCR disabled
    idNumber: "850315021234",      // Required if AutofillFromOCR disabled
    armyNumber: "ATM123456",       // Required if AutofillFromOCR disabled
  ),
);

Required Fields:

  • name - Full name (required only if AutofillFromOCR is disabled)
  • idNumber - IC number (required only if AutofillFromOCR is disabled)
  • armyNumber - Military service number (required only if AutofillFromOCR is disabled)

AML Check Only

await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "JOHN DOE",              // Required
    birthdate: "1985-06-20",       // Optional
    nationality: "MYS",            // Optional
  ),
);

Required Fields:

  • name - Full name (always required for standalone AML checks)

Note: For AML checks, other fields like birthdate, nationality, and idNumber are optional but recommended for more accurate results.


Recovery links allow users to resume incomplete verifications. You can generate them using the validationId from a previous verification.

Future<void> generateRecoveryLink(String validationId) async {
  try {
    final recovery = await Ekyc.generateRecoveryLink(
      GenerateRecoveryLinkParams(
        validationId: validationId,
      ),
    );
    
    // Open the recovery link in KenalWebView
    setState(() {
      verificationUrl = recovery.fullURL;
    });
  } catch (error) {
    print("Recovery link error: $error");
  }
}

Response:

class GenerateRecoveryLinkData {
  final String token;        // JWT token for the recovery session
  final String fullURL;      // Full URL to resume verification
  final int expiresAt;       // Unix timestamp in milliseconds when link expires
}

Important Notes:

  • Recovery links expire after 1 hour
  • The recovery link allows users to continue from where they left off

Bringing it together in a minimal form:

// Start a verification
final start = await Ekyc.startVerification(
  EkycStartParams(
    refId: "customer-12345",
    name: "JOHN DOE",
  ),
);

// Later, using a validationId obtained from Kenal callback or your backend
final recovery = await Ekyc.generateRecoveryLink(
  GenerateRecoveryLinkParams(
    validationId: "your-validation-id",
  ),
);

print(recovery.fullURL);              // URL to resume verification
print(recovery.token);                // Recovery token
print(recovery.expiresAt);            // Expiry time in milliseconds

Legacy Document-Specific Services #

The following services are maintained for backward compatibility. For new integrations, use the unified Ekyc service above.

MyKad Verification #

import 'package:flutter/material.dart';
import 'package:kenal_ekyc_sdk/kenal_ekyc_sdk.dart';

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

  @override
  State<MyKadScreen> createState() => _MyKadScreenState();
}

class _MyKadScreenState extends State<MyKadScreen> {
  String? ekycUrl;

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

  Future<void> _initializeClient() async {
    await KenalClient.initialize(
      KenalClientConfig(
        apiKey: "YOUR_API_KEY",
        environment: "sandbox",
      ),
    );
  }

  Future<void> startVerification() async {
    try {
      final result = await MyKad.start(
        MyKadParams(
          name: 'JOHN DOE',
          idNumber: '900101014321',
          refId: 'REF12345',
          useOCRForData: false, // Set to true to use OCR for data extraction
        ),
      );

      setState(() {
        ekycUrl = result.fullURL;
      });
    } catch (error) {
      print("Verification error: $error");
    }
  }

  @override
  Widget build(BuildContext context) {
    if (ekycUrl != null) {
      return KenalWebView(
        url: ekycUrl!,
        onComplete: (data) {
          print("Verification completed: $data");
          setState(() => ekycUrl = null);
        },
        onError: (error) => print("WebView error: $error"),
      );
    }

    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: startVerification,
          child: const Text('Start MyKad Verification'),
        ),
      ),
    );
  }
}

MyKad Parameters:

  • name - Full name (required if useOCRForData is false)
  • idNumber - 12-digit MyKad number (required if useOCRForData is false)
  • refId - Your unique reference ID (required)
  • useOCRForData - Set to true to extract data via OCR (optional, default: false)

Passport Verification #

import 'package:flutter/material.dart';
import 'package:kenal_ekyc_sdk/kenal_ekyc_sdk.dart';

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

  @override
  State<PassportScreen> createState() => _PassportScreenState();
}

class _PassportScreenState extends State<PassportScreen> {
  String? ekycUrl;

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

  Future<void> _initializeClient() async {
    await KenalClient.initialize(
      KenalClientConfig(
        apiKey: "YOUR_API_KEY",
        environment: "sandbox",
      ),
    );
  }

  Future<void> startVerification() async {
    try {
      final result = await Passport.start(
        PassportParams(
          name: 'JOHN DOE',
          passportNumber: 'A12345678',
          docIssueCountry: 'USA',
          refId: 'REF12345',
        ),
      );

      setState(() {
        ekycUrl = result.fullURL;
      });
    } catch (error) {
      print("Verification error: $error");
    }
  }

  @override
  Widget build(BuildContext context) {
    if (ekycUrl != null) {
      return KenalWebView(
        url: ekycUrl!,
        onComplete: (data) {
          print("Verification completed: $data");
          setState(() => ekycUrl = null);
        },
        onError: (error) => print("WebView error: $error"),
      );
    }

    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: startVerification,
          child: const Text('Start Passport Verification'),
        ),
      ),
    );
  }
}

Passport Parameters:

  • name - Full name as on passport (required)
  • passportNumber - Passport number (required)
  • docIssueCountry - Country that issued the passport (required)
  • refId - Your unique reference ID (required)

API Reference #

KenalClient #

Initializes the SDK with your API key and environment settings.

await KenalClient.initialize(
  KenalClientConfig(
    apiKey: "YOUR_API_KEY",
    environment: "sandbox", // or "production"
  ),
);

Ekyc #

Unified service for all document types and AML checks.

Ekyc.startVerification(params)

Starts a new eKYC verification process.

Returns: Future<EkycStartData>

class EkycStartData {
  final String token;     // JWT token for the verification session
  final String fullURL;   // Full URL to open in KenalWebView
}

Ekyc.generateRecoveryLink(params)

Generates a recovery link for an existing verification session.

Returns: Future<GenerateRecoveryLinkData>

class GenerateRecoveryLinkData {
  final String token;        // JWT token for the recovery session
  final String fullURL;      // Full URL to resume verification
  final int expiresAt;       // Unix timestamp (seconds) when link expires
}

MyKad (Legacy) #

Static service for MyKad verification.

Future<MyKadData> MyKad.start(MyKadParams params)

Returns: MyKadData with fullURL property.

Passport (Legacy) #

Static service for Passport verification.

Future<PassportData> Passport.start(PassportParams params)

Returns: PassportData with fullURL property.

KenalWebView #

Widget for displaying the eKYC verification flow.

KenalWebView(
  url: String,                          // Required: verification URL
  onComplete: (data) {},               // Called when verification completes
  onError: (error) {},                 // Called on error
  onExceedMaxRetries: (data) {},       // Called when user exceeds max retries
  onMessage: (message) {},             // Called for custom messages
  loader: Widget?,                      // Optional: custom loading widget
)

Permissions Setup #

To ensure the eKYC flow works correctly, you need to set up the necessary permissions for camera access in both Android and iOS platforms.

Android (AndroidManifest.xml) android/app/src/main/AndroidManifest.xml #

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.CAMERA"/>

  <application
    android:label="kenal_ekyc_demo_flutter"
    android:name="${applicationName}"
    android:icon="@mipmap/ic_launcher"
    android:usesCleartextTraffic="true">

    // Other configurations...

    <provider
        android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
        android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>
  </application>
</manifest>

iOS (Info.plist) #

<key>NSCameraUsageDescription</key>
<string>Camera is required for eKYC verification</string>
0
likes
110
points
16
downloads

Publisher

unverified uploader

Weekly Downloads

Kenal eKYC SDK for Flutter applications

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, flutter_inappwebview, http, permission_handler

More

Packages that depend on kenal_ekyc_sdk