Getting started
Errors and rate limits
The error format, every status code the API returns, per-minute rate limits and monthly quotas.
Error format
Every error from an endpoint that takes a key has the same JSON body, and the status code is also the HTTP status. Match on the status code; the message is for people and can change.
| Field | Description |
|---|---|
errorstringrequired | Human-readable message. Match on the status code, not on this text. |
statusintegerrequired | The HTTP status code, repeated. |
timestampstringrequired | When the error was produced.date-time |
{
"error": "Insufficient permissions. Required scope: ai:query",
"status": 403,
"timestamp": "2026-10-23T14:02:11.093Z"
}Status codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 307 | Redirect to an OAuth provider (GET /oauth/{provider} only). |
| 400 | The request is invalid: a missing field, a value out of range, an unsupported provider. The message says which. |
| 401 | The key is missing, malformed, unknown or revoked; the account has no active plan; or the key has used its monthly quota. |
| 403 | The key lacks the scope, is a test key on trade execution, or the account is not on the plan the endpoint needs. |
| 410 | The provider has been switched off (Coinbase). |
| 429 | The key hit its per-minute rate limit. |
| 500 | Something failed on our side, or the body was not valid JSON (see below). |
| 503 | GET /health only: the database is unreachable. |
Authentication errors
Every endpoint that takes a key checks it first, in this order, before reading the request body. The first failing check decides the response. The last row is the fallback when a check itself fails.
| Status | When | error |
|---|---|---|
| 401 | No Authorization header. | Missing Authorization header. Include "Authorization: Bearer enton_live_xxx" or "Authorization: Bearer enton_test_xxx" |
| 401 | The header does not start with "Bearer ". | Invalid Authorization format. Use "Bearer enton_live_xxx" or "Bearer enton_test_xxx" |
| 401 | The token does not start with "enton_". | Invalid API key format. Keys must start with "enton_live_" or "enton_test_" |
| 401 | No active key matches. | Invalid or inactive API key |
| 401 | The account that owns the key has no active Trader or Partner plan (a trial counts). | Active subscription required. Please upgrade your plan at https://enton.ai/pricing |
| 429 | The key made its per-minute limit of requests in the last 60 seconds. Sent with Retry-After: 60. | Rate limit exceeded. Please wait before making more requests. |
| 401 | The key has used its monthly quota. Quotas reset at 00:00 UTC on the first of the month. | Monthly quota exceeded. Please upgrade your plan or wait until next month. |
| 401 | The key lookup itself failed. | Internal server error during authentication |
Two of these are 401 where you might expect another code: an account without a plan, and a key over its monthly quota. Read the message to tell them apart from a bad key.
Rate limits
Each key has a per-minute limit set by its plan. The API counts the key's requests in the 60 seconds before each new one; when that count has reached the limit, the request gets 429 with Retry-After: 60.
| Plan | Requests per minute | Requests per month |
|---|---|---|
| Free | 10 | 1,000 |
| Trader | 60 | 50,000 |
| Partner | 120 | No limit |
Responses to authenticated requests carry these headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests per minute allowed for this key. |
X-RateLimit-Remaining | Requests left in the current 60-second window. |
X-RateLimit-Reset | ISO 8601 time 60 seconds after this request. |
X-API-Key-Name | The name you gave the key. Sent on successful authentication only. |
X-API-Key-Tier | The plan the key was created under. Sent on successful authentication only. |
Retry-After | Seconds to wait. Sent with 429 only, always 60. |
Monthly quota
Each key also has a monthly request quota (none on Partner). It resets at 00:00 UTC on the first day of each month. A key over its quota gets 401 with Monthly quota exceeded until the reset. No header reports the quota; the developer portal shows each key's usage.
What counts as a request
- A request that passes the authentication checks counts once toward both the rate limit and the quota, whatever happens next. A 400, a 403 for a missing scope or a 500 still counts.
- A request refused during authentication, including a 429, does not count.
GET /healthandGET /openapi.jsontake no key and never count.
Retrying
- 429: wait for
Retry-Afterseconds, then retry. - 500 and 503: retry with exponential backoff and a cap. Each retry counts toward your limits.
- 400, 401, 403 and 410: do not retry. Fix the request, key, scope or plan first.
- Trade execution: never retry an
executecall blindly after a timeout. Check the order in your broker account first, then prepare again if you need to.
Known quirks
- A body that is not valid JSON gets 500, not 400.
- An error from an internal service can be passed through with that service's status code and message, so you may see a status not listed for an endpoint. Treat any other 4xx as not retryable and any other 5xx as retryable.
- Some endpoints currently fail with 401 after your key is accepted. See the known issues.