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
| Field | Type | Default | Notes |
|---|---|---|---|
host | String | https://api.drukverify.com | Base URL of the gateway. Override for staging (https://staging.api.drukverify.com) or a local stack. |
apiKey | String (required) | n/a | Your public tenant key (dv_pk_test_… or dv_pk_live_…). The environment is encoded in the key, so there are no separate sandbox URLs. |
tokenProvider | Future<String> Function() (required) | n/a | Async callback returning a dv_tok_… session token minted by your server. |
apiVersion | String | '2026-05-12' | The Drukverify-Version the SDK sends. Override only if you know your gateway accepts a different one. |
timeout | Duration | 30s | Per-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:).