# Hosted or headless

Run the capture on our hosted screen with a single-use session token, or run the on-device pipeline yourself and post only derived signals. Never video, never frames, never audio.

## Hosted

Your server mints a single-use session token with [hosted-session-create](/sessions/create), hands it to the browser, and our screen exchanges it with [hosted-session-consume](/sessions/consume) when it boots.

> There is no redirect URL and no mode parameter in this contract. The session — not the URL — carries merchant, action, reference and amount, which is why a browser cannot tamper with an amount it never carries.

Branding is not sent at creation: the screen reads it from [merchant-theme-get](/theme). Token lifetime is `ttl_seconds`, 60–900, default 300.

## Headless

You run the on-device pipeline yourself — camera, rPPG, FaceMesh, voice-pulse correlation — and post only derived signals: a 128-float descriptor with a quality score, the vitals, the capture hash and the device signature.

Never video, never frames, never audio. Payload cap 1 MB, and the vector is shredded in-browser after use.

> This is a privacy invariant, not a size optimisation: an integrator holding the vector becomes a controller of a biometric identifier under BIPA, CUBI and WA MHMDA. Not holding it is the point.

## Desktop-to-phone handoff

When the desktop has no camera, register a handoff with `POST /functions/v1/handoff-register-public`. Browser-safe key. The action is limited to `login` or `genesis` — money actions go through the authenticated path. The token lives five minutes, progress is read with `handoff-events`, and the phone resolves it with `resolve-handoff-token` or `resolve-handoff-code`.

## What is the same either way

- Liveness is of the moment: every operation needs a fresh capture.
- `assurance_level` is derived at the act and frozen on the receipt — [assurance](/assurance).
- A capture is valid as mandate proof for five minutes — [mandates/issue](/mandates/issue).
