DocsOpen Moon AI
Browse the docs

Roles

Create roles with their permissions and assign them to members, groups or labels through the admin API, with the full catalog of permissions.

On this page

A role is a set of permissions. Five roles are built in; the organization can create others and assign them to a member, to a group (all its members) or to a label (everyone who carries it). A member holds the union of their base role and the roles they receive.

All routes are under https://chat.realmoon.ai/api/v1/orgs/{org_id}. Scopes: roles:read to read, roles:write to write. A write never grants more than the key’s own permissions (403 role_escalation, with permission).

PermissionsLink to the Permissions section

A permission has a reach: org (the whole organization), managed_groups (the groups the person manages) or self (their own data).

PermissionReachAllows
org.settingsorgChange the organization’s settings.
org.delete, org.transferorgDelete or transfer the organization. Reserved for the owner, never in a custom role.
billing.read, billing.manageorgRead or manage billing.
members.readorg, managed_groupsSee members (email addresses only with org).
members.inviteorg, managed_groupsInvite.
members.importorgImport a CSV file.
members.suspend, members.removeorg, managed_groupsSuspend, remove.
members.assign_rolesorgAssign roles.
roles.manageorgCreate and edit roles.
groups.create, groups.deleteorgCreate or delete groups.
groups.membersorg, managed_groupsAdd and remove group members.
groups.rulesorgChange a group’s rules and a dynamic group’s rule.
groups.instructionsorg, managed_groupsWrite a group’s instructions.
labels.manageorgCreate and edit labels.
labels.assignorg, managed_groupsApply labels to members.
policies.orgorgChange the organization’s rules.
models.manageorgManage organization models.
connectors.manageorgManage MCP servers.
storage.manageorgManage storage.
library.manageorgShare knowledge bases.
catalog.publishorgShare agents.
usage.readorg, managed_groups, selfRead usage.
usage.exportorg, managed_groupsExport usage.
security.manageorgDomains, single sign-on, SCIM, accounts.
audit.read, audit.exportorgRead or export the audit log.
licenses.read, licenses.manageorgRead or assign licenses.
api.manageorgManage admin keys and webhooks. Never through a key.

A role’s permissions dictionary maps a permission to a reach:

JSON
{ "members.read": "managed_groups", "groups.members": "managed_groups", "usage.read": "self" }

Built-in rolesLink to the Built-in roles section

The API returns the names of built-in roles in French; the English app shows the name in parentheses.

role_keyNamePermissionsAssignable
ownerPropriétaire (Owner)Allno (base role)
adminAdministrateur (Admin)All except org.delete, org.transfer and billing.manageyes, by the owner only
managerDepends on the organization type: Gestionnaire, Enseignant, Manager, Chef de service (Manager, Teacher, Manager, Head of department)members.read, groups.members, groups.instructions, labels.assign, usage.read, with managed_groupsyes
billingFacturation (Billing contact)billing.read, licenses.readyes
memberDepends on the type: Membre, Élève, Collaborateur, Agent (Member, Student, Employee, Agent)usage.read with selfno (every member)

The manager role acts on the groups the person manages (see Groups). A custom role has custom:<id> as its role_key.

The role objectLink to the The role object section

JSON
{
  "id": "5c1e2f8a-7d4b-4c9e-9a1f-2b3c4d5e6f70",
  "org_id": "8c1f2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
  "key": "prof_principal",
  "name": "Professeur principal",
  "description": "Gère sa classe et ses étiquettes.",
  "permissions": { "members.read": "managed_groups", "groups.members": "managed_groups", "labels.assign": "managed_groups" },
  "created_by": "1f2e3d4c-5b6a-4987-8a6b-5c4d3e2f1a0b",
  "created_at": 1793836800,
  "updated_at": 1793836800,
  "role_key": "custom:5c1e2f8a-7d4b-4c9e-9a1f-2b3c4d5e6f70",
  "builtin": false,
  "assignable": true
}

key is a readable identifier, unique in the organization; assignments use role_key.

List rolesLink to the List roles section

GET /roles · roles:read

Parameters: page, limit (pagination of custom roles, sorted by name). The response also includes builtin (the five built-in roles, with their permissions) and permission_catalog (each permission: key, allowed scopes, owner_only).

Create a roleLink to the Create a role section

POST /roles · roles:write

FieldTypeRequiredDescription
keystringyes2 to 40 characters: unaccented lowercase letters, digits and _. Not owner, admin, manager, billing or member.
namestringyes1 to 128 characters.
descriptionstringnoUp to 500 characters.
permissionsobjectnoPermissions and their reach. {} by default.
cURL
curl https://chat.realmoon.ai/api/v1/orgs/$ORG_ID/roles \
  -H "Authorization: Bearer $MOONAI_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "lecture_utilisation",
    "name": "Lecture de l’utilisation",
    "permissions": {"members.read": "org", "usage.read": "org"}
  }'
Python
import os
import requests

BASE = f"https://chat.realmoon.ai/api/v1/orgs/{os.environ['ORG_ID']}"
HEADERS = {"Authorization": f"Bearer {os.environ['MOONAI_ADMIN_KEY']}"}

role = requests.post(
    f"{BASE}/roles",
    headers=HEADERS,
    json={
        "key": "lecture_utilisation",
        "name": "Lecture de l’utilisation",
        "permissions": {"members.read": "org", "usage.read": "org"},
    },
    timeout=30,
)
role.raise_for_status()
print(role.json()["role_key"])
JavaScript
const BASE = `https://chat.realmoon.ai/api/v1/orgs/${process.env.ORG_ID}`;
const r = await fetch(`${BASE}/roles`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.MOONAI_ADMIN_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    key: 'lecture_utilisation',
    name: 'Lecture de l’utilisation',
    permissions: { 'members.read': 'org', 'usage.read': 'org' },
  }),
});
if (!r.ok) throw new Error(await r.text());
console.log((await r.json()).role_key);

An organization can have up to 100 custom roles.

StatuscodeCause
400invalid_requestInvalid or reserved key, empty name, unknown or owner-only permission, reach not allowed, more than 100 roles.
403role_escalationThe role would grant a permission the key does not have.
409invalid_requestUn rôle avec cet identifiant existe déjà. (a role with this key already exists)

Read a roleLink to the Read a role section

GET /roles/{role_id} · roles:read

role_id is the ID of a custom role (id, not custom:<id>) or the key of a built-in role (owner, admin…). A custom role also carries assignment_count, its number of assignments.

Update a roleLink to the Update a role section

PATCH /roles/{role_id} · roles:write

Optional fields name, description (null clears it) and permissions (replaces everything; null removes every permission). key does not change. You must hold both the role’s current permissions and the new ones. Members who have the role get its new permissions right away. A built-in role returns 404.

Delete a roleLink to the Delete a role section

DELETE /roles/{role_id} · roles:write

Deletes the role, its assignments and its rules. Response: {"success": true, "assignments_removed": 3}.

AssignmentsLink to the Assignments section

The assignment objectLink to the The assignment object section

JSON
{
  "id": "0d9c8b7a-6f5e-4d3c-8b2a-190817263544",
  "org_id": "8c1f2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
  "role_key": "custom:5c1e2f8a-7d4b-4c9e-9a1f-2b3c4d5e6f70",
  "subject_type": "group",
  "subject_id": "3e4f5a6b-7c8d-4e9f-8a0b-1c2d3e4f5a6b",
  "created_by": "1f2e3d4c-5b6a-4987-8a6b-5c4d3e2f1a0b",
  "created_at": 1793836800,
  "subject_name": "Classe de 3A",
  "role_name": "Professeur principal"
}

subject_type is user, group or label; subject_name gives the member’s name, the group’s name or the label’s key = value.

List assignmentsLink to the List assignments section

GET /role-assignments · roles:read

ParameterTypeDescription
role_keystringOne role (manager, custom:<id>…).
subject_typestringuser, group or label.
subject_idstringA member, a group or a label.
page, limitintegerPagination.

Only explicit assignments are listed, not members’ base roles.

Assign a roleLink to the Assign a role section

POST /role-assignments · roles:write

FieldTypeRequiredDescription
role_keystringyesadmin, manager, billing or custom:<id>.
subject_typestringyesuser, group or label.
subject_idstringyesThe ID of the member (active or suspended), the group or the label.

The response is the assignment with created: false if it already existed (the request has no effect and also returns 200).

StatuscodeCause
400invalid_requestowner or member (they come from the base role); unknown role.
400scim_group_roleA group synced from the SCIM directory does not grant roles.
403forbiddenAppointing an admin (owner only, so never through a key); assigning a role to yourself; targeting the owner.
403license_change_forbiddenThe change would move members to another license pool; it requires the permission to manage licenses (licenses:write scope). Carries user_ids and count.
404not_foundMember, group or label not found.
409directory_group_adminThe admin role on a group filled by the directory or by single sign-on.

Remove an assignmentLink to the Remove an assignment section

DELETE /role-assignments · roles:write

Identify the assignment with ?id=<id>, or with a {role_key, subject_type, subject_id} body. Response: {"success": true}. Removing admin is reserved for the owner, and refused if no active admin would be left (409).

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.