A workspace key (moai_org_…) calls the Moon AI chat on behalf of a team workspace: the request runs in that workspace, with its models, its rules and its usage limit.
Available endpointsLink to the Available endpoints section
A workspace key only reaches these paths, on https://:
| Method and path | Purpose |
|---|---|
POST / or / | A chat response, in the OpenAI Chat Completions format. |
GET / or / | The models the key can use. |
POST / or / | A response in the Anthropic Messages format. |
Any other path returns 403 . On the two Anthropic-format paths, the x-api-key header is accepted in place of Authorization: .
Send a messageLink to the Send a message section
POST /
| Field | Type | Required | Description |
|---|---|---|---|
model | string | yes | An ID returned by GET /. |
messages | list | yes | The messages, in the OpenAI format (role, content). |
stream | boolean | no | true to receive the response as a stream (SSE events). |
curl https://chat.realmoon.ai/api/chat/completions \
-H "Authorization: Bearer $MOONAI_ORG_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-haiku-4.5",
"messages": [{"role": "user", "content": "Résume la politique de congés en trois points."}],
"stream": false
}'import os
import requests
r = requests.post(
"https://chat.realmoon.ai/api/chat/completions",
headers={"Authorization": f"Bearer {os.environ['MOONAI_ORG_KEY']}"},
json={
"model": "anthropic/claude-haiku-4.5",
"messages": [{"role": "user", "content": "Résume la politique de congés en trois points."}],
"stream": False,
},
timeout=120,
)
r.raise_for_status()
print(r.json()["choices"][0]["message"]["content"])const r = await fetch('https://chat.realmoon.ai/api/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MOONAI_ORG_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.5',
messages: [{ role: 'user', content: 'Résume la politique de congés en trois points.' }],
stream: false,
}),
});
if (!r.ok) throw new Error(await r.text());
const data = await r.json();
console.log(data.choices[0].message.content);The response follows the OpenAI format: choices[0].message.content holds the text.
On whose behalfLink to the On whose behalf section
- The key acts on behalf of the person who created it, with the member role, never with admin rights.
- It stays tied to the key’s workspace, whatever workspace that person has open in the app.
- Usage counts toward that person’s limit in that workspace.
What the key does not useLink to the What the key does not use section
So that a key can never read anything private, a request made with it:
- has no attached files, no tools and no tool servers;
- uses neither the person’s memory, nor their connectors, nor their folders;
- only picks from the platform’s public models and the models shared with the workspace, never one of the person’s private models or agents and never a direct connection (
Model).not found
When the key stops workingLink to the When the key stops working section
| Situation | Response |
|---|---|
| Unknown or expired key | 401 |
| The creator is no longer an active owner or admin of the workspace: the key is revoked for good, even if they get that role back | 401 |
| The creator’s account is suspended | 403 |
| The workspace’s plan no longer includes API access | 403 |
| Path not in the list | 403 |
| The server cannot read the data | 503, try again |
Deleting the workspace also makes its keys unusable.
Manage keysLink to the Manage keys section
These routes are called with the session of a workspace owner or admin signed in to Moon AI, never with a key.
Create a keyLink to the Create a key section
POST /
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The key’s name, truncated to 128 characters. |
expires_in_days | integer | no | How long the key is valid, from 1 to 3,650 days. If missing, the key never expires. |
{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"org_id": "8c1f2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
"name": "Intranet",
"key": "moai_org_…",
"key_prefix": "moai_org_3f9a",
"expires_at": 1801296000,
"created_at": 1793520000
}The full key (key) is only returned in this response.
| Status | Code or message | Cause |
|---|---|---|
| 400 | Un (a name is required) | name is empty. |
| 400 | org_api_key_personal_workspace | The workspace is a personal one. |
| 403 | org_api_key_plan_required | The workspace’s plan does not include API access. |
| 409 | org_api_key_limit | The workspace already has 25 active keys. |
List keysLink to the List keys section
GET /
Returns the keys that are not revoked, without their value:
[
{
"id": "6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d",
"org_id": "8c1f2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
"name": "Intranet",
"key_prefix": "moai_org_3f9a",
"created_by": "3f2b9c1d-7e4a-4b8c-9d0e-1f2a3b4c5d6e",
"last_used_at": 1793606400,
"expires_at": 1801296000,
"revoked_at": null,
"created_at": 1793520000,
"updated_at": 1793520000
}
]Revoke a keyLink to the Revoke a key section
DELETE /
Returns {"success": , or 404 if the key does not exist in this workspace. Revocation is permanent.
Every creation and every revocation is recorded in the organization’s audit log.