Skip to main content

apenia_verify 0.0.6 copy "apenia_verify: ^0.0.6" to clipboard
apenia_verify: ^0.0.6 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:apenia_verify/apenia_verify_platform_interface.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';

import 'fake_platform.dart';

/// Real native camera capture on Android/iOS; fake capture on web/desktop.
final bool _realCapture = !kIsWeb &&
    (defaultTargetPlatform == TargetPlatform.android ||
        defaultTargetPlatform == TargetPlatform.iOS);

/// Flip to false to run against the real Apenia API instead of the mock.
const bool kUseMockBackend = true;

/// Which outcome the mock Apenia backend returns next (demo control).
String _scenario = 'approved';

http.Client _mockBackend() {
  return MockClient((req) async {
    // Stand-in for Apenia's ML validation endpoint — log what we'd send.
    if (req.url.path == '/v1/ml/validate') {
      debugPrint('ML PAYLOAD → ${req.body}');
      return http.Response('{"ok":true}', 200);
    }
    if (req.method == 'PUT') return http.Response('', 200);
    if (req.method == 'GET' &&
        req.url.path.startsWith('/v1/onboarding/sessions/')) {
      await Future<void>.delayed(const Duration(milliseconds: 500));
      return http.Response(_scenarioBody(req.url.pathSegments.last), 200,
          headers: {'content-type': 'application/json'});
    }
    return http.Response('{"error":"unexpected ${req.method} ${req.url}"}', 404);
  });
}

const _sampleDoc =
    '"document":{"type":"NATIONAL_ID","full_name":"Asha N. Mwangi",'
    '"id_number":"31245678","date_of_birth":"1994-06-12","sex":"F",'
    '"nationality":"Kenyan","expiry_date":"2031-06-11"}';

String _scenarioBody(String sessionId) {
  switch (_scenario) {
    case 'review':
      return '{"session_id":"$sessionId","status":"review","subject_id":"sub_demo",'
          '"result":{"face_match":{"score":0.72,"match":true},'
          '"liveness":{"score":0.90,"live":true},"voice":{"score":0.70},'
          '"identity_confidence":61,$_sampleDoc}}';
    case 'failed':
      return '{"session_id":"$sessionId","status":"failed","subject_id":null,'
          '"result":{"face_match":{"score":0.30,"match":false},'
          '"liveness":{"score":0.41,"live":false},"identity_confidence":18}}';
    default:
      return '{"session_id":"$sessionId","status":"completed","subject_id":"sub_demo",'
          '"result":{"face_match":{"score":0.96,"match":true},'
          '"liveness":{"score":0.98,"live":true},"voice":{"score":0.93},'
          '"identity_confidence":88,$_sampleDoc}}';
  }
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  if (!_realCapture) {
    ApeniaVerifyPlatform.instance = FakeApeniaVerifyPlatform();
  }

  await ApeniaVerify.initialize(
    kUseMockBackend ? _demoConfig() : _productionConfig(),
  );

  runApp(const ExampleApp());
}

/// ── Production wiring ───────────────────────────────────────────────────
/// The only Apenia-specific things the app holds are the base URL and the
/// **publishable** key. Your backend owns the secret (`sk_…`) and is the only
/// party that may call `POST /v1/onboarding/sessions`.
ApeniaConfig _productionConfig() => ApeniaConfig(
      baseUrl: 'https://verify.apenia.com',
      appKey: 'pk_YOUR_PUBLISHABLE_KEY',
      documentCaptureMode: DocumentCaptureMode.auto,
      // Optional: also push the on-device analysis to your ML service. It
      // already travels inside the upload manifest either way.
      analysisEndpoint: '/v1/ml/validate',
      sessionProvider: (req) async {
        // Call YOUR backend, which in turn calls Apenia with the secret key
        // and returns { session_id, upload_url, client_token }.
        //
        //   final json = await myBackend.createSession(
        //     flow: req.flow,                // biometric_kyc | doc_verification | …
        //     metadata: req.params.toJson(), // user_id, job_id, customer_ref…
        //   );
        //   return ApeniaSession.fromJson(json);
        throw UnimplementedError('Wire sessionProvider to your backend');
      },
    );

/// ── Demo wiring ─────────────────────────────────────────────────────────
/// Fakes the session and the API so the whole flow can be exercised with no
/// backend at all. Never ship `httpClient` in production.
ApeniaConfig _demoConfig() => ApeniaConfig(
      baseUrl: 'https://mock.apenia',
      appKey: 'pk_demo',
      documentCaptureMode: DocumentCaptureMode.auto,
      analysisEndpoint: '/v1/ml/validate',
      sessionProvider: (req) async => const ApeniaSession(
        sessionId: 'onb_demo',
        uploadUrl: 'https://mock.apenia/uploads/onb_demo',
        clientToken: 'cst_demo',
      ),
      httpClient: _mockBackend(),
    );

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Apenia Verify',
      debugShowCheckedModeBanner: false,
      theme: ApeniaTheme.light(),
      home: const OnboardingHost(),
    );
  }
}

/// Hosts the single-entry [ApeniaOnboarding], restarting it after completion
/// so the demo can be run repeatedly.
class OnboardingHost extends StatefulWidget {
  const OnboardingHost({super.key});
  @override
  State<OnboardingHost> createState() => _OnboardingHostState();
}

class _OnboardingHostState extends State<OnboardingHost> {
  Key _runKey = UniqueKey();

  void _restart() => setState(() => _runKey = UniqueKey());

  @override
  Widget build(BuildContext context) {
    return ApeniaOnboarding(
      key: _runKey,
      badgeLabel: 'Sandbox',
      params: const PartnerParams(userId: 'user-123', jobId: 'job-demo'),
      onComplete: (verdict) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Result: ${verdict.status.name}')),
        );
        _restart();
      },
      // Demo-only: pick what the mock backend returns.
      introActions: [
        PopupMenuButton<String>(
          tooltip: 'Demo outcome',
          icon: const Icon(Icons.tune_rounded),
          initialValue: _scenario,
          onSelected: (v) => _scenario = v,
          itemBuilder: (_) => const [
            PopupMenuItem(value: 'approved', child: Text('Outcome: Approved')),
            PopupMenuItem(value: 'review', child: Text('Outcome: Needs review')),
            PopupMenuItem(value: 'failed', child: Text('Outcome: Failed')),
          ],
        ),
      ],
    );
  }
}
0
likes
0
points
236
downloads

Publisher

unverified uploader

Weekly Downloads

Apenia Verify — KYC capture SDK. Native active-liveness selfie + document scan; matching runs server-side in Apenia Verify.

Homepage

License

unknown (license)

Dependencies

archive, flutter, http, plugin_platform_interface

More

Packages that depend on apenia_verify

Packages that implement apenia_verify