Skip to main content
KaireonAI implements the SCIM 2.0 protocol (RFC 7644) for automated user provisioning from enterprise identity providers like Okta, Azure AD, and OneLogin. SCIM endpoints require bearer-token authentication configured in your IdP — the bearer token is a Kaireon krn_ API key scoped to "scim".
Base URL. The working SCIM base path is /scim/v2/* (e.g. https://playground.kaireonai.com/scim/v2/Users). The /api/v1/scim/* alias exists in the codebase but Bearer-authenticated calls to it are blocked at middleware. Always use /scim/v2/ when configuring your IdP.

Authentication

Every SCIM request runs through Kaireon’s SCIM auth gate, which accepts two modes:
  1. Bearer token (production IdP integration). Send Authorization: Bearer krn_<your_api_key>. The token is verified against your tenant’s API keys and the bound tenantId is used for scoping. The API key must carry the "scim" scope — a key with an empty scopes array (a key minted before scopes existed) is also accepted for backwards compatibility, but a non-empty scopes array that does not include "scim" returns a SCIM-formatted 403 { detail: "API key lacks the 'scim' scope" }. Invalid or expired tokens return a SCIM-formatted 401.
  2. Session fallback (admin UI testing only). When no Authorization: Bearer header is present, the route falls back to the standard requireRole("admin") + requireTenant chain. This path is for debugging from a logged-in admin browser session and is not used by IdPs.

Creating a SCIM-scoped API key

Pass the returned key value as Authorization: Bearer <key> when configuring your IdP.

GET /scim/v2/Users

List users in SCIM ListResponse format.

Query Parameters

startIndex is clamped to a minimum of 1 and count to the range [1, 200].

Response

userName is the user’s stored email (falling back to the user id when no email is set). name is emitted as { "formatted": "<stored full name>" }, and is omitted entirely when the user has no stored name. active is always true in this representation — the User resource does not carry a per-user disabled flag in this version. The default page size is count=50 (max 200) when no count query parameter is supplied.

POST /scim/v2/Users

Create a user from a SCIM resource. userName is required. New users are provisioned with role viewer.

Request Body

The email is resolved in this order: the emails entry marked primary: true, then emails[0].value, then userName. The stored name is composed from name.givenName + name.familyName (space-joined, dropping any blank parts); when both are absent the name is stored as null.

Response (201)

Returns the created SCIM User resource (the same shape as the list Resources[] entries — id, userName, name.formatted, emails, active: true, meta).

Error — Invalid body (400)

When userName is missing or the body fails validation, the route returns the Zod validation message:

Error — User Exists (409)

The user-uniqueness check is by email. The error detail embeds the conflicting email.

GET /scim/v2/Users/

Get a single user by ID. Tenant-scoped — returns 404 { detail: "User not found" } with a SCIM error envelope when the id does not belong to the bearer token’s tenant.

PUT /scim/v2/Users/

Replace a user resource. The accepted body fields are userName, name.formatted, and emails — the route updates the user’s email (from emails[0].value, falling back to userName, then the existing email) and name (from name.formatted, falling back to the existing name).
This version’s PUT does not accept or act on an active field — the PutBody schema has no active property, so any active value in the request is ignored. There is no enable/disable-via-PUT behavior. The returned resource always reports active: true.
Returns the updated SCIM User resource on success, or 404 { detail: "User not found" } when the id is not in the caller’s tenant, or 400 with the Zod validation message for a malformed body.

DELETE /scim/v2/Users/

Deletes the user record (prisma.user.delete). Tenant-scoped — the user must belong to the bearer token’s tenant.

Response

204 No Content on success. 404 { detail: "User not found" } with a SCIM error envelope when the id is not in the caller’s tenant.