Every API call is made with an sk-moon-… key. The key belongs to a workspace: requests are charged to its wallet and follow its spend caps and, in a managed organization, its rules.
Send the keyLink to the Send the key section
Put the key in the Authorization header, after Bearer. The x-api-key header is also accepted.
curl https://api.realmoon.ai/v1/models \
-H "Authorization: Bearer $MOONAI_API_KEY"
# Equivalent
curl https://api.realmoon.ai/v1/models \
-H "x-api-key: $MOONAI_API_KEY"import os
from openai import OpenAI
# The SDK sends the key in the Authorization header.
client = OpenAI(
base_url="https://api.realmoon.ai/v1",
api_key=os.environ["MOONAI_API_KEY"],
)
print([m.id for m in client.models.list()])import OpenAI from 'openai';
// The SDK sends the key in the Authorization header.
const client = new OpenAI({
baseURL: 'https://api.realmoon.ai/v1',
apiKey: process.env.MOONAI_API_KEY,
});
const models = await client.models.list();
console.log(models.data.map((m) => m.id));A request with no key, or with an unknown, revoked or expired key, gets 401 . The other key-related refusals (address not allowed, scope, rate) are described in Errors.
Who manages keysLink to the Who manages keys section
Keys are managed in the portal, in the “API keys” tab (open). Only the workspace owner and admins have access to it. No API endpoint called with an sk-moon-… key can create or revoke a key.
A key belongs to the workspace, not to the person who created it. It stops working:
- when it is revoked or replaced, or when it expires;
- when the workspace is deleted;
- when the workspace owner’s account is suspended (within a minute).
Each time a key is created, a security email goes to the workspace owner and to the billing contact.
Create a keyLink to the Create a key section
- In “API keys”, under “Create an API key”, enter a “Name” (128 characters at most), for example “production backend”.
- Open “Advanced options” if you want to restrict the key (table below).
- Click “Create key”.
- In the “Save your API key” window, copy the key, then click “I have saved my key”. If you close the window without copying, Moon AI asks “Close without copying your key?”: the key will never be shown again.
| Setting | Label | Effect |
|---|---|---|
| Expiration | “Expires in (days)” | The key stops working after this many days (401 ). Empty: “Never”. |
| Spend cap | “Spend cap (€)” and “Period” (“per hour”, “per day”, “per month”) | A cap specific to the key, over a sliding window of one hour, 24 hours or 30 days. Beyond it: 402 with scope: "key". Empty: “No limit”. |
| IP allowlist | “IP allowlist” | IPv4 or IPv6 addresses, or CIDR ranges, separated by commas (for example 1.2.3.4, ). A request coming from anywhere else gets 403 . Empty: all addresses. |
The spend cap and the IP allowlist are set when the key is created. To change them, create a new key with the right settings, update your apps, then revoke the old one.
The key listLink to the The key list section
Under “Your keys”, each row shows:
- the start and end of the key (
sk-moon-...a1b2), so you can recognize it; - “Created”, “Expires”, and the “Expires soon” or “Expired key” badges;
- “Last used” and the number of “Requests” (updated at most once a minute);
- the spend cap and its period, and “Moon Blur off” when that applies.
Configure a keyLink to the Configure a key section
A row’s “Key settings” button opens:
- “Key name” and “Save name”;
- the “Moon Blur” switch, on by default.
Moon Blur masks the personal data it detects (email addresses, phone numbers, bank details, ID numbers) before the request reaches the model provider, and puts it back in the response. Turn it off only if your app needs that data itself, for example to extract it from a document. Moon AI asks for confirmation (“Turn off Moon Blur for this key?”) and records the change in the workspace audit log. See Privacy.
Replace a keyLink to the Replace a key section
The “Replace key” button creates a new key with the same settings and the same validity period. The old key stops working immediately: update your apps with the new one, which is shown only once. For an expired key, the button is called “Renew key” and does the same thing.
To replace a key with no downtime, create a second key instead, deploy it, then revoke the first one.
Revoke a keyLink to the Revoke a key section
The “Revoke key” button stops the key immediately for every app that uses it. This cannot be undone.
Key scopeLink to the Key scope section
A key carries scopes (scopes). Every key created in the portal has the inference scope, which all API endpoints require, including /v1/models and /v1/credits. A key without it gets 403 .
Best practicesLink to the Best practices section
- One key per app and per environment: you can revoke one without stopping the others.
- Keep the key on the server side: never in the code of a web page or a distributed mobile app.
- Read the key from an environment variable or a secrets manager, never hard-coded.
- For a server with a fixed address, add an IP allowlist. To limit your exposure, add a spend cap to the key and caps to the workspace (“Limits” tab).
- Set an expiration on temporary keys (tests, contractors).
HeadersLink to the Headers section
Request headersLink to the Request headers section
| Header | Purpose |
|---|---|
Authorization: | API key. |
x-api-key: | Another way to send the key. |
Content-Type | application/, or multipart/ for a file upload. |
Content-Length | Required for a multipart/ upload (otherwise 411 ). curl and the SDKs send it. |
Response headersLink to the Response headers section
| Header | Values | Present on |
|---|---|---|
X-Moon-Request-Id | gen-… | Every accepted request. The ID to pass to GET /. |
X-Moon-Prompt-Storage | none | Every accepted request: the content is not stored. |
X-Moon-Blur | on, off | Chat and embeddings: Moon Blur scanned the request (on) or is turned off for the key (off). |
X-Moon-Blur | not_applied | Images, videos, speech, transcription: Moon Blur does not apply to this content. |
X-Moon-Blur | not_needed | OCR: the document never leaves our servers. |
X-Moon-Blur-Redactions | number | When Moon Blur replaced values: how many. |
X-Moon-Credits | number | Speech and transcription: credits charged for the request. |
X-Moon-Hosting | fr | OCR: processed on our servers in France. |
Cache-Control | no-store | Media and video responses. |
Retry-After | seconds | Some 429 and 503 errors: how long to wait before retrying. |
To read the headers with an SDK:
curl -i https://api.realmoon.ai/v1/chat/completions \
-H "Authorization: Bearer $MOONAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-haiku-4.5", "messages": [{"role": "user", "content": "Hello"}]}'raw = client.chat.completions.with_raw_response.create(
model="anthropic/claude-haiku-4.5",
messages=[{"role": "user", "content": "Hello"}],
)
print(raw.headers.get("x-moon-request-id"), raw.headers.get("x-moon-blur"))
completion = raw.parse()const { data: completion, response } = await client.chat.completions
.create({
model: 'anthropic/claude-haiku-4.5',
messages: [{ role: 'user', content: 'Hello' }],
})
.withResponse();
console.log(response.headers.get('x-moon-request-id'), response.headers.get('x-moon-blur'));