Docs

Overview

End users of partner applications — tenant-scoped identities with their own registration and space access.

A Separate Identity Population

Consumers are not admins — and one email is not one person.

Consumers are the end users of partner applications built on KeenAgents (and of Keen's own first-party surface). They are a completely separate population from organization accounts: they have their own registration flows, their own sign-in, and their own admin pages. An organization admin account and a consumer account never mix — even when they share an email address.

The load-bearing identity rule is tenant scoping: a consumer's email is unique only per tenant. Each partner site is a tenant, identified by a 19-character consumer-contract key shared with that partner. The same email can therefore hold one account under partner A, another under partner B, and a first-party account — all independent, with independent passwords, profiles and space grants. Every login, password reset, profile read and chat query is scoped to the tenant resolved from the calling partner's credentials, so one tenant can never read or authenticate another tenant's users. Requests use a two-token model — the partner backend's application_token plus the consumer browser's access_token — covered in detail on the Authentication page; the self-service flows (password reset, delete, profile, chat) have their own page too.

Core Concepts

Consumer
An end-user account: email, a password stored irreversibly hashed, first and last name, gender, date of birth (entered as day / month / year), a consent flag, the list of AI spaces the account may use, a confirmed status (the invite or registration was completed) and an external marker recording whether the account was created through a partner or by an admin invite. Each account is bound to at most one tenant.
Tenant (consumer contract)
Each partner site is a tenant, represented by a consumer contract with a 19-character key that the partner holds. The contract carries the per-tenant policy: five toggles, a master allowed-spaces set and default space sets for admin-invited and partner-registered consumers. Partner notifications travel through the webhook entry bound to the partner's API key. Every consumer belongs to at most one contract; deleting a contract releases its consumers for re-assignment rather than deleting them.
Email uniqueness per tenant
KeenAgents refuses a duplicate email within a tenant, never across tenants: the same address may exist once under each partner, plus a first-party account with no tenant at all. Duplicate registration under the same tenant is refused with "already registered".
First-party consumer
A consumer registered on Keen's own surface with no partner contract. First-party logins follow the org-global settings for registration gating and OTP instead of any contract policy, and their spaces are not clamped by a contract.
Consumer spaces
The space list controls which AI spaces the consumer may use. At login the effective set is the account's own list intersected with the tenant's allowed spaces, and on every conversation run KeenAgents re-checks the tenant's current allowed spaces — so a space revoked from a tenant stops working immediately, not at the next login.

Registration: System vs Outside

Two ways a consumer comes to exist — the external marker records which.

Outside registration is partner-driven and follows a request → email → confirm handshake — nothing is created until the user proves ownership of the address:

  1. The partner backend submits the registration request with its application token, an X-Callback-Url (the target of the email link) and the user's details. KeenAgents refuses the request when the tenant's outsideRegistration toggle is off — each tenant can be gated independently.
  2. The platform hashes the password irreversibly, encrypts the registration details so that only this tenant can read them, and emails the user a verification link. The plaintext password never rides the link.
  3. The user clicks; the partner site decrypts the link payload with its tenant secret and submits the confirmation step with the single-use confirmation secret the payload contains.
  4. KeenAgents checks the org-wide registration switch (the master kill-switch), then validates the payload, the secret and the expiry — links are valid for 10 minutes from the initial request.
  5. The account is created already confirmed and marked external, with spaces seeded from the contract's default outside-registration set. A duplicate under the same tenant is refused with "already registered".

System registration is an admin invite from the org console: the account is created unconfirmed and first-party (no tenant) and an activation mail with a one-time link goes out. The user completes name and password on the confirmation page, which marks the account confirmed. Admin-created consumers stay first-party until a contract is bound.

OTP: when policy requires it, login returns a "Verify" challenge instead of signing the user in — a 6-digit pin (100000–999999) is emailed, valid for 120 s and tied to the exact login attempt and site that triggered it; a pin can be tried exactly once. The requirement is contract-first (otpOutsideRegistration / otpInsideRegistration, chosen by how the account was registered), falling back to the org-global settings for first-party logins.

Contract OTP still needs the global flag
OTP confirmation additionally requires the org-global otpOutsideRegistration setting to be on — even when the challenge was triggered by contract-level policy. A tenant with contract OTP enabled but the global flag off sends pins that can never be confirmed.

Rules & Limits

  • Email uniqueness is per tenant: the same email at most once under each partner, plus a first-party account. Duplicates within a tenant are refused with "already registered".
  • Emails are compared exactly as typed — A@x.com and a@x.com are different accounts. Addresses must be a valid email shape.
  • Outside-registration fields: a valid email plus firstName / lastName / password as required non-empty values, a boolean consent, gender exactly male | female | other, and dob { day, month, year } — all three parts required.
  • Registration and confirmation links are valid for 10 minutes from the request; an expired link is refused and the flow starts over.
  • OTP: a 6-digit pin in [100000, 999999], valid for 120 s, one attempt — a wrong entry spends the challenge and the user signs in again to get a fresh pin.
  • At login the consumer's effective spaces are the account's list intersected with the tenant's allowed list. An empty intersection still signs in — with zero spaces.
  • Registration gating is two-scope: the tenant's outsideRegistration toggle gates the start of a registration (one tenant can be disabled alone); the org-wide switch gates its completion (master kill-switch). Both must be on for a registration to finish.
  • On every conversation run KeenAgents re-checks that the target space is still granted to both the consumer and the tenant, and that the requested agent exists and is active in that space — otherwise the run is refused with an "agent not found in space" error.

Admin Console & Partner Webhooks

What operators change, and how partner sites hear about it.

Consumers are managed from the org admin console: viewing requires the Consumer permission; all changes additionally require its Write grant. The consumer list is a paged table with filters — narrow it by the fields you see in the table before paging through — and each row opens the consumer's detail page. From there admins can invite by email, send a password reset, edit the space list, bind / re-bind / unbind the tenant contract (binding clamps spaces to the contract's allowed set; unbinding wipes them; a re-bind that collides with an existing same-email account under the destination tenant is refused), and delete. When a contract is deleted, its consumers are released — they remain, unassigned, and the consumer detail page is where an admin re-assigns each one to a contract. Per-tenant policy lives on the consumer contract page — five toggles plus three space lists, where the defaults must be subsets of the master set and shrinking the master set automatically prunes every bound consumer. Org-wide switches (the global registration kill-switch and the global OTP flags) live in System Consumer Settings.

outsideRegistrationotpInsideRegistrationotpOutsideRegistrationblockOutsideRegistrationLoginsblockSystemRegistrationLogins

Partner sites hear about changes through notify-then-fetch webhooks: a lightweight POST says what changed — never the data itself — and the partner re-fetches through the authenticated API. Consumer-targeted pings carry the consumer's id:

targeted consumer ping

POST <your webhook entry's notification URL>
{ "synch-data": ["r_consumer_spaces_update"], "consumer": { "id": "<consumer id>" } }
  • r_consumer_spaces_update — an admin changed that consumer's spaces; sent to the current tenant's notification URL (the webhook entry bound to its API key).
  • r_consumer_contract_changed — an admin re-bound or unbound the tenant; sent to the previous tenant's URL, since that site holds the now-stale session.
  • A contract-level change (policy toggles, space sets) is announced with a refresh notice — sent by the admin via the bound API key's Wake action, per contract rather than per consumer.
  • The expected partner reaction is a force-logout of the named consumer: entitlements are fixed into the session when the user signs in, so a re-login is what picks up the new spaces or tenant. Delivery is best-effort — a webhook never delays or blocks the admin's action, and a tenant whose API key has no webhook entry bound is silently skipped.

Good to Know

  • Two first-party accounts with the same email can coexist (a duplicate admin invite creates a real second account). Not exploitable across tenants — login is tenant-scoped — and an admin recovers by deleting one of the two.
  • A consumer who "can log in but nothing works" usually has an empty space intersection: a valid session with zero spaces, so every run fails space authorization. Check the tenant's allowed spaces against the account's spaces.
  • Flipping the org-wide registration switch off rejects in-flight registrations (requested but not yet confirmed) at the confirmation step — intentional, not a bug.
  • Rotating a contract's key from the contract page is a per-tenant kill-switch: every signed-in consumer of that tenant is refused immediately and must log in again. Other tenants are untouched.
Where the rest lives
Tokens, sign-in and OTP confirmation are on the Authentication page; registration confirmation details, password flows, delete, profile and the chat surface are on the Self-Service page.

Previous

Connecting a Site

Next

Authentication

Keen Agents 2026

Documentation

Release 15