Security model
How access is enforced in Practicl. This page describes mechanisms, not commitments — for the latter see our security page. Each claim below is one we can demonstrate on request.
Five endpoints of fifty-nine accept no credential
They are the two health checks (/health, /ready), sign-up, the sign-in method lookup the login page calls before anyone has a session, and the contact form on our own marketing site.
Every other endpoint resolves a credential before it does anything else — including the widget’s configuration call, which reads an API key. None of the five open endpoints reads a document, an answer, a session or an account.
An API key cannot administer anything
Nine endpoints accept an API key. Five are the ones your code calls — ask a question, read a document’s metadata, check ingestion status, get a signed PDF URL, list a product’s documents. Four more are what an embedded widget calls on your behalf.
The remaining fifty require a signed-in session. Creating or revoking keys, uploading documents, inviting colleagues, changing personas, editing settings and everything billing are in that group. A key that leaks cannot create another key, cannot widen its own scope, and cannot see who else is in your organisation.
This is structural rather than conventional: requesting a role on an endpoint makes it reject API keys outright, because a key carries no user and therefore no role to check.
A key’s scope is checked on every request
A share key names the documents or the product it opens. That list is consulted on each request, not just when the key is issued, so moving a document out of a product stops the product’s links opening it immediately.
A key with an empty scope cannot be active. That is a database constraint rather than application logic — the row itself cannot exist in that state, so no code path, migration or manual edit can produce a live key that opens everything.
Revoking a key takes effect on the next request
Every request carrying an API key looks that key up and checks whether it is still active. Nothing is cached, so a key revoked in the dashboard stops working on the next call that uses it — there is no window in which a revoked key is still honoured.
If the store holding the keys cannot be reached, the request is rejected. An unverifiable credential is not honoured.
A key’s organisation is fixed when it is created
Every request resolves its organisation from the credential. Nothing a caller sends can point a request at a different one: there is no organisation parameter, header or body field on any endpoint an API key can reach.
X-Org-Id header. The API never read it, and we removed the attribute rather than leave something in a customer-editable snippet that looked as though it mattered.Widget hand-off tokens are signed with a key that signs nothing else
When someone moves from an embedded widget into the full application, they carry a short-lived token scoped to that one conversation. It is signed with its own secret, valid for thirty minutes, and names the single session it transfers.
That secret signs nothing else, so the token cannot be presented as a sign-in, and rotating it does not touch anyone’s session. If the secret is not configured, no token is minted — there is no second key the code will reach for instead.
The key audit log cannot be edited
Creation, rotation, revocation, reactivation, scope changes and failed authentications are recorded against the key and the person who acted. Records outlive the key they describe, so deleting a key does not delete the evidence that it existed.
Nothing can modify or remove a record. No signed-in role has permission to, at any level, and the application has no code path that updates or deletes one.
Questions this page does not answer
Data residency, retention periods, sub-processors, breach notification, certifications and our roadmap for each are handled in a security questionnaire rather than here, because the useful answer to most of them depends on your deployment. Ask us and we will complete yours.