Errors
Every error from the QuantConomy API returns the same JSON shape with the appropriate HTTP status. Errors are machine-readable: branch on the HTTP status and the stable error.code rather than parsing error.message, which is human-facing and may change.
Error envelope
Section titled “Error envelope”{ "success": false, "error": { "message": "Human-readable description of what went wrong.", "code": "MACHINE_READABLE_CODE", "details": [{ "field": "limit", "message": "Expected number" }] }, "statusCode": 400, "timestamp": "2026-06-05T12:00:00.000Z"}| Field | Type | Notes |
|---|---|---|
success | false | Always false on errors. Successful responses use { "success": true, "data": ... }. |
error.message | string | Human-readable summary. Do not match on this. |
error.code | string | Stable machine-readable code (see table below). Branch on this. |
error.details | array? | Present only on field-level validation failures. |
statusCode | number | Mirrors the HTTP status. |
timestamp | string | ISO 8601 timestamp of when the error was generated. |
Status codes
Section titled “Status codes”| Status | error.code | Cause | How to fix |
|---|---|---|---|
200 | — | Success. Body is { "success": true, "data": ... }. | — |
400 | BAD_REQUEST | Malformed request or schema validation failure (bad/missing query params, invalid body). Carries details[] on field errors. Also returned to the demo key when you request limit greater than 3 or use a pagination param (cursor/offset/page). | Fix the offending parameters listed in details[]. With the demo key, request at most 3 results and don’t paginate — or use your own key. |
401 | UNAUTHORIZED | Missing, malformed, invalid, expired, or revoked API key. Every endpoint except GET / and GET /health requires a key. | Send a valid Authorization: Bearer mtk_... header (the demo key mtk_demo works). See Authentication. |
402 | INSUFFICIENT_CREDITS | Your credit balance is below the request’s cost. Nothing was charged or executed. With the demo key, this means the shared ~100/hour demo budget is exhausted. | Wait for your monthly grant, buy a credit pack, or upgrade. On the demo key, wait for the hourly refill or use your own key. |
403 | FORBIDDEN | Your plan lacks access to this resource (e.g. SEC data requires Starter or higher; real-time signals require real-time SSE access). | Upgrade your plan to a tier that includes the feature. |
404 | NOT_FOUND | The resource does not exist, or the route/path is unknown. | Check the id and the URL path against the API reference. |
429 | RATE_LIMIT_EXCEEDED | You exceeded your plan’s request rate (or, on the demo key, the shared demo rate bucket). No credits charged. | Back off and retry. Honour Retry-After. See Rate limits. |
500 | INTERNAL_ERROR | Unexpected server-side error. | Retry with backoff. If it persists, check the status page. |
Validation errors (details[])
Section titled “Validation errors (details[])”A 400 from schema validation includes a details array. Each entry pinpoints one offending field:
| Field | Type | Meaning |
|---|---|---|
field | string | The path of the parameter or body field that failed (e.g. limit, packageId). |
message | string | What was expected for that field. |
{ "success": false, "error": { "message": "Validation failed", "code": "BAD_REQUEST", "details": [ { "field": "limit", "message": "Expected number to be less than or equal to 100" }, { "field": "cursor", "message": "Expected string" } ] }, "statusCode": 400, "timestamp": "2026-06-05T12:00:00.000Z"}Example error bodies
Section titled “Example error bodies”401 — missing or invalid key
{ "success": false, "error": { "message": "Unauthorized", "code": "UNAUTHORIZED" }, "statusCode": 401, "timestamp": "2026-06-05T12:00:00.000Z"}402 — out of credits
{ "success": false, "error": { "message": "Insufficient credits", "code": "INSUFFICIENT_CREDITS" }, "statusCode": 402, "timestamp": "2026-06-05T12:00:00.000Z"}402 — demo budget exhausted (the shared demo key’s hourly credit bucket is empty; it refills hourly)
{ "success": false, "error": { "message": "Demo credit budget exhausted — it refills hourly. Sign up for your own credits at https://app.quantconomy.com.", "code": "INSUFFICIENT_CREDITS" }, "statusCode": 402, "timestamp": "2026-06-05T12:00:00.000Z"}400 — demo result cap exceeded (the demo key is limited to 3 results and cannot paginate)
{ "success": false, "error": { "message": "The demo key is limited to 3 results per request. Sign up for your own key at https://app.quantconomy.com to request more.", "code": "BAD_REQUEST" }, "statusCode": 400, "timestamp": "2026-06-05T12:00:00.000Z"}403 — plan does not include SEC data
{ "success": false, "error": { "message": "Forbidden", "code": "FORBIDDEN" }, "statusCode": 403, "timestamp": "2026-06-05T12:00:00.000Z"}404 — unknown resource
{ "success": false, "error": { "message": "Not found", "code": "NOT_FOUND" }, "statusCode": 404, "timestamp": "2026-06-05T12:00:00.000Z"}429 — rate limited (see Rate limits for the accompanying headers)
{ "success": false, "error": { "message": "Rate limit exceeded. Please try again later.", "code": "RATE_LIMIT_EXCEEDED" }, "statusCode": 429, "timestamp": "2026-06-05T12:00:00.000Z"}Retrying safely
Section titled “Retrying safely”Next steps
Section titled “Next steps” Rate limits Per-plan limits, the 429 headers, and a backoff implementation.
Plans & credits What 402 and 403 mean in practice, and how to resolve them.