API Errors
All errors return a standard JSON envelope. Use the statusCode and message fields for programmatic handling.
Error Response Format
{
"statusCode": 403,
"message": "Only organization owners and admins can manage policy rules",
"error": "Forbidden"
}Validation errors (400) may include a message array listing each failing field:
{
"statusCode": 400,
"message": ["name must be a string", "role must be one of: member, admin, owner"],
"error": "Bad Request"
}HTTP Status Codes
| Code | Meaning | Common causes |
|---|---|---|
200 | OK | Successful read or mutation |
201 | Created | Resource created |
204 | No Content | Successful deletion |
400 | Bad Request | Validation failure - check message for field details |
401 | Unauthorized | Missing, expired, or invalid token |
403 | Forbidden | Valid token but insufficient role, or JWT-only endpoint called with management token |
404 | Not Found | Resource does not exist or belongs to a different organization |
409 | Conflict | Duplicate resource (e.g. agent name already in use) |
422 | Unprocessable Entity | Semantically invalid request (e.g. parameters don't match capability schema) |
429 | Too Many Requests | Rate limit exceeded - see below |
500 | Internal Server Error | Unexpected server-side error |
401 - Unauthorized
Your token is missing, malformed, or expired.
Checklist:
- The
Authorizationheader is present:Authorization: Bearer fml_mgmt_... - The token has not been revoked (check dashboard → Settings → API Keys)
- The token has not passed its expiry date
- You are not calling a JWT-only endpoint with a management token (use the dashboard instead)
403 - Forbidden
Your token is valid but lacks the required role for this operation.
Checklist:
- The token's role meets the minimum required (see the endpoint summary in the API reference)
- For admin-only operations, upgrade the token role or use a different token
- For JWT-only endpoints, authenticate via the dashboard OAuth2 flow
429 - Rate Limiting
The API applies per-organization rate limits. When exceeded, the response includes a Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{"statusCode": 429, "message": "Too Many Requests"}
Retry strategy: wait Retry-After seconds before retrying. Do not retry immediately - repeated 429s with no backoff will extend the cooldown window.
Retry Patterns
For transient errors (500, 502, 503, 504), use exponential backoff:
async function withRetry<T>(fn: () => Promise<T>, maxAttempts = 3): Promise<T> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (err) {
const isRetryable = err.status >= 500 || err.status === 429;
const isLastAttempt = attempt === maxAttempts;
if (!isRetryable || isLastAttempt) throw err;
const delay = 2 ** attempt * 100; // 200ms, 400ms, 800ms
await new Promise((r) => setTimeout(r, delay));
}
}
throw new Error('unreachable');
}Do not retry 400, 401, 403, 404, or 409 - these are deterministic failures that require a code or configuration fix, not a retry.