The rules of a managed organization decide which models, features, connectors, files and usage limits its members get. They are written at four levels: the organization, roles, groups and a member’s exception. Saved rules only apply once the organization is managed (managed, see Organization and settings).
All routes are under https://. Scopes: rules:read to read, rules:write to write.
Organization rulesLink to the Organization rules section
A missing key takes the platform value: everything is allowed, 100% of the limits, no file size imposed.
{
"models": { "mode": "allow", "ids": ["anthropic/claude-haiku-4.5", "mistralai/mistral-large-2512"], "eu_only": false },
"modes": { "agent": false },
"features": { "web_search": true, "image_generation": false, "public_share": false },
"connectors": { "mode": "allow", "ids": ["gmail", "notion"], "personal_mcp": false },
"files": { "max_mb": 50, "types": ["pdf", "docx", "xlsx"] },
"usage": { "session_pct": 50, "week_pct": 80 },
"learn_mode_default": false,
"outside_access": true,
"retention_days": 365
}| Key | Values |
|---|---|
models.mode | all (every model offered) or allow (only ids, up to 1,000). |
models.eu_only | true: only models hosted in the European Union; also turns off image_generation, video_generation, music_generation, web_search, deep_research and voice. |
modes | auto, agent, compare: true or false. |
features | true or false for each feature (list below). |
connectors.mode | all, none or allow (only ids, up to 1,000). |
connectors.personal_mcp | Members can add their own MCP servers. |
files.max_mb | Maximum size of a file, from 1 to 500 MB. |
files.types | Allowed extensions, without the dot (up to 200). |
usage.session_pct, usage.week_pct, usage.month_pct | Share of the 5-hour, weekly and monthly usage limit that each member can use, from 1 to 100. |
learn_mode_default | Learning mode is on by default. |
outside_access | false: members can no longer use Moon AI outside the organization (requires an active contract). |
retention_days | How long conversations are kept, from 30 to 3,650 days; null: nothing is deleted. |
Features in features: web_search, url_fetch, deep_research, image_generation, video_generation, music_generation, voice, sandbox, code_interpreter, memory, projects, routines, agents, skills, artifacts, import, public_share, temporary_chats, file_upload, personal_instructions, cli, api_keys, economy_fallback, messaging.
When music_generation is not set anywhere, music follows video_generation if that one is turned off.
Rules for a role, a group or a memberLink to the Rules for a role, a group or a member section
At these levels, a missing key is inherited. outside_access and retention_days only exist at the organization level.
{
"features": { "web_search": "deny", "image_generation": "allow" },
"modes": { "agent": "deny" },
"models": { "mode": "only", "ids": ["mistralai/mistral-large-2512"], "eu_only": "deny" },
"connectors": { "remove": ["slack"], "personal_mcp": "allow" },
"files": { "max_mb": 20, "types": { "mode": "only", "ids": ["pdf"] } },
"usage": { "month_pct": 40 },
"learn_mode_default": "on"
}| Form | Values |
|---|---|
Features, modes, models.eu_only, connectors.personal_mcp | allow, deny, or inherit / null (inherited); true and false mean allow and deny. For models.eu_only, deny requires models hosted in the European Union. |
learn_mode_default | on, off, or inherit. |
models, connectors, files.types | {"mode": , {"mode": , {"mode": (connectors only), and add / remove to add or remove items. A bare list means only. |
files.max_mb, usage.* | A number; null is inherited. |
InstructionsLink to the Instructions section
Each level can carry instructions: a text of up to 4,000 characters, added to the conversations of the members concerned. An empty string or null clears them. They are added in this order: organization, roles, groups, member exception.
How rules combineLink to the How rules combine section
For each member, these count: their base role, their other roles (given to them, to one of their groups or to one of their labels), the groups they are a member of (not those they only manage) and their exception.
- Features and modes: the exception decides if it is set; otherwise a
denyfrom a role or a group wins, then anallow, then the organization rule. - Numbers (
files.max_mb,usage.*): the exception decides; otherwise the smallest restriction, otherwise the largest relaxation, otherwise the organization value. - Lists (
models,connectors,files.types): the organization list, to which the levels add and then remove items; a removal always wins. The exception comes last.
GET / gives the result for a member and the source of each value.
Read and write the organization rulesLink to the Read and write the organization rules section
GET / · rules:read
{
"id": "5b1e0c3a-7d2f-4a8e-9c11-2f6d8e4b7a90",
"org_id": "8c1f2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
"scope_type": "org",
"scope_id": null,
"rules": { "features": { "image_generation": false }, "retention_days": 365 },
"instructions": "Répondez en français et citez vos sources.",
"rules_format": null,
"updated_by": "0d9a2f44-1c3b-4e7a-8b6f-55e2c1d0a9b8",
"updated_at": 1762339200,
"policy_version": 42,
"limits": { "files_max_mb": { "min": 1, "max": 500 }, "retention_days": { "min": 30, "max": 3650 }, "usage_pct": { "min": 1, "max": 100 }, "instructions_max": 4000, "model_ids_max": 1000, "connector_ids_max": 1000, "file_types_max": 200 },
"counts": { "active_members": 380, "outside_access_retained": 379, "without_group": 4 }
}policy_version goes up with every write to rules, roles, groups, labels or settings. limits also gives the allowed lengths of group, role and label names.
PUT / · rules:write
| Field | Type | Required | Description |
|---|---|---|---|
rules | object | no | Replaces all the rules. If outside_access or retention_days are missing, their saved values are kept. |
instructions | string | no | The organization’s instructions. |
A missing field is left untouched; send at least one of the two.
curl -X PUT https://chat.realmoon.ai/api/v1/orgs/$ORG_ID/policies/org \
-H "Authorization: Bearer $MOONAI_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"rules": {"features": {"image_generation": false}, "usage": {"session_pct": 50}}}'import os
import requests
r = requests.put(
f"https://chat.realmoon.ai/api/v1/orgs/{os.environ['ORG_ID']}/policies/org",
headers={"Authorization": f"Bearer {os.environ['MOONAI_ADMIN_KEY']}"},
json={"rules": {"features": {"image_generation": False}, "usage": {"session_pct": 50}}},
timeout=30,
)
if r.status_code == 400:
print(r.json()["detail"].get("errors"))
r.raise_for_status()
print(r.json()["policy_version"])const r = await fetch(`https://chat.realmoon.ai/api/v1/orgs/${process.env.ORG_ID}/policies/org`, {
method: 'PUT',
headers: { Authorization: `Bearer ${process.env.MOONAI_ADMIN_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ rules: { features: { image_generation: false }, usage: { session_pct: 50 } } }),
});
const body = await r.json();
if (!r.ok) throw new Error(JSON.stringify(body.detail));
console.log(body.policy_version);Invalid rules return 400 (message Règles , invalid rules) with errors: up to 20 objects such as {"path": (the message is in French; here, enter at least one model). Turning off outside_access without an active contract returns 403 .
PUT / · rules:write
Changes only the model rule: {"models": . {"models": goes back to all models. The list of models a rule can allow is read with GET /.
Every write to rules sends the policy.updated webhook event with scope_type and scope_id.
Group rulesLink to the Group rules section
GET / · rules:read
PUT / · rules:write
Same body as for the organization, in the level format. The response also includes group_name and rules_format: . A group’s instructions also require groups:write. A key that cannot act on this group gets 404.
Role rulesLink to the Role rules section
GET / · rules:read
{
"items": [
{ "role_key": "owner", "name": "Propriétaire", "kind": "provided", "has_rules": false, "has_instructions": false },
{ "role_key": "member", "name": "Élève", "kind": "provided", "has_rules": true, "has_instructions": false },
{ "role_key": "custom:9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", "name": "Surveillant", "kind": "created", "has_rules": true, "has_instructions": true }
],
"total": 6,
"policy_version": 42
}Built-in roles come first (owner, admin, manager, member, billing), then custom roles. The names of the manager and member roles depend on the type of organization.
GET / · rules:read
PUT / · rules:write
Same body as for a group; the response also includes role. An unknown role returns 404.
Member exceptionsLink to the Member exceptions section
An exception takes precedence over all the member’s other rules.
| Method and path | Scope | Purpose |
|---|---|---|
GET / | rules:read | The members who have an exception, most recent first. |
GET / | rules:read | A member’s exception (rules: {} if they have none). |
PUT / | rules:write | Set or update the exception; if nothing remains, it is deleted. |
DELETE / | rules:write | Delete the exception; returns {"removed": . |
A key cannot set an exception on its own creator, the owner, an admin, or a member who has more rights than the key (403 ).
A member’s effective rulesLink to the A member’s effective rules section
GET / · members:read
{
"managed": true,
"user_id": "41ab2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"policy_version": 42,
"rules": { "features": { "web_search": false, "image_generation": false }, "models": { "eu_only": true, "mode": "all" }, "retention_days": 365 },
"sources": {
"features.web_search": [{ "scope_type": "group", "scope_id": "<group id>", "name": "Classe 3e B" }],
"models.eu_only": [{ "scope_type": "org", "scope_id": null, "name": null }]
},
"derived": { "features.image_generation": "models.eu_only" },
"instructions": "<organization_instructions source=\"organization\">\nRépondez en français.\n</organization_instructions>",
"instruction_blocks": [{ "scope_type": "org", "scope_id": null, "name": null, "text": "Répondez en français." }],
"group_ids": ["<group id>"],
"base_role": "member",
"role_keys": ["member"],
"managed_group_ids": [],
"member_exception": false,
"layers": [{ "scope_type": "group", "scope_id": "<group id>", "name": "Classe 3e B", "has_rules": true }],
"settings": {
"features.web_search": { "value": false, "source": "group:<group id>", "sources": [], "derived": null },
"usage.session_pct": { "value": 100, "source": "default", "sources": [], "derived": null }
},
"can_edit_exception": true
}| Field | Description |
|---|---|
rules | The rules that apply to the member. |
sources | For each setting, the level that decided it. |
derived | Settings forced by another rule, for example a feature turned off by models.eu_only. |
settings | Each setting with its value and source: member, group:<id>, role:<key>, org or default. |
instruction_blocks | Instructions per level. Without the right to read rules, the instructions of roles, of the exception and of the groups the key does not manage are hidden (hidden: true). |
The calculation runs even when the organization is not managed yet.
Retention previewLink to the Retention preview section
GET / · rules:read
Returns {"days": : the workspace conversations not modified since cutoff that a retention of days days would delete in the next nightly cleanup. days ranges from 30 to 3,650.
See alsoLink to the See also section
- Rules, in the admin console
- Organization models
- Groups