kenal_ekyc_sdk 1.1.0
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'
),
);
Unified eKYC Service (Recommended) #
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.
Generating Recovery Links #
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
Complete Example with Recovery Link #
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 ifuseOCRForDatais false)idNumber- 12-digit MyKad number (required ifuseOCRForDatais false)refId- Your unique reference ID (required)useOCRForData- Set totrueto 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>