DocsOpen Moon AI
Browse the docs

Rules

The format of rules for the organization, roles, groups and member exceptions, how they combine, and the routes that read and write them.

On this page

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://chat.realmoon.ai/api/v1/orgs/{org_id}. 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.

JSON
{
  "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
}
KeyValues
models.modeall (every model offered) or allow (only ids, up to 1,000).
models.eu_onlytrue: only models hosted in the European Union; also turns off image_generation, video_generation, music_generation, web_search, deep_research and voice.
modesauto, agent, compare: true or false.
featurestrue or false for each feature (list below).
connectors.modeall, none or allow (only ids, up to 1,000).
connectors.personal_mcpMembers can add their own MCP servers.
files.max_mbMaximum size of a file, from 1 to 500 MB.
files.typesAllowed extensions, without the dot (up to 200).
usage.session_pct, usage.week_pct, usage.month_pctShare of the 5-hour, weekly and monthly usage limit that each member can use, from 1 to 100.
learn_mode_defaultLearning mode is on by default.
outside_accessfalse: members can no longer use Moon AI outside the organization (requires an active contract).
retention_daysHow 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.

JSON
{
  "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"
}
FormValues
Features, modes, models.eu_only, connectors.personal_mcpallow, 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_defaulton, off, or inherit.
models, connectors, files.types{"mode": "only", "ids": [...]}, {"mode": "all"}, {"mode": "none"} (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 deny from a role or a group wins, then an allow, 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 /policies/effective/{user_id} 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 /policies/org · rules:read

JSON
{
  "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 /policies/org · rules:write

FieldTypeRequiredDescription
rulesobjectnoReplaces all the rules. If outside_access or retention_days are missing, their saved values are kept.
instructionsstringnoThe organization’s instructions.

A missing field is left untouched; send at least one of the two.

cURL
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}}}'
Python
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"])
JavaScript
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 invalid_request (message Règles invalides., invalid rules) with errors: up to 20 objects such as {"path": "models.ids", "message": "Indiquez au moins un modèle."} (the message is in French; here, enter at least one model). Turning off outside_access without an active contract returns 403 managed_needs_contract.

PUT /policies/org/models · rules:write

Changes only the model rule: {"models": {"mode": "allow", "ids": ["mistralai/mistral-large-2512"]}}. {"models": {}} goes back to all models. The list of models a rule can allow is read with GET /models/catalog.

Every write to rules sends the policy.updated webhook event with scope_type and scope_id.

Group rulesLink to the Group rules section

GET /policies/groups/{group_id} · rules:read

PUT /policies/groups/{group_id} · rules:write

Same body as for the organization, in the level format. The response also includes group_name and rules_format: 2. 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 /policies/roles · rules:read

JSON
{
  "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 /policies/roles/{role_key} · rules:read

PUT /policies/roles/{role_key} · 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 pathScopePurpose
GET /policies/membersrules:readThe members who have an exception, most recent first.
GET /policies/members/{user_id}rules:readA member’s exception (rules: {} if they have none).
PUT /policies/members/{user_id}rules:writeSet or update the exception; if nothing remains, it is deleted.
DELETE /policies/members/{user_id}rules:writeDelete the exception; returns {"removed": true, "policy_version": 43}.

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 forbidden).

A member’s effective rulesLink to the A member’s effective rules section

GET /policies/effective/{user_id} · members:read

JSON
{
  "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
}
FieldDescription
rulesThe rules that apply to the member.
sourcesFor each setting, the level that decided it.
derivedSettings forced by another rule, for example a feature turned off by models.eu_only.
settingsEach setting with its value and source: member, group:<id>, role:<key>, org or default.
instruction_blocksInstructions 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 /policies/retention/preview?days=365 · rules:read

Returns {"days": 365, "count": 1284, "cutoff": 1730803200, "managed": true}: 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

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.