PlatformsLinux (Headless C, beta)

Linux (Headless C SDK)

⚠️

This Linux headless C SDK is in beta. The API and behavior may still change.

This SDK is headless. There is no embedded UI or camera handling. You must capture frames, submit them to the SDK, and build any user guidance yourself.

This SDK targets arm64 Linux and exposes a C API for running Shen.AI measurements without an embedded UI.

The shipped header shenai_sdk_c.h is the source of truth for the full C API surface (functions, structs, and enums).

Download

See the Customer Portal for SDK downloads.

See system requirements for runtime dependencies.

Quickstart (minimal flow)

#include "shenai_sdk_c.h"
 
int main(void) {
  shen_context_t* ctx = NULL;
 
  shen_init_options_t opts = {
    .api_key_or_token = "YOUR_API_KEY_OR_TOKEN",
    .user_id = "user-123",
    .language = "en",
    .offline_mode = 0
  };
 
  if (shen_initialize(&opts, &ctx) != SHEN_STATUS_OK || ctx == NULL) {
    return 1;
  }
 
  shen_set_operating_mode(ctx, SHEN_OPERATING_MEASURE);
 
  for (;;) {
    shen_frame_desc_t desc = {
      .width = 1280,
      .height = 720,
      .stride_bytes = 1280 * 3,
      .format = SHEN_PIXEL_FORMAT_BGR24,
      .timestamp_ns = 0
    };
 
    const uint8_t* frame_data = get_next_frame(&desc);
    if (!frame_data) {
      break;
    }
 
    shen_submit_frame(ctx, &desc, frame_data);
 
    shen_measurement_state_t state = SHEN_MEAS_NOT_STARTED;
    shen_get_measurement_state(ctx, &state);
    if (state == SHEN_MEAS_FINISHED || state == SHEN_MEAS_FAILED) {
      break;
    }
  }
 
  shen_measurement_results_t results;
  if (shen_get_measurement_results(ctx, &results) == SHEN_STATUS_OK) {
    /* Use results. */
  }
 
  shen_deinitialize(ctx);
  shen_destroy_runtime();
  return 0;
}

Replace get_next_frame() with your camera or video capture pipeline.

Status codes

Most functions return a shen_status_t value:

  • SHEN_STATUS_OK
  • SHEN_STATUS_NOT_INITIALIZED
  • SHEN_STATUS_INVALID_ARGUMENT
  • SHEN_STATUS_INVALID_STATE
  • SHEN_STATUS_LICENSE_INVALID
  • SHEN_STATUS_CONNECTION_ERROR
  • SHEN_STATUS_NO_DATA
  • SHEN_STATUS_INTERNAL_ERROR

Frame input

shen_submit_frame() accepts raw BGR frames:

  • Format: SHEN_PIXEL_FORMAT_BGR24 (8-bit, 3 channels, B-G-R order)
  • Layout: row-major, stride_bytes >= width * 3
  • timestamp_ns: optional, set to 0 if unknown
shen_frame_desc_t desc = {
  .width = width,
  .height = height,
  .stride_bytes = stride,
  .format = SHEN_PIXEL_FORMAT_BGR24,
  .timestamp_ns = timestamp_ns
};
 
shen_submit_frame(ctx, &desc, frame_data);

Initialization and configuration

Use shen_init_options_t to pass your API key or token, user id, language, and offline mode preference. Set offline_mode to non-zero to enable offline processing. The SDK can be initialized multiple times; subsequent calls reuse the same engine and return SHEN_STATUS_OK.

Configuration options are set through explicit setters. You can also apply a full SDK config JSON string via shen_apply_sdk_config() and inspect the current configuration with shen_get_sdk_config_string().

shen_set_precision_mode(ctx, SHEN_PRECISION_STRICT);
shen_set_measurement_preset(ctx, SHEN_MEAS_PRESET_ONE_MINUTE_ALL_METRICS);
 
const char* config_json = load_config_json();
shen_apply_sdk_config(config_json);

Replace load_config_json() with your config loader.

Custom measurement config

shen_custom_measurement_config_t cfg = {0};
cfg.has_duration_seconds = 1;
cfg.duration_seconds = 30.0f;
 
shen_metric_t instant_metrics[] = { SHEN_METRIC_HEART_RATE };
cfg.instant_metrics = instant_metrics;
cfg.instant_metrics_count = sizeof(instant_metrics) / sizeof(instant_metrics[0]);
 
shen_set_custom_measurement_config(ctx, &cfg);

If you call shen_get_custom_measurement_config(), release the returned arrays with shen_release_custom_measurement_config().

Preset semantics and metric meanings match the documentation in Configuration. Use the corresponding SHEN_MEAS_PRESET_*, SHEN_METRIC_*, and SHEN_HEALTH_INDEX_* constants.

Operating mode and state

Because there is no UI, you control the measurement flow via the API:

shen_set_operating_mode(ctx, SHEN_OPERATING_POSITIONING);
shen_set_operating_mode(ctx, SHEN_OPERATING_MEASURE);
 
shen_operating_mode_t mode;
shen_get_operating_mode(ctx, &mode);
 
shen_measurement_state_t state;
shen_get_measurement_state(ctx, &state);
 
float progress = 0.0f;
shen_get_progress_percent(ctx, &progress);

Typical flow is to keep the SDK in SHEN_OPERATING_POSITIONING, wait until shen_get_face_state() returns SHEN_FACE_OK, then switch to SHEN_OPERATING_MEASURE.

You can provide your own positioning guidance using:

shen_face_state_t face_state;
shen_get_face_state(ctx, &face_state);
 
shen_normalized_face_bbox_t bbox;
shen_get_normalized_face_bbox(ctx, &bbox);
 
shen_face_pose_t pose;
shen_get_face_pose(ctx, &pose);

Realtime metrics and heartbeats

shen_realtime_metrics_t metrics;
shen_get_realtime_metrics(ctx, 30.0, &metrics);
 
int hr_10s = 0;
shen_get_heart_rate_10s(ctx, &hr_10s);
 
shen_heartbeat_array_t heartbeats = {0};
shen_get_realtime_heartbeats(ctx, 30.0, &heartbeats);
shen_release_heartbeat_array(&heartbeats);

Final results and history

shen_measurement_results_t exposes all final metrics. Use has_* flags to check availability.

Results map to the metrics described in Results, with additional optional fields for blood pressure confidence, weight, and height in the C API.

shen_measurement_results_t results;
if (shen_get_measurement_results(ctx, &results) == SHEN_STATUS_OK) {
  /* Results are available in results.* */
}
 
shen_heartbeat_array_t hb = {0};
shen_get_measurement_results_with_heartbeats(ctx, &results, &hb);
shen_release_heartbeat_array(&hb);
 
shen_measurement_results_history_t history = {0};
if (shen_get_measurement_results_history(ctx, &history) == SHEN_STATUS_OK) {
  shen_release_measurement_results_history(&history);
}

Health risks (optional)

The C API includes health risks computation. Set has_* flags for each provided field:

shen_risks_factors_t factors = {0};
factors.has_age = 1;
factors.age = 42;
factors.has_gender = 1;
factors.gender = SHEN_GENDER_FEMALE;
 
shen_health_risks_t risks;
shen_compute_health_risks(ctx, &factors, &risks);

Raw data, reports, and FHIR

The headless C SDK exposes the same optional outputs as other platforms:

int recording_enabled = 0;
shen_set_recording_enabled(ctx, 1);
shen_get_recording_enabled(ctx, &recording_enabled);
 
float signal_quality = 0.0f;
shen_get_current_signal_quality_metric(ctx, &signal_quality);
 
float bad_signal_seconds = 0.0f;
shen_get_total_bad_signal_seconds(ctx, &bad_signal_seconds);
 
shen_blob_t png = {0};
shen_get_face_texture_png(ctx, &png);
shen_release_blob(&png);
 
shen_blob_t quality_png = {0};
shen_get_signal_quality_map_png(ctx, &quality_png);
shen_release_blob(&quality_png);
 
shen_blob_t meta_png = {0};
shen_get_meta_prediction_image_png(ctx, &meta_png);
shen_release_blob(&meta_png);
 
shen_float_array_t signal = {0};
shen_get_full_ppg_signal(ctx, &signal);
shen_release_float_array(&signal);
 
shen_request_measurement_results_pdf_url(ctx);
const char* url = shen_get_measurement_results_pdf_url();
 
shen_request_measurement_results_pdf_bytes(ctx);
shen_blob_t pdf = {0};
if (shen_get_measurement_results_pdf_bytes(ctx, &pdf) == SHEN_STATUS_OK) {
  shen_release_blob(&pdf);
}
 
const char* fhir = shen_get_result_as_fhir_observation();

Use shen_send_measurement_results_pdf_to_email() to deliver reports by email, and shen_send_result_fhir_observation() to push the FHIR payload to a server.

Memory ownership

Release buffers and arrays returned by the SDK using the matching helpers:

  • shen_release_custom_measurement_config()
  • shen_release_heartbeat_array()
  • shen_release_measurement_results_history()
  • shen_release_health_risks_factors()
  • shen_release_blob()
  • shen_release_float_array()

Use shen_free() for any heap memory explicitly documented as allocated by the SDK. Strings returned by functions such as shen_get_version() are owned by the library and must not be freed.

Metadata and debug helpers

const char* version = shen_get_version();
int initialized = shen_is_initialized();
const char* plan = shen_get_pricing_plan();
 
const char* trace_id = shen_get_trace_id();
const char* measurement_id = shen_get_measurement_id();
;