End users of partner applications — tenant-scoped identities with their own registration and space access.
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.
Consumers come in two kinds. A consumer is a person — email, password, a profile, optionally a one-time passcode at sign-in. An MCP consumer is a headless identity an AI agent creates for itself through the Keen MCP Server — ID and secret instead of email and password, never a passcode, and a token that only the MCP server can issue. Everything on this page about tenants, contracts and spaces applies to both; the MCP Consumers page covers the rest. An AI agent signed in with an MCP account may view the consumers listed here but can never invite, reset, move, re-grant or delete one — those actions are human-only.
YYYY-MM-DD string and stored 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 set on accounts that signed up through a partner site (admin-invited accounts carry no marker; the console shows Partner sign-up or nothing). Each account is bound to at most one tenant.key that the partner holds. The contract carries the per-tenant policy: five toggles, a master allowed-spaces set and two default space sets. The partner-registration default is granted automatically when a user signs up on the partner site; an admin-invited consumer starts with no spaces and is granted them from its detail page (the in-app default set is published to your site with the policy but is not applied automatically). 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.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:
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.10 minutes from the initial request.System registration is an admin invite from the org console (Ai → Consumers → Create): the admin enters the email and picks the tenant it belongs to — or none, for a first-party consumer — the account is created unconfirmed, 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. An invited consumer starts with no spaces; grant them from its detail page. It can be moved to another tenant later.
OTP: when the tenant's policy requires it, login returns a "Verify" challenge instead of signing the user in — a 6-digit pin (100000–999999) is emailed, valid for 2 minutes and tied to the exact login attempt and site that triggered it. A correct pin works exactly once; a wrong pin is answered "Expired" and does not spend the challenge, so the user may retry with the right pin until it expires. Which OTP toggle applies is chosen by how the account was registered — One-time code — consumers who signed up on a partner site for partner sign-ups, One-time code — consumers created in-app for invited accounts. A consumer with no contract is never challenged.
A@x.com and a@x.com are different accounts. Addresses must be a valid email shape.'true' / 'false'), gender exactly male | female | other, and dob as a YYYY-MM-DD string.10 minutes from the request; an expired link is refused and the flow starts over.[100000, 999999], valid for 2 minutes; a correct pin is accepted once, a wrong pin answers "Expired" and leaves the challenge open for another try.403 Action forbidden. while it is off.What operators change, and how partner sites hear about it.
Consumers are managed from the org admin console under Ai → Consumers: viewing requires the consumer scope (Consumers on the permissions board); all changes additionally require its write grant. The consumer list is a paged table with filters — narrow it by name, email, contract (including No contract (orphans & first-party)), confirmed, sign-up origin, ID and creation date 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 (the Spaces board offers only the tenant's allowed spaces and is locked until the consumer has a tenant), 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. There are no organization-wide consumer switches: every registration, passcode and login rule belongs to the tenant's consumer contract. An AI agent signed in through the Keen MCP server with an MCP account may view consumers but can never invite, reset, move, re-grant or delete one — those actions are human-only and answer 403 for an MCP session.
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.r_consumer_policy refresh notice ({ "synch-data": ["r_consumer_policy"] }), per contract rather than per consumer; deleting the contract sends r_consumer_policy_delete. The API key's Wake action re-sends the full set of notices on demand.Keen Agents 2026
Documentation
Release 15