apex_kyc 1.1.4
apex_kyc: ^1.1.4 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 [...]
Apex KYC Flutter SDK #
The complete Flutter SDK for KYC verification β document capture, liveness detection, and seamless backend integration.
π Full Documentation Β· π KYC Web App Β· π Website Β· π Issues
Table of contents #
- Installation
- Choose your integration
- Way 1 β Native Flutter SDK
- Way 2 β WebView inside Flutter
- Way 3 β External browser / link
- Getting an applicant ID
- API reference
- Webhooks
- Verification types
- Platform setup
- Support
Full interactive API reference, Flutter SDK examples, and webhook documentation are available at apexkyc.com/docs.
Installation π¦ #
dependencies:
apex_kyc: ^1.1.4
flutter pub get
Choose your integration π #
Pick the approach that fits your product:
| Way 1 β Native SDK | Way 2 β WebView | Way 3 β Browser link | |
|---|---|---|---|
| UX | β Best native | π‘ Good embedded | π΅ Opens browser |
| Camera | Native device | Web in WebView | Web in browser |
Requires apex_kyc |
β Yes | For applicant creation | Optional |
| Extra package | None | webview_flutter |
url_launcher |
| Best for | Mobile-first apps | Hybrid apps | Email/SMS links, web |
Way 1 β Native Flutter SDK (recommended) π’ #
Full in-app experience: native camera, randomised liveness challenges, and document capture β all inside your Flutter app.
Step 1 β Initialize once in main() #
import 'package:apex_kyc/index.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
ApexKycConfig.initialize(
apiKey: 'your-api-key', // From https://apexkyc.com/ β Dashboard β API Keys
// baseUrl defaults to https://api.apexkyc.com
);
runApp(const MyApp());
}
Step 2 β Get an applicantId #
An applicant is a person going through KYC. You must get their id from the API before starting the flow.
Using the SDK (simplest)
final service = SdkVerificationService();
final applicant = await service.createApplicant(
customerIdentifier: 'user-12345', // Your stable internal user ID or email
fullName: 'Jane Doe', // Optional
email: 'jane@example.com', // Optional
);
final String applicantId = applicant.id; // β pass this to ApexKycFlowWidget
β Same
customerIdentifierβ same applicant returned (no duplicates ever created).
Step 3 β Launch the KYC flow #
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ApexKycFlowWidget(
applicantId: applicantId,
showProgress: true,
onComplete: (SdkVerificationResponse verification) {
print('β
Done: ${verification.id} β ${verification.status}');
},
onError: (String error) {
print('β Error: $error');
},
),
),
);
Full working example #
import 'package:flutter/material.dart';
import 'package:apex_kyc/index.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
ApexKycConfig.initialize(apiKey: 'your-api-key');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
title: 'KYC Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const KycScreen(),
);
}
class KycScreen extends StatefulWidget {
const KycScreen({super.key});
@override
State<KycScreen> createState() => _KycScreenState();
}
class _KycScreenState extends State<KycScreen> {
final _service = SdkVerificationService();
String? _applicantId;
bool _loading = false;
String? _error;
Future<void> _getApplicant() async {
setState(() { _loading = true; _error = null; });
try {
final applicant = await _service.createApplicant(
customerIdentifier: 'demo-user-001',
fullName: 'Demo User',
email: 'demo@example.com',
);
setState(() { _applicantId = applicant.id; _loading = false; });
} catch (e) {
setState(() { _error = e.toString(); _loading = false; });
}
}
Future<void> _startKyc() async {
if (_applicantId == null) return;
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ApexKycFlowWidget(
applicantId: _applicantId!,
showProgress: true,
onComplete: (v) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('β
Verification done β ${v.status}'),
backgroundColor: Colors.green,
));
},
onError: (e) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('β $e'),
backgroundColor: Colors.red,
));
},
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Identity Verification')),
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Complete identity verification to continue.',
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 24),
if (_error != null)
Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Text(_error!, style: TextStyle(color: Colors.red.shade700)),
),
if (_applicantId == null)
FilledButton.icon(
icon: const Icon(Icons.person_add),
label: Text(_loading ? 'Please waitβ¦' : 'Start verification'),
onPressed: _loading ? null : _getApplicant,
)
else
FilledButton.icon(
icon: const Icon(Icons.verified_user),
label: const Text('Verify my identity'),
onPressed: _startKyc,
),
],
),
),
);
}
}
Way 2 β WebView inside Flutter π‘ #
Embed the hosted KYC web app (kyc.apexkyc.com) inside your Flutter app using webview_flutter. The SDK is still used to create the applicant; the KYC UI runs in-app but on a web page.
Setup #
dependencies:
apex_kyc: ^1.1.4 # Create applicant
webview_flutter: ^4.0.0 # Embed the web app
Get the KYC URL #
// Initialize config first (same as Way 1)
ApexKycConfig.initialize(apiKey: 'your-api-key');
final service = SdkVerificationService();
final applicant = await service.createApplicant(
customerIdentifier: 'user-12345',
);
// Prefer kycWebUrl from the API; fall back to the public URL pattern
final String kycUrl = applicant.kycWebUrl?.isNotEmpty == true
? applicant.kycWebUrl!
: 'https://kyc.apexkyc.com/?id=${applicant.id}';
Embed the WebView #
import 'package:webview_flutter/webview_flutter.dart';
class KycWebViewScreen extends StatefulWidget {
final String kycUrl;
const KycWebViewScreen({super.key, required this.kycUrl});
@override
State<KycWebViewScreen> createState() => _KycWebViewScreenState();
}
class _KycWebViewScreenState extends State<KycWebViewScreen> {
late final WebViewController _controller;
bool _loading = true;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (_) => setState(() => _loading = true),
onPageFinished: (_) => setState(() => _loading = false),
))
..loadRequest(Uri.parse(widget.kycUrl));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Identity Verification'),
leading: const CloseButton(),
),
body: Stack(
children: [
WebViewWidget(controller: _controller),
if (_loading) const Center(child: CircularProgressIndicator()),
],
),
);
}
}
Open it #
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => KycWebViewScreen(kycUrl: kycUrl),
),
);
Android: Camera access in WebView requires the permissions in the Platform setup section below.
Way 3 β External browser / link π΅ #
No Flutter KYC widgets at all. Create an applicant on your backend and open the KYC web app in the device's default browser β or send the link by email/SMS.
Flutter (with url_launcher) #
dependencies:
url_launcher: ^6.0.0
apex_kyc: ^1.1.4 # Optional β only if you also create the applicant in Flutter
import 'package:url_launcher/url_launcher.dart';
import 'package:apex_kyc/index.dart';
Future<void> openKycInBrowser(SdkApplicantResponse applicant) async {
// Prefer the ready-made URL from the API
final String raw = applicant.kycWebUrl?.isNotEmpty == true
? applicant.kycWebUrl!
: 'https://kyc.apexkyc.com/?id=${applicant.id}';
final uri = Uri.parse(raw);
if (!await launchUrl(uri, mode: LaunchMode.externalApplication)) {
throw Exception('Could not open $raw');
}
}
Backend only (no Flutter) #
# 1. Create applicant on your server
curl -X POST "https://api.apexkyc.com/sdk/kyc-verification/applicants" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"customerIdentifier": "user-12345", "email": "jane@example.com"}'
# Response β { "id": "664f...", "kycWebUrl": "https://kyc.apexkyc.com/?id=664f..." }
# 2. Send kycWebUrl to the user via email / SMS / push notification
# The user clicks it β completes KYC in their browser β no app install needed
Getting an applicant ID πͺͺ #
Every KYC flow requires an applicant ID. This ID is always created and stored server-side β you never invent it in the UI.
SDK helper methods #
| Method | When to use |
|---|---|
createApplicant(customerIdentifier: ...) |
Always safe to call β creates or returns the existing record |
findApplicantByIdentifier(id) |
Look up without creating |
findApplicantByEmail(email) |
Look up by email |
getApplicant(applicantId) |
Fetch full details when you already have the ID |
HTTP API (any language / Postman) #
Endpoint: POST https://api.apexkyc.com/sdk/kyc-verification/applicants
Headers
| Header | Value |
|---|---|
Content-Type |
application/json |
X-API-Key |
Your SDK API key |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
customerIdentifier |
string | β Yes | Stable unique ID in your system |
fullName |
string | No | |
email |
string | No | |
phone |
string | No | |
dateOfBirth |
string | No | ISO date: 1990-01-15 |
nationality |
string | No |
Response
| Field | Description |
|---|---|
id |
Applicant ID β use as applicantId |
customerIdentifier |
Echo of what you sent |
kycWebUrl |
Ready-to-open link (e.g. https://kyc.apexkyc.com/?id=...) β present when backend has KYC_WEB_APP_URL set |
createdAt |
ISO timestamp |
API reference π‘ #
Interactive reference with live try-it fields β apexkyc.com/docs
Base URL: https://api.apexkyc.com/sdk/kyc-verification
All requests need: X-API-Key: your-api-key
Applicants #
| Method | Path | Description |
|---|---|---|
POST |
/applicants |
Create (or resolve) applicant |
GET |
/applicants |
List all applicants (supports ?email= ?identifier=) |
GET |
/applicants/:id |
Get applicant by ID |
Verifications #
| Method | Path | Description |
|---|---|---|
POST |
/applicants/:id/verifications |
Create a verification request |
GET |
/verifications/:id |
Get verification status & results |
PATCH |
/verifications/:id/verification-type |
Change document type |
GET |
/applicants/:id/verifications |
List all verifications for an applicant |
Documents #
| Method | Path | Description |
|---|---|---|
POST |
/verifications/:id/documents |
Upload a single document image |
POST |
/verifications/:id/documents/batch |
Upload front + back in one call |
Liveness #
| Method | Path | Description |
|---|---|---|
POST |
/verifications/:id/liveness |
Upload a liveness frame |
POST |
/verifications/:id/liveness/batch |
Upload multiple liveness frames |
Config #
| Method | Path | Description |
|---|---|---|
GET |
/config |
SDK config (branding, kycWebUrl, feature flags) |
Full cURL examples #
# Create applicant
curl -X POST "https://api.apexkyc.com/sdk/kyc-verification/applicants" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"customerIdentifier":"user-12345","fullName":"Jane Doe","email":"jane@example.com"}'
# Get applicant
curl "https://api.apexkyc.com/sdk/kyc-verification/applicants/APPLICANT_ID" \
-H "X-API-Key: your-api-key"
# Create verification (ID_CARD | PASSPORT | NATIONAL_ID | DRIVING_LICENSE)
curl -X POST "https://api.apexkyc.com/sdk/kyc-verification/applicants/APPLICANT_ID/verifications" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"verificationType":"ID_CARD"}'
# Get verification status
curl "https://api.apexkyc.com/sdk/kyc-verification/verifications/VERIFICATION_ID" \
-H "X-API-Key: your-api-key"
Webhooks π #
Apex KYC sends HTTP POST requests to your configured webhook URL when events occur.
Configure webhooks in your dashboard or via the Webhooks API. For payload format, retry policy, and signature verification, see apexkyc.com/docs β Webhooks tab.
Applicant events #
| Event | Triggered when |
|---|---|
applicant.created |
New applicant created |
applicant.updated |
Applicant info updated |
applicant.deleted |
Applicant deleted |
Verification events #
| Event | Triggered when |
|---|---|
verification.created |
Verification request created |
verification.started |
Processing begins |
verification.completed |
Successfully completed |
verification.failed |
Verification failed |
verification.rejected |
Verification rejected |
verification.cancelled |
Verification cancelled |
verification.retry |
User retries verification |
Document events #
| Event | Triggered when |
|---|---|
document.uploaded |
Any document uploaded |
document.front.uploaded |
Front side uploaded |
document.back.uploaded |
Back side uploaded |
documents.uploaded |
All required documents received |
Liveness events #
| Event | Triggered when |
|---|---|
liveness.started |
Liveness check begins |
liveness.completed |
Liveness check passed |
liveness.failed |
Liveness check failed |
liveness.frame.uploaded |
A frame is uploaded |
Manual review events #
| Event | Triggered when |
|---|---|
manual_review.required |
Review required by a human agent |
manual_review.approved |
Reviewer approved the verification |
manual_review.rejected |
Reviewer rejected the verification |
Verification types π #
| Type constant | Document |
|---|---|
PASSPORT |
International passport |
ID_CARD |
National ID card (front + back) |
NATIONAL_ID |
Country-specific national ID |
DRIVING_LICENSE |
Driving licence (front + back) |
In Dart, use the VerificationType enum:
VerificationType.passport
VerificationType.idCard
VerificationType.nationalId
VerificationType.drivingLicense
Platform setup π§ #
Android #
Add inside <manifest> in android/app/src/main/AndroidManifest.xml:
<!-- Camera permission β required for liveness and document capture -->
<uses-permission android:name="android.permission.CAMERA"/>
For WebView camera (Way 2), also add inside <application>:
<uses-feature android:name="android.hardware.camera" android:required="false"/>
iOS #
Add to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required for identity verification</string>
Support π¬ #
| Link | |
|---|---|
| π Full documentation | apexkyc.com/docs |
| π KYC web app | kyc.apexkyc.com |
| π Website & dashboard | apexkyc.com |
| π§ Email | contact.apexkyc@gmail.com |
License π #
MIT β see LICENSE file for details.