Skip to main content

Usage

Starting the flow​

AzakawKyc.start presents the onboarding flow and resolves once the user leaves it.

import 'package:azakaw_kyc_flutter/azakaw_kyc_flutter.dart';

final result = await AzakawKyc.start(
context: context,
config: AzakawKycConfig(
sessionId: sessionId,
region: AzakawRegion.uae,
environment: AzakawEnvironment.sandbox,
),
);

Handling the result​

switch (result.status) {
case AzakawKycStatus.completed:
// The portal reported the onboarding finished.
// Confirm server-side before treating the user as verified.
break;

case AzakawKycStatus.cancelled:
// The user closed the flow, via the close button or the system back
// gesture. Both route through a confirmation dialog.
break;

case AzakawKycStatus.failed:
// The portal could not be loaded.
debugPrint('${result.error}');
break;
}

If you prefer callbacks, start also accepts onComplete, onCancel and onError. Note they do not all carry the same payload:

CallbackReceives
onCompleteAzakawKycResult — status and sessionId
onCancelAzakawKycResult — status and sessionId
onErrorAzakawKycException only — message, statusCode, url

The returned future always resolves to an AzakawKycResult, so a failure reaches you there as AzakawKycStatus.failed with the exception on result.error.

await AzakawKyc.start(
context: context,
config: config,
onComplete: (result) => debugPrint('done'),
onCancel: (result) => debugPrint('cancelled'),
onError: (error) => debugPrint('$error'),
);
warning

Treat AzakawKycStatus.completed as a hint to re-check, not as proof. It means the portal signalled completion on the device; always verify the session's real state against the Azakaw API before granting access.

Embedding in your own layout​

Use AzakawKycView to place the flow inside a screen you control rather than a full-screen route:

class VerifyScreen extends StatefulWidget {
const VerifyScreen({super.key, required this.config});

final AzakawKycConfig config;

@override
State<VerifyScreen> createState() => _VerifyScreenState();
}

class _VerifyScreenState extends State<VerifyScreen> {
// Attach this to the view to drive it from your own chrome.
final _kycKey = GlobalKey<AzakawKycViewState>();

Future<void> _close() async {
// Shows the same confirmation the built-in close button uses. When the
// user confirms, requestClose() calls onCancelled itself — so don't pop
// here too, or you pop twice and leave the screen underneath as well.
await _kycKey.currentState?.requestClose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Verify your identity'),
leading: IconButton(icon: const Icon(Icons.close), onPressed: _close),
),
body: AzakawKycView(
key: _kycKey,
config: widget.config,
onCompleted: () => Navigator.of(context).pop(true),
onCancelled: () => Navigator.of(context).pop(false),
onError: (error) => debugPrint('$error'),
),
);
}
}

AzakawKycViewState.currentError reports the failure currently on screen, or null once a retry has cleared it — read it rather than caching a copy, which would go stale after a successful retry.

Language and RTL​

AzakawKycConfig(
sessionId: sessionId,
language: AzakawLanguage.ar, // Arabic, with RTL layout
);

Leaving language as null keeps whatever the portal defaults to.

Any http/https navigation stays inside the WebView, including the tenant domain the portal may redirect to and third-party pages it embeds such as e-signing. Other schemes (mailto:, tel:, app links) are cancelled and handed to your app:

AzakawKyc.start(
context: context,
config: config,
onExternalUrl: (url) => launchUrl(url), // package:url_launcher
);

On Android 11+, url_launcher can only open mailto: and tel: links if your AndroidManifest.xml declares them inside <queries>:

<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
</queries>

How the SDK talks to the portal​

The Web SDK is a parent page holding an iframe, so the portal's postMessage calls cross a frame boundary. A Flutter WebView has no parent frame, so the SDK reports the portal's own origin as hostOrigin and injects a script at document start that forwards the portal's messages to Dart.

This is what makes completion detection possible: the portal only emits events when a hostOrigin is present.

Supported events:

EventDirectionHandling
OnboardingCompletedportal → SDKResolves with AzakawKycStatus.completed.
IframeParametersRequestportal → SDKAnswered with hideSidebar and hideOnboardingSections.
IframeParametersResponseSDK → portalThe only message the SDK sends.
TenantBaseUrlportal → SDKReloads the flow on the tenant's own host.
ResizeIframeportal → SDKIgnored — a WebView fills its own box and the portal scrolls inside it.