End-user identity
Jobs and streams require exactly one of Find-A-Code user_id or claims-only external_user_id — never both. Partner integrations use external_user_id only. Hosted SKU 2 does not let the browser pick that id.
How conversations are grouped
History, job ownership, and per-user quotas are scoped to:
source_app (your API client slug) + external_user_id + agent.
If every request uses the same id, every thread lands in one inbox. If you pass a stable per-person id, each signed-in user gets their own conversation list. source_app always comes from the authenticated client, never the request body.
API (SKU 1)
{
"prompt": "What is the ICD-10-CM code for type 2 diabetes?",
"context": {
"external_user_id": "opaque-stable-id-from-your-app"
}
}
Send the same id on every stream/job create, and as ?external_user_id= on GET list/read. Do not send FAC user_id.
Use a value that is stable for that person in your product (internal user id, subject claim, account member id). Do not use a session token, IP address, or a new UUID on every page load. Set it on your backend after the user is authenticated — never let a browser pick the id on a secret-keyed API call.
Hosted page (SKU 2) — sign in at login.askaimee.com
Hosted Aimee is signed-only. There is no anonymous hosted chat and ?user= is not authentication. Your users have their own Aimee accounts on your tenant: they sign in at login.askaimee.com with email, password, and your tenant name, then land on https://{slug}.askaimee.com/ signed in. Anyone who opens your tenant URL without a session is redirected to that sign-in page.
- Your tenant admin invites users from the
/accountpage on your tenant (invite links are shown once and expire in 7 days) - Each user gets their own conversation history (
external_user_idishu:{user-id}, assigned by us — never chosen by the browser) - Users can set a display name on
/account. That is a label in the sidebar, not the identity used for history or quotas. - Disabling a user or a lapsed subscription blocks chat immediately
Optional SSO handoff (integrations)
If your product already authenticates users and you want to skip the Aimee sign-in page, your backend can mint a short-lived session token after your own login. The browser never sees your API key.
POST https://api.askaimee.com/v1/hosted-session
Authorization: Bearer <your-secret-key>
{
"external_user_id": "opaque-stable-id-from-your-app",
"ttl_seconds": 3600
}
The response includes token, expires_at, and tenant_url (already has ?token=). Inject the token into the launcher or iframe. Default TTL is one hour (clamped 5 minutes–12 hours). Login-page sessions use the 12-hour maximum. The hu: prefix is reserved for Aimee-managed accounts and is rejected on this route.
SSO users are not Aimee-managed accounts: they have no /account page (that URL redirects to chat). Team invites, display names, and password changes apply only to hu: users.
<script src="https://api.askaimee.com/widget/widget.js"
data-tenant="new-company"
data-session-token="{{token}}"
async></script>
<iframe src="https://new-company.askaimee.com/?token={{token}}"
title="Aimee"></iframe>
Opening the tenant URL without a valid session redirects to the sign-in page. Copying a URL after the token is stripped, or guessing ?user=user-123, cannot open another person’s inbox. A leaked external_user_id is useless without a valid token.
data-user-id is ignored. Iframe allowed origins only control frame-ancestors (clickjacking). They do not isolate users.
Rotate hosted sessions
Incrementing the tenant’s handoff kid invalidates outstanding session tokens immediately (users sign in again). That is separate from rotating the API key. The hosted page still does not use the API key.
Per-user limits
When a per-user daily cap is configured on your client, it meters external_user_id from the verified session. Each signed-in user gets their own meter. See quotas.