Errors & Limits
Understanding API errors, status codes, and plan-based resource limits, including the error response format, rate limits, and common 4xx causes.
Understanding API errors, rate limits, and plan restrictions.
Error Response Format
All errors follow a consistent format:
{
"statusCode": 400,
"statusMessage": "Name is required",
"message": "Name is required",
"url": "/api/v1/sparks",
"error": true
}
| Field | Description |
|---|---|
statusCode | HTTP status code |
statusMessage | Human-readable error description (set per-error by the handler — for validation errors this is the specific issue, e.g. "Spark not found" or "Invalid spark ID format") |
message | Same content as statusMessage for v1 errors. Reserved for stack/extra context in 5xx responses on debug builds. |
url | The request path (added by Nuxt H3) |
error | true for error responses (added by Nuxt H3) |
data | Optional. Present only when an error carries machine-readable detail (see below). Absent on most errors. |
Always rely on
statusCodefor programmatic handling andstatusMessage(ormessage) for the human-readable reason. Theurlanderrorfields are convenience metadata from the underlying framework.
The data field
Some errors attach a data object with structured detail you can branch on instead of parsing statusMessage. Two shapes you will encounter:
data.code— a stable machine-readable error code. Currently"PLAN_LIMIT"on plan-limit403s, alongsidelimitType,currentPlan,limit, andcurrent. See Plan Limits below.data.expectedNoise— internal telemetry metadata, set totrueon routine401s and on a few404s that are almost always crawler probes. It tells our error monitoring to drop the event so real faults are not buried. It is not part of the public contract: ignore it, and do not branch on it.
Treat any other data key as reserved. Unknown keys may be added at any time, so read the fields you care about rather than asserting on the whole object.
HTTP Status Codes
2xx Success
| Code | Status | Description |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created successfully (e.g. POST /sparks, POST /sparks/{id}/knowledge) |
| 202 | Accepted | Request accepted for asynchronous processing (e.g. POST /sparks/{id}/knowledge with keywords) |
| 204 | No Content | Request succeeded, no response body (e.g. DELETE /sparks/{id}/knowledge/{itemId}) |
4xx Client Errors
| Code | Status | Description |
|---|---|---|
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Access denied or plan limit reached |
| 404 | Not Found | Resource doesn't exist |
| 415 | Unsupported Media Type | Wrong Content-Type header |
| 429 | Too Many Requests | Rate limit exceeded |
5xx Server Errors
| Code | Status | Description |
|---|---|---|
| 500 | Internal Server Error | Server-side error |
| 503 | Service Unavailable | Service temporarily unavailable |
Common Errors
400 Bad Request
Missing Required Field:
{
"statusCode": 400,
"statusMessage": "Name is required"
}
Invalid Input:
{
"statusCode": 400,
"statusMessage": "File too large: document.pdf (55.2MB). Maximum size is 50MB."
}
401 Unauthorized
Missing API Key:
{
"statusCode": 401,
"statusMessage": "Unauthorized",
"message": "Unauthorized",
"url": "/api/v1/sparks",
"error": true,
"data": {
"expectedNoise": true
}
}
The data.expectedNoise flag is internal telemetry metadata, not part of the contract — see The data field above.
Solution: Include the Authorization header:
-H "Authorization: Bearer minds_your_api_key"
403 Forbidden
Plan Limit Reached:
{
"statusCode": 403,
"statusMessage": "Individual plan limit reached",
"message": "Individual plan limit reached",
"url": "/api/v1/sparks",
"error": true,
"data": {
"code": "PLAN_LIMIT",
"limitType": "sparks",
"currentPlan": "premium",
"limit": 100,
"current": 100
}
}
Branch on data.code === "PLAN_LIMIT" and data.limitType rather than on the message text — see Plan Limits below.
Access Denied:
{
"statusCode": 403,
"statusMessage": "Access denied"
}
404 Not Found
Resource Doesn't Exist:
{
"statusCode": 404,
"statusMessage": "Spark not found"
}
415 Unsupported Media Type
Wrong Content-Type:
{
"statusCode": 415,
"statusMessage": "Unsupported Content-Type. Use application/json for links or multipart/form-data for files"
}
Solution: Use the correct Content-Type header:
application/jsonfor JSON requestsmultipart/form-datafor file uploads
429 Too Many Requests
Rate Limit Exceeded:
{
"statusCode": 429,
"statusMessage": "Too many requests. Please try again later."
}
Rate Limits
The v1 API enforces a per-account fixed-window limit. The default deployment limit is 300 requests per minute, but operators can tune it, so integrations must use response headers rather than hard-code that number:
RateLimit-Limit— current per-minute ceilingRateLimit-Remaining— requests remaining in the active windowRetry-After— seconds to wait after a429
The limiter is applied per application instance and may fail open during limiter infrastructure errors. Keep concurrency bounded even when no 429 is observed.
Plan Limits
Different plans have different resource limits.
Mind Limits
| Plan | Maximum Minds |
|---|---|
| Free | Unlimited |
| Individual | 100 |
| Team | Unlimited |
Minds are no longer capped on the Free plan. The one tier that carries a mind cap is Individual, at 100. Note that the Individual plan is "premium" in API payloads (data.currentPlan) — "Individual" is only its display name, and it is the name that appears in statusMessage.
Error when limit reached:
{
"statusCode": 403,
"statusMessage": "Individual plan limit reached",
"message": "Individual plan limit reached",
"url": "/api/v1/sparks",
"error": true,
"data": {
"code": "PLAN_LIMIT",
"limitType": "sparks",
"currentPlan": "premium",
"limit": 100,
"current": 100
}
}
Reading a plan-limit error
Every plan-limit 403 carries the same data shape, so one handler covers all of them:
code— always"PLAN_LIMIT"for this class of error.limitType— which allowance was exhausted. Values reachable from the v1 API are"sparks"(minds owned),"flows"(chats created, including panel sessions),"messages"(messages within one chat or panel), and"groupMembers"(minds in a single group).currentPlan— the caller's plan tier:"free","premium", or"team".limit— the allowance for that plan and limit type.current— the caller's usage at the time of the request.
statusMessage is human-readable and its wording may change; code and limitType are the stable contract.
Knowledge Upload Limits
- File Size: Maximum 50MB per file (all plans)
- Storage: No explicit storage limits currently enforced
API Key Limits
- Maximum Keys: No cap is currently enforced. Delete keys you no longer use rather than letting them accumulate.
Best Practices
Error Handling
Always handle errors:
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
const error = await response.json();
console.error(`Error ${error.statusCode}: ${error.message}`);
// Handle specific errors
if (error.statusCode === 429) {
// Implement retry logic
}
}
const result = await response.json();
return result;
} catch (error) {
console.error('Network error:', error);
}
Retry Logic
Implement smart retries:
- Retry on
429(rate limit) and5xxerrors - Use exponential backoff
- Set maximum retry attempts
- Don't retry on
4xxerrors (except 429)
Monitoring
Track your usage:
- Log rate limit headers
- Monitor error rates
- Set up alerts for recurring errors
- Track response times
Upgrade When Needed
Upgrade your plan if you:
- Hit rate limits frequently
- Need more minds
- Require larger file uploads
- Want priority support
Getting Help
Check Status
Monitor our service status:
- Status page (coming soon)
- Follow @mindsai_co for updates
Contact Support
If you experience:
- Persistent 500 errors
- Incorrect rate limiting
- Unexpected behavior
Contact us:
- Feedback form
- Email: [email protected]
Review Documentation
Status Codes Reference
Quick reference for all HTTP status codes:
2xx Success
├─ 200 OK
└─ 201 Created
4xx Client Error
├─ 400 Bad Request
├─ 401 Unauthorized
├─ 403 Forbidden
├─ 404 Not Found
├─ 415 Unsupported Media Type
└─ 429 Too Many Requests
5xx Server Error
├─ 500 Internal Server Error
└─ 503 Service Unavailable