apenia_verify 0.0.7
apenia_verify: ^0.0.7 copied to clipboard
Apenia Verify — KYC capture SDK. Native active-liveness selfie + document scan; matching runs server-side in Apenia Verify.
example/lib/main.dart
import 'package:apenia_verify/apenia_verify.dart';
import 'package:flutter/material.dart';
/// Minimal end-to-end integration of the Apenia Verify capture SDK.
///
/// Two things live in the app: the API base URL and your **publishable** key.
/// The secret key (`sk_…`) never touches the handset — your own backend holds
/// it and is the only party that may create an onboarding session.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ApeniaVerify.initialize(
ApeniaConfig(
baseUrl: 'https://verify.apenia.com',
appKey: 'pk_YOUR_PUBLISHABLE_KEY',
// Documents capture automatically once detected in the frame; the
// shutter always remains available as a manual override.
documentCaptureMode: DocumentCaptureMode.auto,
// Your backend calls Apenia with the secret key and returns
// { session_id, upload_url, client_token }.
sessionProvider: (request) async {
final json = await _createSessionOnYourBackend(
flow: request.flow, // biometric_kyc | doc_verification | …
metadata: request.params.toJson(),
);
return ApeniaSession.fromJson(json);
},
),
);
runApp(const ExampleApp());
}
/// Stand-in for your own API client.
///
/// Server-side this is:
/// POST https://verify.apenia.com/v1/onboarding/sessions
/// X-App-Secret: sk_…
/// { "flow": "…", "metadata": { … } }
Future<Map<String, dynamic>> _createSessionOnYourBackend({
required String flow,
required Map<String, dynamic> metadata,
}) async {
throw UnimplementedError(
'Point this at your backend endpoint that creates an Apenia session.',
);
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Apenia Verify',
theme: ApeniaTheme.light(),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FilledButton(
onPressed: () => _startVerification(context),
child: const Text('Verify my identity'),
),
),
);
}
void _startVerification(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => ApeniaOnboarding(
// jobId must be stable across retries of the same attempt, so a
// resubmission can't create a duplicate KYC record.
params: PartnerParams(
userId: 'user-123',
jobId: 'job-${DateTime.now().millisecondsSinceEpoch}',
),
onComplete: (verdict) {
Navigator.of(context).pop();
// Branch on the decision, never on the individual scores — a
// strong face-match can still accompany a rejection.
final message = verdict.isApproved
? 'Verified'
: 'Not approved (${verdict.decision ?? verdict.status.name})';
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message)));
},
onExit: () => Navigator.of(context).pop(),
),
),
);
}
}