{"openapi":"3.1.0","info":{"title":"11FaceID API","version":"v1","description":"Enrollment, 1:1 verification, secure QR lifecycle, Session Assurance, configuration and audit. Face images are never persisted — they are processed in memory and discarded. The organization is always derived from the credential, never from the request body."},"servers":[{"url":"https://app.11faces.com"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key from Settings → API keys. Create it with only the scopes you need."}},"x-scopes":{"identities:read":"List and read enrolled identities and their QR status","identities:write":"Enroll, update, delete identities; revoke/reissue QR tokens; send invites","verify":"Run 1:1 verification and 1:N search","sessions:read":"List Session Assurance sessions and read their state","sessions:write":"Start, tick, re-verify and end Session Assurance sessions","datasets:read":"List face datasets and their members","datasets:write":"Create, edit and delete face datasets and their members","settings:read":"Read use cases, face config, limits, policies and project links","settings:write":"Change use cases, face config, policies, project links and calibration","audit:read":"Read the audit trail, verification history and dashboard stats"}},"security":[{"apiKey":[]}],"paths":{"/api/v1/whoami":{"get":{"operationId":"whoami","summary":"Confirm a key is live and discover what it can do — the organization it belongs to, the current plan, and the expanded list of scopes. Has no side effects, so it is the safe first call from a new integration.","tags":["Meta"],"security":[{"apiKey":[]}],"x-scope":null,"responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"tenantId\": \"tnt_event_northwind\",\n  \"tenantName\": \"Northwind Events\",\n  \"plan\": \"starter\",\n  \"authKind\": \"api_key\",\n  \"actor\": \"key:Kiosk – lobby\",\n  \"role\": \"editor\",\n  \"scopes\": [\"identities:read\", \"identities:write\", \"verify\"]\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/enroll":{"post":{"operationId":"enroll","summary":"Enroll an identity for your organization. The captured face is processed in memory, a feature template is extracted and encrypted, and only the encrypted template is stored — the image is discarded. Issues the first secure QR token.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"id\": \"FID-A1B2C3\",\n  \"status\": \"pending\",\n  \"verifyUrl\": \"/verify/<signed-token>\",\n  \"sessionUrl\": \"/session-join/<signed-token>\",   // Session use cases only\n  \"qr\": { \"version\": 1, \"status\": \"active\", \"expiresAt\": \"…\" },\n  \"registration\": { \"id\": \"FID-A1B2C3\", \"faceTemplate\": { \"dim\": 512, \"alg\": \"AES-256-GCM\" } }\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"requestBody":{"content":{"application/json":{"example":"{\n  \"useCase\": \"event\",\n  \"fullName\": \"Amelia Stone\",\n  \"phone\": \"+1 555 0100\",\n  \"email\": \"amelia@example.com\",\n  \"fields\": { \"ticketId\": \"TKT-4821\", \"eventName\": \"Northwind Summit\" },\n  \"faceImage\": \"data:image/jpeg;base64,…\"   // processed then discarded\n}"}}}}},"/api/v1/registrations":{"get":{"operationId":"listRegistrations","summary":"List enrolled identities, optionally narrowed to one use case, status, or verified state. Returns profiles only — never template material.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"count\": 42,\n  \"registrations\": [ { \"id\": \"FID-A1B2C3\", \"fullName\": \"Amelia Stone\", \"status\": \"checked_in\" } ],\n  \"emailStatus\": { \"FID-A1B2C3\": \"email_sent\" }\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/registrations/{id}":{"get":{"operationId":"getRegistration","summary":"Fetch one enrolled identity together with its QR token history and audit trail. Returns template metadata only (dimensionality and algorithm), never the raw template or any image.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"registration\": { \"id\": \"FID-A1B2C3\", \"fullName\": \"Amelia Stone\",\n                    \"faceTemplate\": { \"dim\": 512, \"alg\": \"AES-256-GCM\" } },\n  \"qrTokens\": [ { \"version\": 2, \"status\": \"active\", \"expiresAt\": \"…\" } ],\n  \"logs\": [ { \"type\": \"verify\", \"decision\": \"approved\", \"timestamp\": \"…\" } ]\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"patch":{"operationId":"updateRegistration","summary":"Edit contact details and/or re-enroll the face. Organization and use case are immutable. Re-enrolling supersedes the outstanding QR token, because it points at a template that no longer exists, and emails the new one.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"registration\": { \"id\": \"FID-A1B2C3\", \"fullName\": \"Amelia Stone-Reid\" },\n  \"qr\": { \"version\": 3, \"status\": \"active\" },   // present only if re-enrolled\n  \"reenrolled\": true\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{\n  \"fullName\": \"Amelia Stone-Reid\",\n  \"fields\": { \"ticketId\": \"TKT-5000\" },\n  \"faceImage\": \"data:image/jpeg;base64,…\"   // optional — re-enrolls the face\n}"}}}},"delete":{"operationId":"deleteRegistration","summary":"Destroy the registration, its encrypted template, and its QR tokens. Irreversible; the audit trail is retained.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"id\": \"FID-A1B2C3\", \"deleted\": true }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true}},"/api/v1/registrations/{id}/qr-link":{"post":{"operationId":"registrationQrLink","summary":"Get a shareable verification link for an identity, issuing a fresh token only if none is currently usable.","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"verifyUrl\": \"/verify/<signed-token>\", \"expiresAt\": \"…\", \"issued\": false }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/registrations/{id}/send-email":{"post":{"operationId":"registrationSendEmail","summary":"Re-send the person's email with their QR code, use case and its open period — for the common case where the first one never arrived. For a Session use case the email carries the use case's Session link instead of the verification link (`link` in the response says which was sent).","tags":["Identities & enrollment"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"sent\": true, \"link\": \"verify\" }   // \"session\" for a Session use case"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true}},"/api/v1/verify":{"post":{"operationId":"verify","summary":"Run a 1:1 verification. Supply the secure QR token (preferred, and no credential needed) or a registration id with a key holding the verify scope. The live face is processed in memory, checked for spoofing, and the live template is compared against the stored encrypted template. Expired, revoked and cross-organization attempts are blocked and audit-logged.","tags":["Verification"],"security":[{"apiKey":[]}],"x-scope":"verify","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"spoofCheck\": \"pass\",\n  \"face_match\": \"pass\",\n  \"matchConfidence\": 0.91,\n  \"verificationThreshold\": 0.75,\n  \"decision\": \"approved\",\n  \"reason\": \"Live face matched the enrolled template.\",\n  \"timestamp\": \"…\",\n  \"tenant_id\": \"tnt_event_northwind\",\n  \"registration_id\": \"FID-A1B2C3\"\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"requestBody":{"content":{"application/json":{"example":"{\n  \"token\": \"<signed-qr-token>\",                   // no credential needed with a token\n  \"verificationImage\": \"data:image/jpeg;base64,…\" // processed then discarded\n}\n// or, with an API key holding `verify`:\n{ \"id\": \"FID-A1B2C3\", \"verificationImage\": \"data:image/jpeg;base64,…\" }"}}}}},"/api/v1/qr/resolve":{"get":{"operationId":"qrResolve","summary":"Resolve a secure QR token to its current state (active, expired, revoked, reissued, invalid) and the profile behind it. Powers the hosted verification page; no credential is needed because the token's signature is the proof.","tags":["Secure QR tokens"],"security":[],"x-scope":null,"responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"status\": \"active\",            // active | expired | revoked | reissued | invalid\n  \"usable\": true,\n  \"qr\": { \"version\": 2, \"status\": \"active\", \"expiresAt\": \"…\" },\n  \"registration\": { \"id\": \"FID-A1B2C3\", \"fullName\": \"Amelia Stone\" },\n  \"tenant\": { \"id\": \"tnt_event_northwind\", \"name\": \"Northwind Events\", \"type\": \"event\" }\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/qr/revoke":{"post":{"operationId":"qrRevoke","summary":"Revoke the active secure QR token for a registration. Subsequent verification attempts with that token are blocked and logged.","tags":["Secure QR tokens"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"registrationId\": \"FID-A1B2C3\", \"status\": \"revoked\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"registrationId\": \"FID-A1B2C3\" }"}}}}},"/api/v1/qr/reissue":{"post":{"operationId":"qrReissue","summary":"Issue a fresh secure QR token, superseding any prior active token (its version increments). Returns the new verify URL.","tags":["Secure QR tokens"],"security":[{"apiKey":[]}],"x-scope":"identities:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"ok\": true,\n  \"registrationId\": \"FID-A1B2C3\",\n  \"verifyUrl\": \"/verify/<new-signed-token>\",\n  \"qr\": { \"version\": 2, \"status\": \"active\" }\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"registrationId\": \"FID-A1B2C3\" }"}}}}},"/api/v1/face-datasets":{"get":{"operationId":"listDatasets","summary":"List your face datasets and how many identities each one holds.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"datasets\": [ { \"id\": \"fds_…\", \"name\": \"Staff\", \"memberCount\": 24 } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"post":{"operationId":"createDataset","summary":"Create a face dataset — a named group of enrolled identities.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"dataset\": { \"id\": \"<uuid>\", \"tenantId\": \"tnt_event_northwind\",\n  \"name\": \"Staff\", \"createdAt\": \"…\", \"createdBy\": null, \"memberCount\": 0 } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"name\": \"Staff\" }"}}}}},"/api/v1/face-datasets/{id}":{"get":{"operationId":"getDataset","summary":"Fetch one dataset together with its members.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"dataset\": { \"id\": \"fds_…\", \"name\": \"Staff\" },\n  \"members\": [ { \"registrationId\": \"FID-A1B2C3\", \"fullName\": \"Amelia Stone\" } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"patch":{"operationId":"updateDataset","summary":"Rename a dataset.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"name\": \"Staff — 2026\" }"}}}},"delete":{"operationId":"deleteDataset","summary":"Delete a dataset. The identities in it are untouched; only the grouping goes away.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"id\": \"fds_…\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true}},"/api/v1/face-datasets/{id}/members":{"post":{"operationId":"addDatasetMember","summary":"Add people to a dataset — link identities that are already enrolled (e.g. a subset of a bigger dataset), or enroll a new face.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"// link:   { \"ok\": true, \"added\": 2, \"alreadyMembers\": 0 }\n// enroll: { \"ok\": true, \"registrationId\": \"FID-A1B2C3\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"// Link people who are already enrolled (no new photo, no extra quota):\n{ \"registrationIds\": [\"FID-A1B2C3\", \"FID-D4E5F6\"] }  // or { \"registrationId\": \"FID-A1B2C3\" }\n\n// …or enroll a new face straight into the dataset:\n{ \"fullName\": \"Amelia Stone\", \"phone\": \"+66812345678\", \"email\": \"amelia@example.com\",\n  \"faceImage\": \"data:image/jpeg;base64,…\" }"}}}}},"/api/v1/face-datasets/{id}/members/{registrationId}":{"delete":{"operationId":"removeDatasetMember","summary":"Remove an identity from a dataset without deleting the registration.","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true}},"/api/v1/face-datasets/{id}/use-cases":{"get":{"operationId":"listDatasetUseCases","summary":"listDatasetUseCases","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"datasets:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"useCases\": [ { \"id\": \"<uuid>\", \"key\": \"math_10\", \"label\": \"Math — Grade 10\",\n  \"closedAt\": null, \"linked\": true } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"put":{"operationId":"setDatasetUseCases","summary":"setDatasetUseCases","tags":["Face datasets"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"linked\": 2, \"added\": 1, \"removed\": 0 }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"// The full set of use cases that should verify against this dataset.\n// Other datasets' links on those use cases are untouched. [] unlinks all.\n{ \"useCaseIds\": [\"<uuid>\", \"<uuid>\"] }"}}}}},"/api/v1/session-policies":{"get":{"operationId":"listPolicies","summary":"List Verification Policies and the available presets (Online Auction, Online Examination, Online Training, Remote Attendance). A preset is a recommended starting configuration only.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"policies\": [\n    { \"id\": \"pol_online_auction\", \"name\": \"Online Auction / Bidder Monitoring\", \"custom\": false },\n    { \"id\": \"pol_…\", \"name\": \"Exam — Room 1\", \"custom\": true, \"libraryVisible\": false, \"linkedUseCases\": [ { \"key\": \"exam\", \"label\": \"Exam\" } ] }\n  ],\n  \"presets\": [ { \"key\": \"online_auction\", \"name\": \"Online Auction / Bidder Monitoring\" } ]\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance"},"post":{"operationId":"createPolicy","summary":"Create a Verification Policy (Save as Custom Policy / Duplicate).","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"policy\": { \"id\": \"pol_…\", \"custom\": true } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{\n  \"name\": \"Exam — Final\",\n  \"initialVerification\": { \"qrRequired\": true, \"spoofCheckRequired\": true, \"retryLimit\": 3, \"retryIntervalSecs\": 5, \"faceQualityRequired\": true },\n  \"verification\": { \"intervalSecs\": 45, \"randomized\": true, \"maxConsecutiveMismatches\": 3, \"maxMissedVerifications\": 2 },\n  \"camera\": { \"disconnectedTimeoutSecs\": 10, \"blockedDetection\": true, \"unavailableAction\": \"require_reverify\" },\n  \"response\": { \"onVerificationFailure\": \"warn\", \"onMaxConsecutiveMismatches\": \"terminate\", \"onMaxMissedVerifications\": \"require_reverify\" },\n  \"auditLevel\": \"full_history\"\n}"}}}}},"/api/v1/session-policies/{id}":{"put":{"operationId":"updatePolicy","summary":"Edit an existing Verification Policy.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"policy\": { \"id\": \"pol_…\", \"updatedAt\": \"…\" } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{ \"verification\": { \"intervalSecs\": 60 } }"}}}},"delete":{"operationId":"deletePolicy","summary":"Delete a Verification Policy. Blocked (409) while referenced by a live session.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"id\": \"pol_…\", \"status\": \"deleted\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"x-module":"session-assurance"}},"/api/v1/sessions":{"get":{"operationId":"listSessions","summary":"List assurance sessions for your organization and their current state.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"count\": 1, \"sessions\": [ { \"id\": \"ses_…\", \"policyName\": \"Online Auction / Bidder Monitoring\", \"status\": \"active\" } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance"}},"/api/v1/sessions/start":{"post":{"operationId":"startSession","summary":"Start a Session Assurance session for an enrolled identity under a selected policy. Records an initial 1:1 verification and returns a hosted session URL you can send the person to; pass returnUrl to bring them back to your own app afterwards.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"session\": { \"id\": \"ses_…\", \"status\": \"active\", \"totalChecks\": 1 },\n  \"sessionUrl\": \"https://…/session/<signed-token>\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{ \"registrationId\": \"FID-D4E5F6\", \"policyId\": \"pol_online_auction\", \"returnUrl\": \"https://your.app/done\" }"}}}}},"/api/v1/sessions/check":{"post":{"operationId":"checkSession","summary":"Run one periodic identity verification. Frames are processed in memory only. Optional flags simulate a missed check or a camera problem; the policy decides the response.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"session\": { \"status\": \"warning\", \"failedChecks\": 1, \"consecutiveMismatches\": 1 } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{ \"sessionId\": \"ses_…\", \"kind\": \"scheduled\" }   // or { \"missed\": true } / { \"camera\": \"lost\" }"}}}}},"/api/v1/sessions/reverify":{"post":{"operationId":"reverifySession","summary":"Perform an immediate re-verification. On success the session returns to active; on failure it escalates per the policy.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"session\": { \"status\": \"active\" } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{ \"sessionId\": \"ses_…\", \"verificationImage\": \"data:image/jpeg;base64,…\" }"}}}}},"/api/v1/sessions/end":{"post":{"operationId":"endSession","summary":"End a session and write the closing audit event. A session ended before its policy's time limit is recorded as expired; one that ran its full length as completed.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"session\": { \"status\": \"expired\", \"endReason\": \"ended_early_by_admin\", \"endedAt\": \"…\" } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance","requestBody":{"content":{"application/json":{"example":"{ \"sessionId\": \"ses_…\" }"}}}}},"/api/v1/sessions/tick":{"post":{"operationId":"tickSessions","summary":"Advance every live session by one scheduler step. Use this when you drive the clock yourself — from your own cron, say — instead of relying on the browser session page.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"advanced\": 3, \"sessions\": [ { \"id\": \"ses_…\", \"status\": \"active\" } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance"}},"/api/v1/sessions/{id}/link":{"post":{"operationId":"sessionLink","summary":"Re-issue the hosted session URL for a session that is still live, for when the original link was lost.","tags":["Session Assurance"],"security":[{"apiKey":[]}],"x-scope":"sessions:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"sessionUrl\": \"https://…/session/<signed-token>\" }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-module":"session-assurance"}},"/api/v1/use-cases":{"get":{"operationId":"listUseCases","summary":"List your use cases and the custom fields each one collects at enrollment.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"useCases\": [ { \"key\": \"event\", \"label\": \"Event check-in\", \"fields\": [ { \"key\": \"ticketId\", \"label\": \"Ticket ID\" } ] } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"post":{"operationId":"createUseCase","summary":"Create a use case with its own set of enrollment fields.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"useCase\": { \"key\": \"exam\" }, \"policyId\": null }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"key\": \"exam\", \"label\": \"Exam check-in\", \"fields\": [ { \"key\": \"seatNo\", \"label\": \"Seat number\" } ] }"}}}}},"/api/v1/use-cases/{id}":{"patch":{"operationId":"updateUseCase","summary":"Edit a use case — its label, fields, schedule, capacity, or the return URL its hosted links redirect to.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true, \"useCase\": { \"key\": \"exam\" } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"label\": \"Exam check-in (2026)\", \"returnUrl\": \"https://your.app/done\" }"}}}},"delete":{"operationId":"deleteUseCase","summary":"Delete a use case. Blocked while identities are still enrolled under it.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true}},"/api/v1/settings/face-config":{"get":{"operationId":"getFaceConfig","summary":"Read the organization's detector-confidence floor for enrollment. Null means the engine default applies.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"enrollMinDetScore\": 0.8, \"isCustom\": false,\n  \"platformDefault\": 0.8, \"range\": { \"min\": 0.5, \"max\": 0.9 } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"patch":{"operationId":"updateFaceConfig","summary":"Raise or lower the detector-confidence floor required to accept an enrollment photo. Send null to go back to the engine default.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"enrollMinDetScore\": 0.7, \"isCustom\": true,\n  \"platformDefault\": 0.8, \"range\": { \"min\": 0.5, \"max\": 0.9 } }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"minDetScore\": 0.7 }   // null resets to the platform default"}}}}},"/api/v1/calibration":{"post":{"operationId":"calibration","summary":"Compare two images through the live engine and get the raw similarity back, without enrolling anything. Use it to pick a match threshold against your own photos rather than guessing.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"detect\": { \"accepted\": true, \"reason\": \"OK\", \"numFaces\": 1, \"score\": 0.9, \"bbox\": [278, 188, 811, 927] },\n  \"spoofCheck\": { \"probability\": 0.94, \"isLive\": true },\n  \"enrollMinDetScore\": 0.8,\n  \"wouldEnroll\": true\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"image\": \"data:image/jpeg;base64,…\" }"}}}}},"/api/v1/limits":{"get":{"operationId":"limits","summary":"Current plan limits and usage — enrolled faces, team seats, verifications this month.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"limits\": { \"maxVerificationsPerMonth\": 1000, \"maxEnrolledFaces\": null, \"maxUsers\": 5 },\n  \"usage\": { \"verificationsThisMonth\": 2, \"enrolledFaces\": 9, \"users\": 1 },\n  \"plan\": \"starter\",\n  \"trialEndsAt\": null\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/tenants":{"get":{"operationId":"tenants","summary":"Your organization's profile as the API sees it.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"count\": 1, \"tenants\": [\n  { \"id\": \"tnt_event_northwind\", \"name\": \"Northwind Events\", \"type\": \"event\", \"defaultUseCase\": \"event\" }\n] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/project-links":{"get":{"operationId":"getProjectLinks","summary":"Get the shareable self-enrollment and self-verification links for a use case, plus whether they are currently open, closed, or full.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"enrollPath\": \"/enroll-link/<signed-token>\",\n  \"verifyPath\": \"/verify-link/<signed-token>\",\n  \"status\": { \"open\": true, \"full\": false }\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}},"post":{"operationId":"emailProjectLink","summary":"Email someone the self-enrollment link for a use case.","tags":["Configuration"],"security":[{"apiKey":[]}],"x-scope":"settings:write","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"ok\": true }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}},"x-requires-editor":true,"requestBody":{"content":{"application/json":{"example":"{ \"useCase\": \"event\", \"email\": \"amelia@example.com\" }"}}}}},"/api/v1/logs":{"get":{"operationId":"logs","summary":"The append-only audit trail for your organization, newest first and capped per request.","tags":["Audit & reporting"],"security":[{"apiKey":[]}],"x-scope":"audit:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{ \"count\": 200, \"logs\": [ { \"type\": \"enroll\", \"reason\": \"…\", \"timestamp\": \"…\" } ] }"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/verifications":{"get":{"operationId":"verifications","summary":"Verification history — successful, failed, and blocked attempts, with the reason each one was blocked.","tags":["Audit & reporting"],"security":[{"apiKey":[]}],"x-scope":"audit:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"count\": 42,\n  \"verifications\": [\n    { \"type\": \"verify\", \"decision\": \"approved\", \"matchConfidence\": 0.91, \"timestamp\": \"…\" },\n    { \"type\": \"verify_blocked\", \"block\": \"qr_expired\", \"timestamp\": \"…\" }\n  ]\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}},"/api/v1/dashboard":{"get":{"operationId":"dashboard","summary":"The numbers behind the portal dashboard: enrollment and verification totals, approval rate, session stats, and recent activity.","tags":["Audit & reporting"],"security":[{"apiKey":[]}],"x-scope":"audit:read","responses":{"200":{"description":"Success","content":{"application/json":{"example":"{\n  \"stats\": { \"registrations\": 812, \"verifications\": 4310, \"approvalRate\": 0.97 },\n  \"sessionStats\": { \"active\": 3, \"flagged\": 1 },\n  \"recent\": [ { \"type\": \"verify\", \"decision\": \"approved\", \"timestamp\": \"…\" } ],\n  \"activity\": [ … ], \"activityTotal\": 512\n}"}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key lacks the required scope, or the module is disabled"}}}}}}