# Task: Run a liveness check

I want my application to do what Lacuna's "Run a liveness check" demo does: Check that a live person is in front of the camera, with FaceTec 3D liveness on Rest PKI Core.

- Docs: https://docs.lacunasoftware.com/pt-br/articles/rest-pki/core/integration/bio-sessions/liveness
- Live demo: https://try.lacunasoftware.com/en/lacuna-bio/run-a-liveness-check
- This demo for AI agents: https://try.lacunasoftware.com/en/lacuna-bio/run-a-liveness-check.md

## Samples

- Lacuna's samples for this product: https://github.com/LacunaSoftware/RestBioSamples

## Call sequence

Recorded on 2026-10-12 against the real products with Lacuna's public test certificates and data. Keys, tokens, sessions, ids, file contents and personal data are masked.

### 1. Rest PKI Core starts a liveness session with the page's origin as the trusted origin, PreferMobile and FaceTec's 3D liveness pinned, and the browser gets the session URL alone.

On the server: `IRestBioService.StartLivenessSessionAsync`

`POST https://core.pki.rest/api/bio/sessions/liveness` → 200

Request:

```json
{
  "CaptureIdentificationDocument": false,
  "FaceCaptureProvider": 1,
  "TrustedOrigin": "https://try.lacunasoftware.com/",
  "PlatformPreference": 2
}
```

Response:

```json
{
  "sessionType": "Liveness",
  "sessionId": "***",
  "sessionUrl": "***"
}
```

### 2. Lacuna's capture widget opens the session URL over the page and gives back a ticket to complete the session with; the capture needs a person, so it and the completion are not recorded.

In the browser: `widget.performBioSession(sessionUrl)`

## Patterns to copy

- Server, browser, server: your server starts the liveness session and hands the browser only the session URL; Lacuna's capture widget (`performBioSession`) hands back only a ticket; your server completes the session and reads the outcome, so the result never comes from the browser. Treat the session URL and the ticket as credentials: never log or show them.
- On the start request, set `TrustedOrigin` to your page's scheme and host and `PlatformPreference` to `PreferMobile`, and pin `FaceCaptureProvider = FaceTecLiveness3d` rather than leave it to the subscription's default.
- Read the outcome from the completion's `FaceLivenessStatus.Success`: there is no score. Don't fetch the session's result data unless you need it: on a pass it holds the captured face.
- The session URL must be opened within 5 minutes and a capture can last 30, so put no timeout on the widget call; complete promptly, or Rest PKI Core answers `ApiSessionExpired`. When the widget returns both a ticket and a failure code, the failure code wins.

## What to do

Implement this in my project with its existing stack, language, framework and conventions, following the call sequence and the patterns above, and adapting the samples rather than copying them whole. Ask me before adding any dependency or package. Keep API keys and private keys out of the browser and out of the repository.
