Error Handling

The API uses standard HTTP status codes and returns all responses in a consistent JSON envelope with success, data, error, and meta fields.

ENVELOPE

Response Format

All API responses — both success and error — follow this standard envelope:

Success Response

{
  "success": true,
  "data": { ... },
  "error": null,
  "meta": {
    "requestId": "req_a1b2c3",
    "timestamp": "2026-03-17T10:30:00Z",
    "version": "v1"
  }
}

Error Response

{
  "success": false,
  "data": null,
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "The \"code\" parameter is required.",
    "details": "Provide a valid contract code (e.g., AAPL_NASDAQ). Use GET /v1/market/exchanges/{symbol} to find available exchanges."
  },
  "meta": {
    "requestId": "req_x9y8z7w6",
    "timestamp": "2026-03-17T10:30:00Z",
    "version": "v1"
  }
}

SCHEMA

Envelope Fields

FieldTypeDescription
successbooleanWhether the request was successful
dataobject | array | nullThe response payload (varies by endpoint)
errorApiError | nullError details when success is false
metaApiMetaRequest metadata (requestId, timestamp, version)

ApiError Object

FieldTypeDescription
codestringMachine-readable error code (e.g., "INVALID_PARAMETER")
messagestringHuman-readable error message
detailsstring | nullAdditional context about the error

ApiMeta Object

FieldTypeDescription
requestIdstringUnique request identifier for debugging
timestampdatetimeServer timestamp of the response
versionstringAPI version (e.g., "v1")

STATUS CODES

HTTP Status Codes

CodeNameDescriptionHow to Fix
400Bad RequestThe request body or parameters are invalid.Check required fields and data types match the schema.
401UnauthorizedMissing or invalid API key / JWT token.Include a valid X-Api-Key header or JWT Bearer token.
403ForbiddenThe API key lacks permission for this action.Use an active API key with sufficient permissions.
404Not FoundThe requested resource does not exist.Verify the symbol, keyId, or endpoint path.
405Method Not AllowedThe path exists but not for this HTTP method. This is rejected by the framework before the response envelope is applied, so a 405 carries an EMPTY body — do not try to parse it as JSON.Check the method for the route (for example POST /v1/portfolio/analyze is POST-only).
429Too Many RequestsRate limit exceeded.Wait and retry. Check your usage limits via GET /v1/account/usage.
500Internal Server ErrorAn unexpected error occurred on the server.Retry the request. Contact support if it persists.
503Service UnavailableA backing service this endpoint depends on — the news pipeline, the Nova ML engine, or the graph analysis service — is temporarily unreachable. The request itself was valid.Retry after a short delay. The error code names the subsystem (for example NEWS_UNAVAILABLE, NOVA_UNAVAILABLE, REPORT_UNAVAILABLE).

RATE LIMITS

Rate Limiting

The API enforces per-account rate limits to ensure fair usage and platform stability. Rate limit information is included in every response via HTTP headers. Check your limits via GET /v1/account/usage.

Per-Minute Limit

A sliding one-minute window, applied per API key. The allowance is set by your subscription tier and ranges from 60 requests/minute on Free to 1,000 on Business. Exceeding it returns 429 RATE_LIMIT_EXCEEDED with a Retry-After header.

Daily Limit

A calendar-day (UTC) quota, also set by your tier — from 1,000 requests/day on Free up to unlimited on Business and Enterprise. It resets at 00:00 UTC.

The same limits apply to every endpoint — there is no separate allowance for market data. Every request that carries your X-Api-Key counts against your quota, including requests made from the Try It console on this site. Requests sent without an API key are bucketed by IP address instead, at 30 requests/minute and 500 per UTC day. Your own effective limits are returned by GET /v1/account/usage and may be higher than your tier default if custom limits are set on your account; the full tier table is at GET /v1/account/tiers.

Rate Limit Headers

HeaderDescription
X-RateLimit-LimitYour daily request quota, or "unlimited" on tiers without one
X-RateLimit-RemainingRequests left in the current UTC day, or "unlimited"
X-RateLimit-ResetUnix timestamp of the next daily reset (00:00 UTC)
X-RateLimit-TierThe subscription tier the limits were resolved from
X-RateLimit-Minute-LimitYour per-minute allowance
X-RateLimit-Minute-RemainingRequests left in the current minute window

HANDLING

When Rate Limited

When you exceed the rate limit, the API returns a 429 Too Many Requests response:

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Per-minute rate limit exceeded.",
    "details": "Tier: Free. Retry after 55 seconds. Upgrade your plan at /v1/account/tiers for higher limits."
  },
  "meta": { "requestId": "req_x9y8z7", "timestamp": "2026-07-28T02:10:05Z", "version": "v1" }
}

Note that this response omits the data key altogether rather than sending "data": null. The message distinguishes which limit you hit — Per-minute rate limit exceeded. or Daily rate limit exceeded.

Recommended strategy: Implement exponential backoff with jitter, and honour the Retry-After header — it carries the exact number of seconds until the limit you hit clears (seconds remaining in the minute, or until 00:00 UTC for the daily limit). X-RateLimit-Reset is the daily reset timestamp, so it is the wrong signal to wait on after a per-minute 429.

Need Help?

Our developer support team is here to help you integrate successfully.

Contact SupportView Quickstart