Authentication
Memory OS uses API key authentication for all API requests. Every request must include a valid API key in the Authorization header.
API Key Format
API keys follow the format:
mos_live_<random_string>mos_- Memory OS prefix (required)live_- Environment indicator (livefor production,testfor sandbox)<random_string>- 32-character base64url-encoded random string
Example key:
mos_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8Authorization Header
Include your API key in the Authorization header using the Bearer scheme:
Authorization: Bearer mos_live_<your_key>cURL Example
curl -X GET "https://api.mymemoryos.com/api/v1/memories" \
-H "Authorization: Bearer mos_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8"JavaScript Example
const response = await fetch('https://api.mymemoryos.com/api/v1/memories', {
headers: {
'Authorization': 'Bearer mos_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8',
'Content-Type': 'application/json'
}
});Python Example
import requests
headers = {
'Authorization': 'Bearer mos_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8',
'Content-Type': 'application/json'
}
response = requests.get('https://api.mymemoryos.com/api/v1/memories', headers=headers)Scopes
API keys are issued with specific scopes that control access to different API endpoints. Scopes follow a resource:action pattern.
| Scope | Description | Endpoints |
|---|---|---|
memories:read | Read access to memories | GET /v1/memories, GET /v1/memories/:id, GET /v1/entities, GET /v1/tags |
memories:write | Write access to memories | POST /v1/memories, PATCH /v1/memories/:id, DELETE /v1/memories/:id, POST /v1/entities |
search:read | Access to search and context | POST /v1/search, POST /v1/context |
admin | Administrative operations | GET /v1/keys, POST /v1/keys, GET /v1/usage |
* | Full access (all scopes) | All endpoints |
Default Scopes
When creating an API key without specifying scopes, these defaults are applied:
["memories:read", "memories:write", "search:read"]Checking Required Scopes
Each endpoint requires a specific scope. If your API key lacks the required scope, the API returns a 403 Forbidden error:
{
"error": {
"code": "FORBIDDEN",
"message": "Missing scope: admin"
},
"meta": {
"request_id": "req_abc123"
}
}Rate Limiting
API requests are rate-limited per API key to ensure fair usage and system stability.
Default Limits
| Plan | Requests per Minute | Requests per Day |
|---|---|---|
| Free | 100 | 1,000 |
| Pro | 1,000 | 100,000 |
| Enterprise | 10,000 | Unlimited |
| Self-Hosted | Configurable | Configurable |
Rate Limit Headers
Every response includes rate limit information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1704067200| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute |
X-RateLimit-Remaining | Remaining requests in the current window |
X-RateLimit-Reset | Unix timestamp when the rate limit resets |
Handling Rate Limits
When you exceed the rate limit, the API returns a 429 Too Many Requests response:
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded"
},
"meta": {
"request_id": "req_abc123"
}
}The response includes an X-RateLimit-Reset header indicating when you can retry.
Retry Strategy
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const resetTime = parseInt(response.headers.get('X-RateLimit-Reset'));
const waitMs = (resetTime * 1000) - Date.now() + 1000; // Add 1s buffer
console.log(`Rate limited. Waiting ${waitMs}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, Math.max(waitMs, 1000)));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Authentication Error Responses
401 Unauthorized
Returned when the API key is missing or invalid:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
},
"meta": {
"request_id": "req_abc123"
}
}Common causes:
- Missing
Authorizationheader - Incorrect key format (not starting with
mos_) - Revoked or expired API key
- Invalid key hash
403 Forbidden
Returned when the API key lacks required permissions:
{
"error": {
"code": "FORBIDDEN",
"message": "Missing scope: memories:write"
},
"meta": {
"request_id": "req_abc123"
}
}Common causes:
- API key does not have the required scope
- Attempting to access admin endpoints with non-admin key
Creating API Keys
API keys are created via the /v1/keys endpoint (requires admin scope):
curl -X POST "https://api.mymemoryos.com/api/v1/keys" \
-H "Authorization: Bearer mos_live_<admin_key>" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"scopes": ["memories:read", "memories:write", "search:read"],
"rate_limit": 1000
}'Response:
{
"data": {
"id": "key_123456",
"name": "Production API Key",
"key": "mos_live_newKeyValue123...",
"message": "Store this key securely - it will not be shown again"
},
"meta": {
"request_id": "req_abc123",
"latency_ms": 45
}
}Important: The full API key is only returned once during creation. Store it securely immediately.
Security Best Practices
- Never expose keys in client-side code - API keys should only be used in server-side applications
- Use environment variables - Store keys in environment variables, not in code
- Rotate keys regularly - Create new keys and revoke old ones periodically
- Use minimal scopes - Only request the scopes your application needs
- Monitor usage - Check the
/v1/usageendpoint to detect unusual activity - Use separate keys per environment - Use different keys for development, staging, and production
Environment Variables Example
# .env.local
MEMORYOS_API_KEY=mos_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8// In your application
const apiKey = process.env.MEMORYOS_API_KEY;