DocsOpen Moon AI
Browse the docs

SCIM 2.0

The SCIM 2.0 service of a managed organization: directory token, Users and Groups resources, filters, PATCH operations, limits and SCIM-format errors.

On this page

An organization’s SCIM 2.0 service follows RFC 7643 and RFC 7644. Your directory (Microsoft Entra ID, Okta, Google Workspace…) calls it to create, suspend and remove members, and to keep groups up to date. The step-by-step setup is in SCIM directory.

URL and authenticationLink to the URL and authentication section

ItemValue
Base URLhttps://chat.realmoon.ai/api/v1/orgs/scim/v2
AuthenticationAuthorization: Bearer moai_scim_…
Responsesapplication/scim+json; the request’s content type is not checked

The token identifies the organization: the URL never contains its ID. A missing, wrong or revoked token, or one from a personal workspace, gets 401 with WWW-Authenticate: Bearer and the message Jeton invalide. (invalid token). Every route requires the token, including /ServiceProviderConfig, /ResourceTypes and /Schemas.

The directory tokenLink to the The directory token section

An organization has a single active token. The organization’s owner or an admin creates it in the admin console › “Sign-in” › “Directory synchronization (SCIM)”. It is shown only once; creating a new one revokes the previous one immediately.

The token routes are under https://chat.realmoon.ai/api/v1/orgs/{org_id}:

Method and pathWhoPurpose
GET /scim-tokenKey with security:readToken status, never its value.
POST /scim-tokenOwner or admin, with their sessionCreate a token and revoke the previous one.
DELETE /scim-tokenOwner or admin, with their sessionRevoke the active token (404 if there is none).

An admin key gets 403 owner_only on POST and DELETE.

JSON
{
  "can_configure": false,
  "active": true,
  "prefix": "moai_scim_X7k2Qp",
  "created_at": 1762339200,
  "last_used_at": 1762339800,
  "created_by_name": "Camille Martin",
  "base_url": "https://chat.realmoon.ai/api/v1/orgs/scim/v2"
}

last_used_at is updated at most once a minute. The creation response also includes token (its value) and revoked_previous. Every write from the directory is recorded in the organization’s log with the author scim:<start of the token>.

What the service advertisesLink to the What the service advertises section

GET /ServiceProviderConfig:

FeatureSupported
patchyes
filteryes, up to 200 results
bulkno
changePasswordno
sortno
etagno
Authenticationbearer token (oauthbearertoken)

GET /ResourceTypes and GET /Schemas describe the User and Group resources.

UsersLink to the Users section

A User is a member of the organization, active or suspended.

Method and pathPurpose
GET /UsersList, with startIndex (starting at 1), count (100 by default, up to 200) and filter; sorted by join date.
GET /Users/{id}One member.
POST /UsersAdd a member; returns 201.
PUT /Users/{id}Apply the attributes sent.
PATCH /Users/{id}Update attributes.
DELETE /Users/{id}Remove the member from the organization; returns 204 with no body.

FiltersLink to the Filters section

A single attribute eq "value" condition, on userName, externalId, id, emails, emails.value or emails[type eq "work"].value. Only the eq operator is supported; the value is up to 512 characters and the filter up to 1,024. userName and addresses are compared case-insensitively. Example: GET /Users?filter=userName eq "camille.martin@ecole.fr".

A User resourceLink to the A User resource section

JSON
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "<account id>",
  "externalId": "<id in your directory>",
  "userName": "camille.martin@ecole.fr",
  "name": { "formatted": "Camille Martin", "givenName": "Camille", "familyName": "Martin" },
  "displayName": "Camille Martin",
  "emails": [{ "value": "camille.martin@ecole.fr", "type": "work", "primary": true }],
  "active": true,
  "groups": [{ "value": "<group id>", "display": "Site de Lyon", "$ref": "https://chat.realmoon.ai/api/v1/orgs/scim/v2/Groups/<group id>" }],
  "meta": { "resourceType": "User", "created": "2026-11-05T09:00:00+00:00", "lastModified": "2026-11-05T09:00:00+00:00", "location": "https://chat.realmoon.ai/api/v1/orgs/scim/v2/Users/<account id>" }
}

groups only lists the groups created by the directory. givenName and familyName come from the display name, split at the first space.

Create a memberLink to the Create a member section

  • The address is read from userName, otherwise from the primary address, otherwise from the first entry in emails.
  • It must belong to a domain verified by the organization, otherwise 409 (scimType invalidValue), whether or not the account exists.
  • An unknown account is created; an existing account is attached. The name comes from name.formatted, otherwise from givenName and familyName, otherwise from displayName.
  • A missing active means true; active: false creates the member as suspended.
  • 409 also when the person already has a place in the organization (uniqueness), when every seat is taken, or for the account of a platform administrator. Same response on a workspace paid by card: each added seat would be billed, so invite the person from the admin console instead.

Update and removeLink to the Update and remove section

  • PUT only applies the attributes present: a missing attribute changes nothing.
  • active: false suspends the member and closes every session of their account. active: true lifts a suspension made by the directory; a suspension decided in the admin console returns 403. On a workspace paid by card, reactivation is done from the admin console (409).
  • DELETE removes the member and closes their sessions. Their account remains, unless it was created by this directory, has had no activity and belongs to no other team workspace: it is then deleted.
  • The owner, the organization’s admins and platform administrators are never suspended or removed by the directory (403).
  • The address does not change: a different address returns 400 (scimType mutability), the same one is accepted. The name only changes for an account created by the organization or whose address is in a verified domain; otherwise it is ignored without an error.
  • Unknown attributes are ignored.

PATCHLink to the PATCH section

add, replace and remove operations, 1 to 100 per request, in Operations. Supported paths: active, displayName, name, name.formatted, name.givenName, name.familyName, externalId, userName, emails, emails.value, emails[type eq "work"].value. An operation without a path accepts an object whose keys are these paths.

remove clears name.givenName and name.familyName, returns 400 (mutability) on active, and has no effect on other paths. active accepts a boolean or the string "true" or "false".

cURL
curl -X PATCH https://chat.realmoon.ai/api/v1/orgs/scim/v2/Users/$USER_ID \
  -H "Authorization: Bearer $MOONAI_SCIM_TOKEN" \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    "Operations": [{ "op": "replace", "path": "active", "value": false }]
  }'
Python
import os
import requests

r = requests.patch(
    f"https://chat.realmoon.ai/api/v1/orgs/scim/v2/Users/{os.environ['USER_ID']}",
    headers={
        "Authorization": f"Bearer {os.environ['MOONAI_SCIM_TOKEN']}",
        "Content-Type": "application/scim+json",
    },
    json={
        "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
        "Operations": [{"op": "replace", "path": "active", "value": False}],
    },
    timeout=30,
)
r.raise_for_status()
print(r.json()["active"])
JavaScript
const r = await fetch(`https://chat.realmoon.ai/api/v1/orgs/scim/v2/Users/${process.env.USER_ID}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.MOONAI_SCIM_TOKEN}`,
    'Content-Type': 'application/scim+json',
  },
  body: JSON.stringify({
    schemas: ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
    Operations: [{ op: 'replace', path: 'active', value: false }],
  }),
});
if (!r.ok) throw new Error(await r.text());
console.log((await r.json()).active);

GroupsLink to the Groups section

A Group is an organization group created by the directory. These groups are read-only in the admin console.

Method and pathPurpose
GET /GroupsList, with filter: displayName eq "…", id eq "…", or id eq "…" and members[value eq "…"]; excludedAttributes=members makes the response lighter.
GET /Groups/{id}One group, with all its members.
POST /GroupsCreate a group (displayName required, members); returns 201.
PUT /Groups/{id}Replace the name and the members. Without members, the group is emptied.
PATCH /Groups/{id}Paths displayName, members and members[value eq "<id>"] (to remove a member).
DELETE /Groups/{id}Delete the group; its members stay in the organization. Returns 204.
  • remove on members without a value empties the group. Any other path returns 400 (invalidPath), except externalId, which is ignored.
  • An ID in members that is not a member of the organization is ignored.
  • Up to 5,000 members per members list in a request or an operation (400, tooMany).
  • Up to 1,000 groups per organization, including groups created in the admin console (400, tooMany).
  • Two groups cannot have the same name, case-insensitive, including a group from the admin console (409, uniqueness).
  • The directory never fills a group that grants the admin role (409, mutability), nor a group whose roles go beyond what the person who created the token can give (403).

Effects on the organizationLink to the Effects on the organization section

Creating or attaching a member sends the member.joined webhook event, removals send member.removed, suspensions member.suspended and reactivations member.reactivated.

LimitsLink to the Limits section

LimitValue
Requests per token600 per minute (429, scimType tooMany, Retry-After: 60)
Authentication failures per IP address60 in 10 minutes, then 429
Body size1 MiB (413)
Operations per PATCH100

ErrorsLink to the Errors section

Errors follow the SCIM format. The detail text is in French:

JSON
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  "status": "409",
  "scimType": "uniqueness",
  "detail": "Un groupe porte déjà ce nom."
}
StatusCause
400Invalid request: unreadable JSON, unsupported filter, invalid operation or value.
401Missing or invalid token.
403Protected person or group, suspension decided in the admin console.
404Member or group not found.
409Domain not verified, already a member, no seats left, group name taken, admin group.
413Body too large.
429Too many requests or authentication failures.
503Service temporarily unavailable; try again.

scimType is present when it narrows down the cause: uniqueness, mutability, invalidFilter, invalidSyntax, invalidPath, invalidValue, tooMany.

See alsoLink to the See also section

Moon AI

Moon AI in action

0:00

Explore

Screenshots of chat.realmoon.ai taken on October 29, 2026, with fictional data.

Moon AI

Your preferences

Visits counted without cookies.

Our server counts visits without cookies or trackers. Your theme and your answer about ad measurement are remembered on this device.

Ad measurement

With your consent, our ad networks’ trackers (Google) measure our ads, from the visit to the sign-up and then to the first subscription and its amount, and may show you our ads. Your answer is valid for 13 months; you can change it here at any time.

No answer saved on this device.

After you decline, no tag is loaded anymore and the site deletes the cookies they had set on realmoon.ai. Those on the ad networks’ own domains are managed with them or in your browser.

The Moon AI app has its own privacy settings.