# Sessions The production shape. Your backend creates a session with your secret key; the browser receives only a single-use session token. ## 1. Server: create the session ```bash curl -X POST https://machine.cognau.com/api/v1/session/create \ -H "Authorization: Bearer $COGNAU_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "platform": "web", "clientReference": "user_4821" }' ``` ```json { "success": true, "data": { "sessionId": "6a7de599a5244ea6a3e65109", "sessionToken": "cgn_st_…", "environment": "live", "livemode": true, "challengeSequence": [{ "type": "headTurn", "index": 0, "params": {} }], "wsEndpoint": "/api/v1/ws/session/6a7de599a5244ea6a3e65109", "expiresAt": 1760000000000 } } ``` ### `clientReference` Your own identifier for whoever is being verified: a user id, an application id, an order number. It is opaque to us, never parsed and never matched across accounts, and it comes back on the webhook. Without it you must store our `sessionId` at create time to know whose result arrived later. ### Other options | Field | Effect | |---|---| | `riskHint` | `low` shortens the sequence to 3 challenges; anything else uses 4 | | `simulate` | sandbox only: `pass` or `fail`, chooses the fake verdict | | `enablePersonId` | opt-in re-recognition; requires you to have collected consent | | `deviceId` | your own device identifier, if you have one | | `trainingConsent` | the user agreed their video may be retained for training | ```tryit { "method": "POST", "path": "/session/create", "title": "creates a sandbox session with a test key", "body": "{\n \"platform\": \"web\",\n \"clientReference\": \"user_4821\",\n \"simulate\": \"pass\"\n}" } ``` ## 2. Browser: run the check Hand the session to the widget. Two shapes, both ending in the same place. **Let the widget fetch it.** Give it your own route and it POSTs there when it is ready, which keeps the session from being created until someone actually reaches the step: ```html ``` Your route just proxies `POST /session/create` with your secret key. Return our response verbatim if you like: the widget accepts the raw session or the `{ success, data }` envelope. **Or hand it over yourself,** if you already created the session: ```js const session = await fetch('/api/start-verification', { method: 'POST' }) .then(r => r.json()); const v = Cognau.open({ session, onVerdict: r => { v.close(); showPending(); } }); ``` Pass the whole session object, not just the token: a session that also collects a document carries a second credential the widget needs. Whichever you use, the token is delivered to the iframe over `postMessage` after it signals readiness, never as a query parameter. A session token in a URL would land in browser history, in the `Referer` of anything the page loads next, and in the access log of whatever served it. **There is no publishable key to add.** Nothing account-level goes to the browser; the session token is the only credential your page holds. See [Authentication](/docs/authentication#there-is-no-publishable-key). More on mounting, sizing and events: [Embedding](/docs/embedding). ## The optional document check A session can also collect an identity document. It is a **separate check**, switched on per account, and it is metered separately from liveness, so a session that runs both is billed for both. A composite session reaches the document step only if liveness passes. Be precise about what it does, because the name invites the wrong assumption. | It does | It does not | |---|---| | Store the submitted image, encrypted | Read anything printed on it | | Check the sides submitted match the declared type | Parse an MRZ or run OCR | | Judge blur, glare, resolution and framing | Check an expiry date | | Produce a recommendation for a reviewer | Compare the portrait against the liveness capture | | | Extract a name, date of birth or address | | | Decide the outcome on its own, unless the account opts in | **There is no text extraction anywhere in this stack.** If you need parsed identity fields, expiry checking, tampering analysis, or AML screening, this is not the tool for that part of the job, and it pairs with one rather than replacing it. The decision is made by a person reviewing the submission, and the automated signal is a recommendation shown to them. An account can opt in to having a sufficiently clear-cut recommendation applied automatically; that is off unless you ask for it. Accepted types are `passport`, `id_card`, `residence_permit` and `drivers_license`. A document image is kept on its own retention schedule, separate from liveness frames: see the [biometric data policy](/biometric-policy). ## 3. Server: trust the webhook The verdict the browser sees is convenient for UX, but it arrives over a channel the end user controls. **Make decisions from the webhook**, which is signed and server-to-server. See [Webhooks](/docs/webhooks). ## Sessions expire A session is short-lived by design, measured in minutes. Create one when the user is about to verify, not when the page is built. If you need something that survives an email, use a [verification link](/docs/verification-links) instead. ## Reading results ```bash curl "https://machine.cognau.com/api/v1/cockpit/sessions?clientReference=user_4821" \ -H "Authorization: Bearer $COGNAU_SECRET_KEY" ``` Filtering by your own reference is the point of setting it: you can answer "did user 4821 ever pass?" without having kept our identifiers.