Skip to main content
The C SDK lets native applications read Emirates ID and capture fingerprints through a plain C API. Every validate operation is asynchronous and callback-based.

Download the example

A self-contained CLI (with a vendored cJSON). Populate deps/ (see below), fill in the config block, and make.
The example builds against the header + shared library in deps/include/ and deps/lib/. The C SDK is published as individual per-platform files in the Nexus raw repository under mbkyc/mbkyc-capi/<version>/<platform>/ — download the two for your platform (no archive to extract). macOS arm64 example:
mkdir -p deps/include deps/lib
BASE="https://repo.client.ae/repository/mbkyc-raw/mbkyc/mbkyc-capi/0.7.0/macos-arm64"
curl -u "$NEXUS_USER:$NEXUS_PASSWORD" -L -o deps/include/mbkyc_capi.h     "$BASE/mbkyc_capi.h"
curl -u "$NEXUS_USER:$NEXUS_PASSWORD" -L -o deps/lib/libmbkyc_capi.dylib  "$BASE/libmbkyc_capi.dylib"
Folders by platform: macos-arm64 / macos-x64 (libmbkyc_capi.dylib), linux (libmbkyc_capi.so), windows (mbkyc_capi.dll + .lib). On Linux you can instead install the .deb/.rpm below and copy from /usr/include/mbkyc/ and /usr/lib/.

Install

.deb (apt) or .rpm (yum) — installs headers to /usr/include/mbkyc/ and libs to /usr/lib/. See Configure Nexus.
You get include/mbkyc_capi.h (+ mbkyc_errors.h) and lib/libmbkyc_capi.{so,dylib,dll}.

Create a handle

The config carries the base URL, the non-secret api_key_id, and a token-signing callback. The SDK invokes sign_cb with the JWT signing input (header.payload bytes); you HMAC-SHA256 it via the holder of the API secret and hand the raw signature back through response_cb.
#include "mbkyc_capi.h"

// Invoked by the SDK whenever it needs a JWT signed.
static void on_sign(void* user_data,
                    const uint8_t* signing_input, uintptr_t signing_input_len,
                    MBKYC_SignResponseCallback response_cb, void* response_user_data) {
    uint8_t signature[32];
    size_t  signature_len = 0;
    // ... compute HMAC-SHA256(signing_input) via your backend / secret ...

    MBKYC_SignResult result = {0};
    result.kind          = MBKYC_SIGN_RESULT_KIND_SUCCESS;
    result.signature     = signature;
    result.signature_len = signature_len;
    response_cb(response_user_data, result);
}

MBKYC_Config config = {
    .base_url          = "https://api.client.ae",
    .api_key_id        = "key-id",
    .sign_cb           = on_sign,        // secret never enters the SDK
    .sign_user_data    = NULL,
    .log_dir           = "/var/log/myapp",
    .max_log_file_size = 10 * 1024 * 1024,
    .max_log_files     = 5,
    .http_timeout_ms   = 30000,
    .header_names      = NULL,
    .header_values     = NULL,
    .header_count      = 0,
};

MBKYC_Handle* handle = NULL;
MBKYC_Error* err = mbkyc_create(&config, &handle);
if (err) { /* print, then */ mbkyc_error_free(err); return 1; }

// Later:
mbkyc_destroy(handle);
sign_cb and sign_user_data must remain valid until mbkyc_destroy. On failure, set result.kind = MBKYC_SIGN_RESULT_KIND_SIGN_ERROR before calling response_cb.

Validate — tagged union

mbkyc_validate takes one MBKYC_ValidationRequest. The request_type discriminator selects which payload field is valid:
MBKYC_ValidationRequest req = {0};
req.request_type = MBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_MANUAL;
req.payload.emirates_id_manual.id_number           = "784-XXXX-XXXXXXX-X";
req.payload.emirates_id_manual.document_number     = "...";
req.payload.emirates_id_manual.nationality         = "ARE";
req.payload.emirates_id_manual.client_reference_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"; // UUID

mbkyc_validate(handle, &req, /* cancel_token */ NULL, /* user_data */ ctx,
               on_success, on_error, on_cancelled);
To read a card or capture a fingerprint, install the matching desktop service first (PC/SC for card readers, your fingerprint vendor’s service for biometrics). Without them, reader enumeration returns empty. Manual entry needs no services.
The requests available per document type:
  • Manual entryMBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_MANUAL. No hardware.
  • Card readMBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_CARD. Needs a smart card reader + PC/SC service.
  • + FingerprintMBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_MANUAL_BIOMETRIC and MBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_CARD_BIOMETRIC. Needs a fingerprint sensor + its service (in addition to the card reader for the card variant).
Each request_type selects the matching payload field, per the discriminator reference:
request_typePayload fieldBiometric
..._EMIRATES_ID_CARDemirates_id_cardno
..._EMIRATES_ID_CARD_BIOMETRICemirates_id_card_biometricyes
..._EMIRATES_ID_MANUALemirates_id_manualno
..._EMIRATES_ID_MANUAL_BIOMETRICemirates_id_manual_biometricyes
..._PASSPORT_MANUALpassport_manualno

Callback contract

Every async call takes three callbacks + a user_data pointer:
typedef void (*MBKYC_VerificationResultCallback)(void* user_data, const MBKYC_VerificationResult* result);
typedef void (*MBKYC_ErrorCallback)(void* user_data, MBKYC_Error* error);
typedef void (*MBKYC_CancelledCallback)(void* user_data);
  • Exactly one of success / error / cancelled fires per invocation.
  • The success result is owned by the library until you call mbkyc_verification_result_free.
  • The error must be freed via mbkyc_error_free; strings via mbkyc_string_free.
  • Callbacks run on an internal worker thread — marshal to your event loop if needed.

Cancellation & errors

MBKYC_CancellationTokenHandle token = mbkyc_cancel_token_create();
mbkyc_cancel_token_cancel(token);   // request cancellation
mbkyc_cancel_token_free(token);     // always free

unsigned short code = mbkyc_error_code(error);
char*          msg  = mbkyc_error_message(error);   // free via mbkyc_string_free
The full code list is in mbkyc_errors.h; see the error reference.
A reference CLI lives at integrations/c/src/main.c in the SDK repo — readers, register, check-registration, validate (with optional --fp-reader), export-logs. It’s the fastest way to see a working signer and biometric callback.

Function reference

Shared value types are described in Data types; the full list of MBKYC_* types is in mbkyc_capi.h and error codes in mbkyc_errors.h.
FunctionPurpose
mbkyc_create(const MBKYC_Config*, MBKYC_Handle** out)MBKYC_Error*Create a handle.
mbkyc_destroy(MBKYC_Handle*)Destroy a handle.
mbkyc_list_smartcard_readers(handle, user_data, on_readers, on_error)Enumerate smart card readers.
mbkyc_list_fingerprint_readers(handle, user_data, on_readers, on_error)Enumerate fingerprint sensors.
mbkyc_register_device(handle, name, user_data, on_success, on_error)Register the device.
mbkyc_check_registration(handle, user_data, on_status, on_error)Query registration status.
mbkyc_validate(handle, request, cancel_token, user_data, on_success, on_error, on_cancelled)Run a validation.
mbkyc_export_logs(handle, path, user_data, on_success, on_error)Bundle logs to a tar.zst.
mbkyc_cancel_token_create() / _cancel(token) / _free(token)Cancellation.
mbkyc_error_code(err) / mbkyc_error_message(err)Read an error.
mbkyc_error_free(err) / mbkyc_string_free(s) / mbkyc_verification_result_free(r)Free owned memory.
Export logs:
mbkyc_export_logs(handle, "/tmp/mbkyc-logs.tar.zst", ctx, on_success, on_error);