> ## Documentation Index
> Fetch the complete documentation index at: https://eurusys-6c0957fa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# C

> Integrate the MBKYC SDK into a native application using the plain C API.

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.

<Card title="Download the example" icon="download" href="/examples/mbkyc-c-example.zip" cta="mbkyc-c-example.zip">
  A self-contained CLI (with a vendored `cJSON`). Populate `deps/` (see below), fill in the config block, and `make`.
</Card>

<Accordion title="Populating the example's deps/ folder" icon="box-archive">
  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:

  ```sh theme={null}
  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/`.
</Accordion>

## Install

<Tabs>
  <Tab title="Linux">
    `.deb` (apt) or `.rpm` (yum) — installs headers to `/usr/include/mbkyc/` and libs to `/usr/lib/`. See [Configure Nexus](/distribution/configure-nexus#apt-debian--ubuntu).
  </Tab>

  <Tab title="Windows">
    `.msi` installer, the `MBKYC.Capi` NuGet package, or a VCPkg port.
  </Tab>

  <Tab title="macOS">
    The macOS framework from the raw repository.
  </Tab>
</Tabs>

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`.

```c theme={null}
#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:

```c theme={null}
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);
```

<Info>
  To read a card or capture a fingerprint, install the matching [desktop service](/distribution/services-overview) first (PC/SC for card readers, your fingerprint vendor's service for biometrics). Without them, reader enumeration returns empty. Manual entry needs no services.
</Info>

The requests available per document type:

<Tabs>
  <Tab title="Emirates ID">
    * **Manual entry** — `MBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_MANUAL`. No hardware.
    * **Card read** — `MBKYC_VALIDATION_REQUEST_TYPE_EMIRATES_ID_CARD`. Needs a smart card reader + PC/SC service.
    * **+ Fingerprint** — `MBKYC_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).
  </Tab>

  <Tab title="Passport">
    * **Manual entry** — `MBKYC_VALIDATION_REQUEST_TYPE_PASSPORT_MANUAL`. No hardware, no biometric variant.
  </Tab>
</Tabs>

Each `request_type` selects the matching `payload` field, per the discriminator reference:

| `request_type`                     | Payload field                  | Biometric |
| ---------------------------------- | ------------------------------ | --------- |
| `..._EMIRATES_ID_CARD`             | `emirates_id_card`             | no        |
| `..._EMIRATES_ID_CARD_BIOMETRIC`   | `emirates_id_card_biometric`   | yes       |
| `..._EMIRATES_ID_MANUAL`           | `emirates_id_manual`           | no        |
| `..._EMIRATES_ID_MANUAL_BIOMETRIC` | `emirates_id_manual_biometric` | yes       |
| `..._PASSPORT_MANUAL`              | `passport_manual`              | no        |

## Callback contract

Every async call takes three callbacks + a `user_data` pointer:

```c theme={null}
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

```c theme={null}
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](/reference/error-codes).

<Info>
  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.
</Info>

## Function reference

Shared value types are described in [Data types](/reference/data-types); the full list of `MBKYC_*` types is in `mbkyc_capi.h` and error codes in `mbkyc_errors.h`.

| Function                                                                                       | Purpose                        |
| ---------------------------------------------------------------------------------------------- | ------------------------------ |
| `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:**

```c theme={null}
mbkyc_export_logs(handle, "/tmp/mbkyc-logs.tar.zst", ctx, on_success, on_error);
```
