Quickstart
This walks through a complete end-to-end verification: a Go backend mints a session token, a Flutter mobile app consumes it, the user completes a passive liveness check, and the backend reads the result. Expect to spend ~5 minutes.
Prerequisites
- Go 1.21+ installed locally
- Flutter 3.13+ with a connected device or running emulator
- An eKYC tenant. If you don't have one yet, request access. You'll receive
dv_sk_test_...anddv_sk_live_...API keys.
1. Mint a session on your server
The sk_ API key stays on your server; you never ship it to a mobile
app. The server's job is to mint short-lived session tokens
(dv_tok_* JWTs, ~30 minute TTL) that the mobile app uses for one
verification session.
Install the Go SDK:
go get github.com/cloudbhutan/ekyc-sdk-go/v2
Server stub (cmd/auth-server/main.go):
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"os"
"time"
ekyc "github.com/cloudbhutan/ekyc-sdk-go/v2"
)
func main() {
client, err := ekyc.NewClient(ekyc.Config{
BaseURL: "https://api.drukverify.com",
APIKey: os.Getenv("EKYC_SECRET_KEY"),
})
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/session", func(w http.ResponseWriter, r *http.Request) {
ref := r.URL.Query().Get("user")
if ref == "" {
http.Error(w, "user query param required", 400)
return
}
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
s, err := client.Sessions.Create(ctx, ekyc.CreateSessionRequest{
CustomerRef: ref,
TTL: 30 * time.Minute,
})
if err != nil {
http.Error(w, err.Error(), 500)
return
}
json.NewEncoder(w).Encode(map[string]string{"token": s.Token})
})
log.Println("listening on :9090")
log.Fatal(http.ListenAndServe(":9090", nil))
}
Run it:
EKYC_SECRET_KEY=dv_sk_test_… go run ./cmd/auth-server
Quick smoke from a different terminal:
curl 'http://localhost:9090/session?user=demo'
# → {"token":"dv_tok_test_eyJhbGciOi..."}
2. Wire the Flutter app
Add the SDK to pubspec.yaml:
dependencies:
ekyc_sdk: ^2.0.0
In your app's startup code:
import 'package:dio/dio.dart';
import 'package:ekyc_sdk/ekyc_sdk.dart';
final sdk = EkycSdk(EkycConfig(
baseUrl: 'https://api.drukverify.com',
tokenProvider: () async {
final res = await Dio().get<Map<String, dynamic>>(
'http://10.0.2.2:9090/session', // Android emulator → host
queryParameters: {'user': 'demo'},
);
return res.data!['token'] as String;
},
));
tokenProvider is called lazily — the first authenticated request will
trigger a fetch from your backend. The SDK caches the result and
auto-refreshes on 401 token_expired.
3. Run a passive liveness check
In a screen widget:
import 'package:ekyc_sdk/widgets.dart';
EkycLivenessWidget(
sdk: sdk,
mode: LivenessMode.passive,
onResult: (result) {
print('liveness: ${result.isLive} score=${result.score}');
},
onError: (e) {
print('error: $e');
},
);
The widget renders the camera, captures a frame, and POSTs to
/v1/liveness/check. The result you see (is_live, score, lc_id)
is the server's verdict. The on-device active-liveness UI runs
in parallel as a UX layer; toggle it with
enableOnDeviceLiveness: false if you want server-only.
4. Read the result on the server
The mobile app's LivenessCheckResult.lcId is a stable id (format
lc_<32hex>). Your server can re-fetch the result later via
GET /v1/liveness/checks/:id for audit / risk review.
What's next
- Test mode vs live mode — how the platform differentiates by API key
- Authentication — full
sk_/tok_lifecycle - Error handling — error envelope shape and retries