Docs contentsYaliyomo ya nyaraka

Licences and renewal

Evaluation mode, applying a licence key, sandbox and production, usage reports, and renewing pay-as-you-go keys.

The SDK works offline. A licence key is checked on the device, with no call to digid, and the SDK never downloads anything. Prices and plans are on the pricing page; this page is about how licences behave in your app.

Evaluation mode

Without a licence key, or with one that fails its check, the SDK runs in evaluation mode. It is never refused:

  • everything works, so you can build and test your whole integration;
  • every result has evaluation: true, and its verdict is never better than review;
  • the ready-made screens show an "Evaluation" tag and a watermark that no config can remove;
  • after 50 completed sessions in one app run, sessions stop with the guidance licence_required. Restart the app to keep testing.

The licence status says why the engine is in evaluation mode (reason), which helps when a key does not apply.

The licence key

A licence key is one line of text starting digidlic1.. It names:

  • your apps: the Android package name and signing certificate, the iOS bundle id, the web origins;
  • the features it includes: card_ocr (card reading), face_match and liveness (the selfie), fingerprints;
  • its validity dates.

Download keys from your product's page in the customer portal (where your keys are, for customers who sign in). Ship the key in your app, or serve it from your backend and pass it to the SDK at start-up.

Applying the key

SDK Call
Flutter await engine.applyLicence(token), or DigidFlow.createEngine(licence: token)
Web await engine.applyLicence(token), or mountFlow(el, { licence: token })
Android digid.applyLicence(token)
iOS try kyc.applyLicence(token)

The call returns the status and never throws for a bad key:

state Meaning
licensed Valid for this app
grace Past its end date but inside the grace period: it still works. Renew it.
evaluation No valid key; reason says why

The app's identity comes from the running app (package and signing certificate on Android, bundle id on iOS, location.origin on the web), never from configuration. A key copied into another app does not apply.

A valid key runs only the features it lists. A flow that needs another feature is refused with a "feature not licensed" error naming it (see Error codes). Evaluation mode never refuses.

Sandbox and production

Each product has a production licence and, once the product is active, can have a free sandbox licence, each with its own key and app list. Until then, build in evaluation mode.

  • Use the sandbox key while you develop and test. Web pages on local origins (localhost, *.test) are accepted only with a sandbox key.
  • Use the production key in the app you release. It becomes active when the product's first invoice is paid; until then the SDK runs in evaluation mode.
  • Features are checked the same way in both.

Expiry and grace

  • A key past its end date keeps working for 14 days, with state: "grace", then the SDK falls back to evaluation mode.
  • Pay-as-you-go keys are short-lived: valid for 7 days, with 3 days of grace. Each phone renews its own key (below), so a phone that cannot reach the internet keeps working for up to 10 days after its last renewal.
  • Monthly and enterprise keys run to the end of the licence term. Download a fresh key from the portal, or through the API, when you renew.

Usage reports

Under a valid licence the SDK counts completed verifications on the device:

  • counts only: a day, a count, your licence and app, and an anonymous counter id for the phone. Nothing about the person;
  • a verification counts when a session ends with a result (pass, review or fail), or a single-photo read finds a NIN. Abandoned attempts and evaluation mode are never counted;
  • the same person verified again on the same phone within 7 days counts once;
  • days follow the Tanzanian calendar (East Africa Time).

The SDK sends nothing by itself. Your app gives it a sender and tells it when it is online:

engine.usageSender = (report) async => (await http.post(
      Uri.parse('https://digid.co.tz/api/v1/usage'),
      headers: {'content-type': 'application/json'},
      body: jsonEncode({'report': report}),
    )).statusCode == 200;
await engine.setUsageStore(myStore);
await engine.online();
  • POST https://digid.co.tz/api/v1/usage with {"report": "digidusage1.…"}. No API key: the licence inside the report authenticates it. Your backend can relay reports instead of the phone posting them.
  • Sending a day again replaces its count; it never lowers it.
  • Give the SDK a usage store (setUsageStore) so counts survive restarts. The stored state holds counts, the counter id and the licence key: no personal data.

Renewing pay-as-you-go keys: no report, no renewal

A pay-as-you-go product starts from one key you download (from the portal or the API), at most once every 30 days per licence. Ship that key in your app. From then on each phone renews its own key with one call:

final renewed = await engine.renewLicence((request) async => (await http.post(
      Uri.parse('https://digid.co.tz/api/v1/licences/renew'),
      headers: {'content-type': 'application/json'},
      body: jsonEncode({'request': request}),
    )).body);
if (renewed != null) await saveLicence(renewed.token); // use it at the next start
const renewed = await engine.renewLicence((request) =>
  fetch("https://digid.co.tz/api/v1/licences/renew", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ request }),
  }).then((r) => r.text()));

The SDK builds the renewal request (digidrenew1.…), which carries this phone's usage reports, sends it through your function, applies the new key and returns it. Keep the new key and apply it at the next start. Android (renewLicence(RenewalSender)) and iOS (try await kyc.renewLicence(_:)) work the same way. Your backend may relay the request server to server; to your app and your backend it is opaque text.

No report, no renewal. The renewal succeeds only when this phone has reported every business day since its previous renewal (or, the first time, since its key was issued, at most 7 days back), days with no checks included. The SDK puts those reports, zero days too, inside the request, so a phone that keeps its usage store renews without anything else to do.

When the renewal is refused, the SDK raises an error with the cloud's code:

Code HTTP What to do
usage_report_missing 409 Some days were never reported (details.missing_days lists them), usually because the usage store was lost. Send those reports, or keep a usage store from now on.
insufficient_credit 402 The product's credit is used up. Top it up in the customer portal.
bootstrap_limit 409 A starting key was already issued for this licence in the last 30 days. Ship that key and let phones renew.

Sites with no internet. Export the request with renewalRequest(), upload it on your product's page in the customer portal (Offline renewal), download the renewed key and apply it with applyRenewal(token). The same rules apply.

Learn more

  • Going live: the licence checklist before release.
  • Cloud API: the usage and renewal endpoints, and keys from your backend.