Configuration
Everything the host app controls is a field on AzakawKycConfig. The surface
mirrors the Web SDK, so a session behaves the same way on
web and on mobile.
final config = AzakawKycConfig(
sessionId: sessionId,
region: AzakawRegion.uae,
environment: AzakawEnvironment.sandbox,
hideSidebar: false,
hideOnboardingSections: false,
language: AzakawLanguage.en,
isFullscreen: true,
);
Options
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
sessionId | String | — | yes | Session id obtained from the Azakaw backend. Must be non-empty, or the constructor throws ArgumentError. |
region | AzakawRegion | uae | no | Selects the portal domain. |
environment | AzakawEnvironment | sandbox | no | Sandbox or production. Combined with region to pick the subdomain. |
hideSidebar | bool | false | no | Hides the sidebar on the onboarding page. |
hideOnboardingSections | bool | false | no | Starts the user on the first page of the form; the sections page stays hidden until onboarding completes. |
language | AzakawLanguage? | null | no | en or ar. ar also switches the portal to RTL. null leaves the portal's own default. |
isFullscreen | bool | true | no | Full-screen route, or an inset dialog. |
resolveTenantHost | bool | true | no | Opens the flow directly on the tenant's own domain. See Tenant domains. |
enableLogging | bool | false | no | Logs protocol traffic through debugPrint. Do not enable in release builds — payloads include the session id. |
hideSidebar and hideOnboardingSections are delivered to the portal over
the postMessage handshake rather than the URL, so they take effect once the
portal has booted rather than at load time. This is the same behaviour as the
Web SDK.
Environment and region
region selects the domain and environment selects the subdomain:
| Region | Domain | Sandbox | Production |
|---|---|---|---|
AzakawRegion.uae (default) | azakaw.com | sandbox.azakaw.com | app.azakaw.com |
AzakawRegion.ksa | azakawksa.com | — not available | app.azakawksa.com |
AzakawRegion.qatar | azakawqatar.com | — not available | app.azakawqatar.com |
AzakawRegion.kuwait | azakaw.com | kuwait-stg.azakaw.com | kuwait.azakaw.com |
Sandbox is provisioned for UAE and Kuwait. Pair ksa and qatar
with AzakawEnvironment.production; those combinations still compose a URL —
as they do in the Web SDK — but the host will not resolve.
AzakawKycConfig.isUnavailableCombination reports this, and the SDK logs a
warning in debug builds.
The API and auth hosts are derived from the same pairing and passed to the portal, so it talks to the matching backend:
baseUrl = https://{subdomain}.{domain}
apiUrl = https://{subdomain}-api.{domain}/
authUrl = https://{subdomain}-auth.{domain}/api/
The subdomain depends on both the region and the environment. Most
regions use app / sandbox, but Kuwait shares the azakaw.com domain
with UAE and is separated by subdomain instead:
| Region | Environment | subdomain |
|---|---|---|
| UAE, KSA, Qatar | Production | app |
| UAE | Sandbox | sandbox |
| Kuwait | Production | kuwait |
| Kuwait | Sandbox | kuwait-stg |
So Kuwait production resolves to kuwait.azakaw.com,
kuwait-api.azakaw.com and kuwait-auth.azakaw.com/api/. Use
AzakawRegion.subdomainFor(environment) rather than assuming the
app/sandbox convention.
Use resolveAzakawUrls if you need those values yourself:
final urls = resolveAzakawUrls(
region: AzakawRegion.ksa,
environment: AzakawEnvironment.production,
);
// urls.baseUrl -> https://app.azakawksa.com
// urls.apiUrl -> https://app-api.azakawksa.com/
// urls.authUrl -> https://app-auth.azakawksa.com/api/
region and environment are read once when the flow starts; changing them
afterwards has no effect, because swapping the URL would destroy an
in-progress session.
Tenant domains
Tenants can serve the portal from their own domain, usually with their own
theming. The domain is carried on the session token as a baseUrl claim.
The Web SDK learns it only after the portal boots: the portal decodes the
token, sees that its own hostname differs, and posts TenantBaseUrl so the
host reloads the iframe on the right domain. That means the generic host
renders first, and a themed tenant flashes the wrong brand.
The Flutter SDK supports the same redirect, and by default also avoids the
flash: with resolveTenantHost: true it reads the baseUrl claim itself
before the first load and opens the WebView on the tenant domain directly.
AzakawKycConfig(
sessionId: sessionId,
resolveTenantHost: true, // default
);
This costs one anonymous GET {authUrl}AppSessionManager/GetToken/{sessionId}.
That endpoint is a pure read — it does not consume or invalidate the session,
so the portal still exchanges the same session id normally.
Resolution is only an optimisation, never a dependency: if the request fails,
times out, or the token names no domain, the region host loads and the
TenantBaseUrl redirect corrects it as before. Set resolveTenantHost: false
to skip the request and rely on the redirect alone.
It also catches the most common integration mistake. If the backend rejects
the session (401/403/404) — almost always because the region or
environment does not match the one it was created for — the SDK fails with
a clear message instead of loading the portal, which would otherwise show its
login screen and look like an SDK fault.
Permissions
The SDK requests the OS camera permission when the onboarding portal asks for it, then grants it to the WebView. If the user denies it, the portal shows its own "camera unavailable" message and the user can retry from the OS settings.
The microphone is never requested.
Security
The SDK takes a session id, never API credentials. Create the session server-side — see Session Management — and always confirm the outcome server-side before treating a user as verified.