Skip to main content

The EkycClient

EkycClient is the top-level type. Construct it once with an EkycConfig and share it across your app.

import 'package:drukverify_flutter/drukverify_flutter.dart';

final client = EkycClient(
config: EkycConfig(
host: 'https://api.drukverify.com',
apiKey: 'dv_pk_live_…',
tokenProvider: () async => await myBackend.fetchToken(),
),
);

EkycConfig​

FieldTypeDefaultNotes
hostStringhttps://api.drukverify.comBase URL of the gateway. Override for staging (https://staging.api.drukverify.com) or a local stack.
apiKeyString (required)n/aYour public tenant key (dv_pk_test_… or dv_pk_live_…). The environment is encoded in the key, so there are no separate sandbox URLs.
tokenProviderFuture<String> Function() (required)n/aAsync callback returning a dv_tok_… session token minted by your server.
apiVersionString'2026-05-12'The Drukverify-Version the SDK sends. Override only if you know your gateway accepts a different one.
timeoutDuration30sPer-request HTTP timeout (connect + receive). Use at least 90s for chained fraud plus OCR.

Multipart upload helpers​

The endpoints that take multipart/form-data bodies have hand-rolled helpers on EkycClient, so callers don't construct FormData themselves:

// /v1/ocr: extract fields from a Bhutanese identity document
final ocr = await client.ocrScanImages(
image: File('/path/to/front.jpg'),
backImage: File('/path/to/back.jpg'), // required for CID and SRC
);

// /v1/face/verify: 1:1 selfie vs ID portrait
final match = await client.faceVerifyImages(
imageA: File('/path/to/id_portrait.jpg'),
imageB: File('/path/to/selfie.jpg'),
);

// /v1/liveness/check
final passive = await client.livenessCheckImage(File('/path/to/frame.jpg'));
final burst = await client.livenessCheckBurst([f1, f2, f3]);
final issued = await client.livenessCreateChallenge();
final challenge = await client.livenessCheckChallenge(
frames, // neutral first, then the action
challengeToken: issued.challengeToken,
idempotencyKey: attemptId, // optional, see Idempotency
);

Each helper goes through the SDK's auth, version and error interceptors. Errors surface as typed EkycException subclasses, such as EkycValidationException on a 400 and EkycAuthException on a 401.

Sub-API accessors​

For endpoints with JSON bodies, the SDK exposes the generated sub-APIs:

client.sessions // mint, revoke
client.face // register, search, dedupe, list registrations
client.ocr // list past scans, get by id, delete
client.liveness // create challenge, get check by id
client.diagnostics // ping

Each sub-API's methods correspond 1:1 with the operations in the API reference.

Custom UI primitives​

For apps that want their own UI on top of the camera, the SDK ships composable primitives covering permissions, camera, face quality, image preprocessing and the burst face-verify loop. See Custom UI primitives.

Test seam​

For unit tests, construct the client with a pre-configured Dio:

final dio = Dio()..httpClientAdapter = MyFakeAdapter();
final client = EkycClient.withDio(dio);

EkycClient.withDio is marked @visibleForTesting. Production code paths always go through EkycClient(config:).