API errors and rate limits
The JSON shape every Endless REST API failure returns, the data.code field to branch on, and the RateLimit headers for 1,000 requests a minute.
Every failure from the Endless REST API at https://api.endless.app returns JSON in one shape, and every response reports your remaining request budget. Versioning has its own page.
The error shape
{
"code": "FORBIDDEN",
"status": 403,
"message": "Your role does not have permission to do this",
"data": { "code": "permission_denied" }
}| Field | What it is |
|---|---|
code | The HTTP status as a word: BAD_REQUEST, UNAUTHORIZED, NOT_FOUND, … |
status | The HTTP status as a number |
message | A sentence for a person. It may be reworded, so don't match on it |
data.code | The machine-readable reason, in snake_case. This is the field to branch on |
data.hint | When present, the step that resolves it |
data.documentation | When present, a link to the API reference |
The Error schema in the OpenAPI document lists every data.code, and each operation in the API reference lists its statuses.
Common codes
| Status | data.code | What to do |
|---|---|---|
| 400 | (validation) | message names the field and the rule it broke |
| 400 | unsupported_api_version | See API versioning |
| 401 | missing_token | Send Authorization: Bearer <token> |
| 401 | invalid_token | The token didn't verify or expired. Get a new one |
| 402 | insufficient_credits, exceeds_spending_limit | The workspace or the caller can't pay for this call |
| 403 | permission_denied, forbidden | The caller's role or access doesn't allow it |
| 404 | not_found, organization_not_found, … | The resource doesn't exist, or the caller can't open it |
| 404 | route_not_found | No operation matches the path (never an HTML page) |
| 404 | invalid_path_parameter | An id in the path can't name a resource |
| 429 | rate_limited | Wait the seconds in retry_after, then retry |
Rate limits
- Limit: 1,000 requests per 60 seconds per caller, in a policy named
default. One counter per caller across all servers. - Fixed window: it resets all at once, so pace by
RateLimit-Remaining, not by an assumed even rate. - Credits are separate: running out of balance or spending limit returns
402, not429.
Every API response, success or failure, carries the counter in two spellings (browsers can read them too):
RateLimit-Policy: "default";q=1000;w=60
RateLimit: "default";r=997;t=42
RateLimit-Limit: 1000
RateLimit-Remaining: 997
RateLimit-Reset: 42r / RateLimit-Remaining are requests left; t / RateLimit-Reset are seconds until reset. Over the limit, the API returns 429 with a Retry-After header and the same seconds in the body:
{
"code": "TOO_MANY_REQUESTS",
"status": 429,
"message": "Too many requests.",
"data": {
"code": "rate_limited",
"hint": "Wait 42s, then retry. Every response carries RateLimit headers — read them to pace yourself before you are refused.",
"documentation": "https://endless.app/docs/api"
},
"retry_after": 42
}Machine-readable sources
- API index: its
rate_limitanderrorsobjects state this policy. - OpenAPI document: the
Errorschema on every failure response. - The MCP server has its own limit: 60 tool calls per minute per account.