Documentation

Everything you need to go from an empty page to a live behavioral verdict. The Behavioral Security product (Lava Sense) is generally documented here; Language Intelligence and Share Without Sharing are in early access — partnerships@cleanlava.com for those.

Overview

Lava Sense has two halves:

The API also serves an interactive OpenAPI explorer at /docs on the API host, with no key required — every request and response schema on this page can be exercised there.

Base URL & keys. Your API base URL and X-API-Key are issued when you're onboarded as a design partner. The live demo runs against our hosted deployment if you want to see the engine work first.

Quickstart

First verdict in under five minutes. Include the SDK and point it at your key:

<script src="https://cleanlava.com/demo/lava-sense.js"></script>
// 1. Create a sensor and attach it to the surfaces you care about
const sense = LavaSense.create({
  apiBase: 'https://YOUR-API-BASE',
  apiKey:  'YOUR-API-KEY',
  appId:   'my-banking-app',
});
sense.attachKeyboard(document.querySelector('#login-form'));
sense.attachPointer(document);

// 2. Start a session when the user arrives
const session = await sense.startSession();

// 3. Before anything high-value: submit features, get the verdict
await sense.submitFeatures(session.session_id);
const verdict = await sense.getVerdict(session.session_id);

if (verdict.verdict === 'STEP_UP') {
  // ask for an OTP — this session doesn't feel like the account owner
}

The first few sessions per device return mode: "enrolling" while the baseline is learned (verdict is ALLOW during enrollment). After that, every session is scored live.

SDK reference — LavaSense.create(options)

Creates a sensor instance. All raw capture buffers live inside this instance and never leave the page.

OptionTypeDescription
apiBasestringBase URL of the Clean Lava API.
apiKeystringYour API key; sent as the X-API-Key header.
appIdstringAn identifier for your application; baselines are scoped to it.
Device identity. The SDK generates a random UUID, stores it only in the user's own localStorage, and sends a SHA-256 hash of it. There is no fingerprinting and nothing tied to the person's identity.

Capturing behavior

MethodWhat it measures
sense.attachKeyboard(el)Typing rhythm on el: key dwell times, flight times between keys, correction rate. Key values are never read (only Backspace/Delete are counted as corrections).
sense.attachPointer(el)Mouse and touch style on el (usually document): movement velocity and curvature signatures, click dwell.

Sessions & verdicts

MethodReturnsDescription
sense.startSession(){ session_id, ... }Opens a scoring session for this device and app.
sense.submitFeatures(id)ackReduces the captured behavior to timing statistics (session summaries + opaque per-key means) and submits them. Raw buffers are cleared.
sense.getVerdict(id)verdict objectScores the session and returns the risk verdict.

REST API — authentication & limits

Every endpoint except /v1/health requires your key:

X-API-Key: your-api-key-here

Endpoints

GET /v1/health

Liveness check. No API key required.

POST /v1/sessions/start

Opens a session. Send the hashed device_id, your app_id, and optional device context. Returns a session_id.

POST /v1/sessions/{session_id}/events

Optional lightweight heartbeat of event counts during a session (used by the simulated fallback). Carries no behavioral content.

POST /v1/sessions/{session_id}/features

Submits the on-device feature summary (session timing statistics plus up to 64 per-key timing means under opaque labels). This is the only behavioral payload the API accepts — there is no endpoint that accepts raw events.

GET /v1/sessions/{session_id}/verdict

Scores the session and returns the verdict object. Repeated calls on the same session are idempotent — a session is never enrolled twice.

DELETE /v1/devices/{device_id}/baseline

Erases the enrolled behavioral baseline for a device — the right-to-erasure call. The next sessions re-enroll from scratch.

The verdict object

{
  "session_id": "3f6a…",
  "mode": "live",                  // "enrolling" | "live" | "simulated"
  "risk_score": 0.08,              // 0.0 no risk → 1.0 high risk (DP noise applied)
  "verdict": "ALLOW",              // "ALLOW" | "STEP_UP" | "BLOCK"
  "signals": {
    "typing_rhythm_match": 0.94,
    "pointer_signature_match": 0.91,
    "device_context_match": 0.99,
    "sim_status": "unknown"        // real SIM signal requires the mobile SDK
  },
  "enrollment": {
    "status": "enrolled",
    "sessions_recorded": 5,
    "sessions_required": 3
  },
  "processing_time_ms": 12,
  "privacy": {
    "raw_data_stored": false,
    "processing_location": "on-device",
    "differential_privacy_applied": true,
    "epsilon": 1.0
  }
}

Modes

Errors

StatusMeaning
401Missing or invalid X-API-Key.
404Unknown session_id or device_id.
429Rate limit exceeded — back off and retry.
5xxOur fault. Fail open or closed per your risk policy; report persistent errors to support@cleanlava.com.

Error bodies are JSON: { "error": "Not Found", "message": "…" }.

Privacy model

What we process, what we store, and what we can never see:

DataWhere it livesRetention
Raw keystroke & pointer eventsBrowser memory onlyDiscarded at feature reduction; never transmitted
Key values (what was typed)Never read by the SDK
Feature summaries (timing statistics only)Clean Lava APIFolded into the device baseline, then discarded
Device baseline (statistical profile)Clean Lava APIUntil erased via DELETE /v1/devices/{id}/baseline
Scores returned to youYour systemsAlways carry differential-privacy noise

This architecture is designed against NDPA 2023 (with GAID 2025 guidance) and GDPR: data minimization by construction, explicit consent surfaces in the SDK integration, and right to erasure as a first-class API call. Compliance questions: support@cleanlava.com.