Docs

Self-Service

What a consumer can do for themselves — profile, password, deletion and their chat history.

What Self-Service Covers

Partner-driven flows a consumer performs on their own account.

Self-service is the family of flows a partner application runs on behalf of a logged-in consumer: reading and updating the profile, changing or resetting the password, deleting the account, and working with the chat history (list, search, read, rename, delete). Every call goes to the KeenAgents public HTTPS API and carries the two-token pair — the partner backend's Authorization: Bearer <application_token> plus the consumer's X-Access-Token — and KeenAgents refuses the request unless both belong to the same tenant. The one exception is forgot-password: the user is logged out, so it is a single-token flow and the emailed link proves ownership.

Reversible edits (profile update, chat rename) are authorized by the live login alone. Destructive or out-of-band actions — password reset, logged-in password change, account delete — use a claim → email → redeem handshake backed by a single-use confirmation grant, so a forged or replayed confirmation link can never change an account on its own.

two-token authclaim → email → redeemsingle-use grantscompletion callbacks

Core Concepts

Confirmation grant (single-use)
When a destructive action is claimed, KeenAgents records a single-use, time-boxed authorization for that specific action on the consumer's account. The grant is checked and consumed when the emailed link is redeemed; a redeem without a fresh matching grant is refused — the link by itself never authorizes anything.
Claim → redeem handshake
The claim leg changes nothing: it records the grant and emails a confirmation link. Only the redeem leg — presenting the link's payload via X-Hash plus its embedded secret via X-Callback-Secret — performs the change, and removing the grant happens in the same step, so each link works exactly once.
One grant per action
Account deletion, the logged-out reset and the logged-in password change each have their own grant, and at most one is live per action at a time. The grants never cross-redeem — a reset link cannot complete a change-password claim, or vice versa — so a link is bound to exactly the action the user asked for.
X-Callback-Url (dual meaning)
One header, two roles. On claim legs it is required: the email-link target, validated as http(s). On redeem and update legs it is optional: a server-to-server completion ping — after the action genuinely succeeds, one POST { action, consumer, apikeyID, contractKey } is sent to it, once, without retries. It never blocks or affects the action itself.
Encrypted vs signed links
Password links carry an encrypted payload only your tenant's shared secret can open — anyone who merely sees the email learns nothing. The delete link instead carries a readable, signed payload your application verifies with the tenant certificate's public PEM, because it contains no secrets. In every flow the new password is irreversibly hashed before the email is ever sent; the plaintext never rides the link.

Rules & Limits

Exact values an integrator or operator will hit.

  • Confirmation links are valid for 10 minutes from claim time, with a small allowance for clock skew. An expired link is refused; claim the action again to get a fresh one.
  • Replace-per-action: claiming again replaces the previous grant for that action in one step — at most one live grant per action; grants for other actions are untouched.
  • Every link embeds a 32-character single-use random secret; the redeem must present it via X-Callback-Secret and it must match the link's embedded value exactly.
  • Profile update is partial only: at least one of firstName, lastName, gender, dobDay, dobMonth, dobYear is required, else 400. Empty or whitespace values count as not supplied — a blank field never blanks the stored value. Email cannot be changed on this route, and the target is always the access token's own account.
  • Profile read returns exactly firstName, lastName, gender, dobDay, dobMonth, dobYear, email — never the password, space grants, or confirmation grants.
  • The completion callback fires only on genuine success with one of the actions external-registration | consumer-delete | password-reset | auth-password-reset | consumer-update. It is sent once and its result is ignored.
  • Delete redeem is idempotent: an account already gone or a concurrent double-click is a success no-op, and no completion callback fires. Only the genuine first delete does.

Forgot-Password, End to End

The claim → email → redeem pattern, using the logged-out reset as the exemplar.

  1. The partner POSTs /v1/consumer/reset-password-claim (application_token only — no live login exists) with { email, password } (the new password) and the required X-Callback-Url email-link target.
  2. KeenAgents irreversibly hashes the new password, records a single-use reset grant on the account (replacing any previous reset grant), and sends the confirmation email. Nothing changes yet.
  3. The user clicks the link; the partner opens the encrypted payload with its tenant secret, extracts the single-use secret, and POSTs /v1/consumer/reset-password-redeem?client_id=… with X-Hash + X-Callback-Secret (plus an optional completion X-Callback-Url).
  4. KeenAgents validates the payload, secret and expiry, finds the confirmed account within your tenant, matches and consumes the reset grant, and applies the new password in the same step that removes the grant. A replayed link finds no grant and is refused.
  5. On success the optional completion callback fires (action: password-reset).

The logged-in change-password flow (auth-reset-password-claim / -redeem) is identical except it also requires X-Access-Token on both legs and uses its own grant — reset and change-password links never cross-redeem. Account delete follows the same shape with both tokens on the claim and a readable, signed link the partner verifies with the tenant certificate's public PEM; the account and its grant are removed together at redeem.

A refused confirmation is deliberately vague
When a redeem is refused, the response is a generic error on purpose — it never says whether the link was expired, already used, or never valid, so a forged or replayed link learns nothing. When a delete or reset "silently failed", claim the action again and use the fresh link: only the newest link for an action can succeed.

The Chat Surface

All chat routes carry both tokens and resolve the consumer through the same two-token check.

RouteWhat it does
GET /v1/consumer/chat-listThe consumer's active chats — archived chats are excluded.
GET /v1/consumer/chat/search?q=&limit=Case-insensitive title substring search. limit caps at 150; an empty q is a 400.
GET /v1/consumer/chat/:id/historyCursor-paginated messages: default limit 50, cursor ?before=<createdAt>:<id>; a malformed cursor falls back to the first page.
POST /v1/consumer/chat/:id/titleRenames the chat; title is capped at 200 characters.
POST /v1/consumer/chat/:id/deleteDeletes the chat. By default a real erasure — the conversation and all its messages are removed. A deployment can be configured to archive instead (kept, but hidden). Either way it vanishes from list, search and history.

Archived chats and other users' chats both answer Chat not found — a deliberate choice that leaks no existence information. Every chat belongs to exactly one tenant, and KeenAgents resolves that tenant from the verified credentials on the request — a client can never choose a tenant for itself.

Good to Know

  • An expired confirmation link is simply inert — claiming the action again issues a fresh link that replaces it, and only the newest link for a given action can succeed.
  • The completion callback is best-effort: the action's success is decided independently and an unreachable partner URL goes unnoticed. Never treat a missing callback as "the action failed".
  • The same X-Callback-Url header means two different things by leg — required email-link target on claim, optional completion ping on redeem/update (a non-http(s) value is a silent no-op). Easy to misread in integrations.
  • Chat "delete" erases the conversation by default — its messages and history are removed, not just hidden. Archiving (keeping it hidden instead of deleting it) is an optional mode a deployment can enable.
  • The new password is irreversibly hashed the moment the claim request arrives; only that original request ever sees the plaintext, and the email link never contains it.
  • Admin counterparts live in the org console: an admin can invite a consumer, send a password reset mail, or delete the account outright — those are role-gated admin actions, not self-service, and are covered on the consumer administration pages.
Registration gating is two-scope
Disabling a single partner site's registration halts that site's claim leg; the organization-wide switch halts every redeem leg across all sites. An in-flight registration — claimed but not yet redeemed — is rejected when the switch flips off between legs. That is intentional.

Previous

Live Chat

Next

Chat SDK

Keen Agents 2026

Documentation

Release 15