Who can call the API and who belongs to the organization: sessions and current identity, user CRUD, service accounts, and API keys.
Common responses
These responses apply across endpoints in this section unless an endpoint documents an additional response.
Status
Meaning
Body
200
Request succeeded.
Endpoint response object.
201
Resource created.
Created resource object.
400
Invalid request.
Error envelope.
401
Missing or invalid bearer token.
Error envelope.
404
Resource not found or not visible to the current organization.
Error envelope.
Sessions
Mint session
Exchange the calling organization's API key plus a user's email and password for a short-lived bearer JWT that identifies that user. The token expires in 8 hours; client UIs refresh it silently before expiry via POST /v1/auth/sessions/renew (no password needed). Programmatic clients should authenticate with the API key directly rather than minting per-call sessions. A suspended or expired organization mints no session either — same generic `401 invalid_credentials` as a wrong password, so this endpoint never becomes an oracle for the organization's billing/suspension state.
POST/v1/auth/sessions
Request body
Name
Type
Required
Description
email
string
Required
The user's organization email. Case-insensitive on lookup.
password
string
Required
The user's plaintext password (bcrypt-verified server-side).
Missing or invalid credential, wrong password, or a suspended/expired organization (`code: invalid_credentials`).
`{ error, code, request_id }`
403
Console credentials only (`can_access_console` keys): the authenticated user is a member with no console role, or a role granting zero sections (`code: no_console_role`). The `error` message is user-facing.
Exchange a genuine (still-valid or recently-expired) session JWT for a fresh one WITHOUT the user's password. Requires the organization's API key in the Authorization header PLUS the current token in the body — so a stolen browser token alone cannot renew. Used by client UIs to keep users signed in across the 8-hour token lifetime. A token left idle past the 7-day renew window must sign in again; the new token also reflects the user's current role and is rejected if the account has since been suspended — same for the organization: a suspended or expired organization renews nothing.
POST/v1/auth/sessions/renew
Request body
Name
Type
Required
Description
token
string
Required
The current session JWT to renew. Its signature must be genuine; it may be expired but not older than the 7-day renew window.
Missing API key, invalid/forged token, token past the renew window (`code: renew_window_expired`), or a suspended/expired organization (`code: invalid_credentials`).
`{ error, code, request_id }`
403
Console credentials only (`can_access_console` keys): the authenticated user is a member with no console role, or a role granting zero sections (`code: no_console_role`). The `error` message is user-facing.
Return the principal behind the credential on this request. Credential-shaped: every field describes the token (organization, role, principal kind, capability flags), not the user. For user-record fields like email, name, or the per-user is_developer flag, call GET /v1/users/me, which is JWT-only and returns the user row.
Return the authenticated user's full profile, joined with the user's organization. Requires a session JWT — API-key credentials with no user identity are rejected with 401. Returns id, names, email, role, the per-user is_developer flag, the organization id, name, and is_system flag, and the user's console role (`console_role`, `console_sections` — both null when the user has no console role assigned). Use this endpoint after minting a session to hydrate user-facing UIs (sidebar, account menu, role-gated panels).
Self-service profile update: `firstName`, `lastName`, and `displayName` (at least one required, all trimmed and length-capped). Email and role are directory-managed and rejected here. JWT-only, like the other /me endpoints. Returns the updated user record in the same shape as GET /v1/users/me.
Missing or invalid credential (or API-key credential without a user).
`{ error, code, request_id }`
Change current user password
Change the authenticated user's own password. Requires a session JWT — API-key credentials with no user identity are rejected with 401. The caller must supply their current password; the new password must be at least 12 characters and different from the current one. Session tokens are stateless and not derived from the password, so existing sessions (including other devices) remain valid until they expire.
POST/v1/users/me/password
Request body
Name
Type
Required
Description
current_password
string
Required
The user's existing password.
new_password
string
Required
The new password. Minimum 12 characters; must differ from the current password.
Invalid body, wrong current password, or unchanged password.
`{ error, code, request_id }`
401
Missing or non-user credential.
`{ error, code, request_id }`
Users
Look up users
Minimal org-scoped user directory for share pickers (project members, agent/workflow assignees, and similar UI). Any authenticated org credential can call this — member, admin, or a console-facing API key — since every member is a valid lookup target. Returns only `id`, `display_name`, and `email` per row; role, department, and every other field are withheld so the picker never leaks org structure to callers who shouldn't see it. `search` does a case-insensitive substring match against display name and email. Deleted users are excluded. Results are ordered by display name.
GET/v1/users/lookup
Query parameters
Name
Type
Required
Description
search
string
Optional
Case-insensitive substring match against display name or email.
List all users in the calling organization. Admin-gated. Results are wrapped in `{ data, has_more, next_cursor }` to match the cursor-pagination envelope used elsewhere in /v1.
Create a new user in the calling organization. Admin-gated. Returns the user record and a one-time temporary password that must be changed on first login. The password is shown only in this response and is never persisted in plaintext.
POST/v1/users
Request body
Name
Type
Required
Description
first_name
string
Required
Given name. 1–255 characters.
last_name
string
Required
Family name. 1–255 characters.
display_name
string
Optional
Display name shown in the UI. Defaults to `first_name + last_name` when omitted.
email
string
Required
Email address used for login. Must be unique across the platform.
role
string
Optional
Either `"admin"` or `"member"`. Defaults to `"member"`.
Return a single user by id, scoped to the caller's organization. Admin-gated. Returns 404 for any id that doesn't belong to the caller's org — cross-org probes can't distinguish "doesn't exist" from "exists in another tenant".
Update a user's name, display name, role, or developer-access flag. All fields optional; strict schema (unknown keys → 400). Admin-gated, and self-modify is forbidden (`self_action_forbidden`) — another admin must perform the action. Cannot demote the last active admin in the org.
PATCH/v1/users/:userId
Path parameters
Name
Type
Required
Description
userId
string
Required
UUID of the user to update.
Request body
Name
Type
Required
Description
first_name
string
Optional
Given name. 1–255 characters.
last_name
string
Optional
Family name. 1–255 characters.
display_name
string
Optional
Display name shown in the UI.
role
string
Optional
Either `"admin"` or `"member"`.
is_developer
boolean
Optional
Grant (`true`) or revoke (`false`) developer access for the target user.
Suspend a user — their credentials are invalidated and they can no longer authenticate. Admin-gated; self-action forbidden. Returns 409 if the target is the last active admin. Returns the updated user record.
POST/v1/users/:userId/suspend
Path parameters
Name
Type
Required
Description
userId
string
Required
UUID of the user to suspend.
Example requestbash
curl https://api.cortex.cognit-dx.com/v1/users/0ce6409a-3bfa-4e2f-883a-5a696b451d8b/suspend \
-X POST \
-H "Authorization: Bearer $CORTEX_TOKEN"
Response codes
Status
Meaning
Body
401
Missing or invalid credential.
`{ error, code, request_id }`
404
User not found in the caller's organization.
`{ error, code, request_id }`
403
Forbidden — caller must be an organization admin, or caller attempted to suspend themselves.
`{ error, code, request_id }`
409
Conflict — cannot suspend the last active admin in the organization.
List all service accounts in the calling organization. Requires the caller to have `is_developer` access. Results are wrapped in `{ data, has_more }` to match the cursor-pagination envelope used elsewhere in /v1.
Create a service account in the calling organization. Requires `is_developer` access. The `role` field accepts `member` (default) or `admin`; only an admin caller may set `admin`. Privileged flags (`can_access_console`, `can_mint_cross_org`) are hardcoded `false` on the public API regardless of the request body — only internal seed paths can enable them. Returns 409 if a service account with the same name already exists.
POST/v1/service-accounts
Request body
Name
Type
Required
Description
name
string
Required
Unique display name within the organization. Trimmed; 1–120 characters.
description
string
Optional
Optional free-text description. Maximum 1000 characters.
role
string
Optional
Role granted to API keys issued under this service account. `member` (default) or `admin`. Only an admin caller may set `admin`.
Update a service account's name, description, role, or suspension state. All fields optional. A `member` caller cannot elevate a service account to `admin` role (returns 403 forbidden_role). Renaming to a name already taken returns 409. Unknown request fields return 400 (strict schema).
PATCH/v1/service-accounts/:id
Path parameters
Name
Type
Required
Description
id
string
Required
The id value from the endpoint path.
Request body
Name
Type
Required
Description
name
string
Optional
New display name. Trimmed; 1–120 characters. Must be unique in the organization.
description
string
Optional
Updated description. Pass `null` to clear. Maximum 1000 characters.
role
string
Optional
`member` or `admin`. Only an admin caller may set `admin`.
is_suspended
boolean
Optional
Set to `true` to suspend the service account (new API keys cannot be issued; existing keys stop working immediately).
Permanently delete a service account. Returns 409 `has_live_keys` if any non-revoked API keys still belong to it — revoke all keys first. Returns 204 on success.
List all API keys (active and revoked) that belong to this service account. The plaintext key is never returned after initial issuance — only the `prefix` (e.g. `ctxk_live_`) and metadata are included. Results are wrapped in `{ data, has_more }`.
Issue a new API key under this service account. The plaintext `key` is returned exactly once in this response — it cannot be recovered later. Store it immediately in your secrets manager. Returns 409 if the service account is suspended. The optional `expires_at` field is an ISO 8601 datetime; omit for a non-expiring key.
POST/v1/service-accounts/:id/api-keys
Path parameters
Name
Type
Required
Description
id
string
Required
The id value from the endpoint path.
Request body
Name
Type
Required
Description
name
string
Required
Human-readable label for this key. Trimmed; 1–120 characters.
expires_at
string
Optional
Optional ISO 8601 expiry datetime. Omit to create a non-expiring key.
Revoke an API key — sets `revoked_at` and immediately prevents further use (subsequent requests with this key return 401). Returns 404 if the key does not exist or belongs to a different service account. Returns 204 on success.