Query QuantLabs equity, ETF, sector and industry data over HTTP
Getting started
Every endpoint lives under one origin and returns JSON. Authenticate by sending your key in the X-API-Key header.
Sign in. API keys are free for every account while QuantLabs is in preview; after that they come with QuantLabs Pro.
Create a key in the panel below. It is displayed once and never again.
Send it with every request.
Base URL
https://quantlabs.ca
Keys are for servers. Anything you ship to a browser is public, so a key in client-side JavaScript is a key you have given away — proxy through your own backend instead.
Your keys
Authentication
X-API-Key is the canonical header. Authorization: Bearer <key> is also accepted, for clients that only support bearer auth.
Three failures are distinguished deliberately, because they need different fixes. 401 invalid_api_key means no key exists with that value — usually a truncated paste. 403 api_key_revoked means you revoked it. 403 pro_required means the key is fine but the subscription behind it has lapsed; resubscribing restores it automatically, without issuing a new key.
Most data endpoints remain readable without a key, returning a reduced payload. A key identifies you, unlocks the Pro data, and raises your rate limits.
Any of `technical`, `fundamental` and `hybrid` may be null. They are independent documents and one can be absent while the others are present — this is the most common integration surprise.
Without a Pro key, `fundamental.history_series.annual` and `.quarterly` are cut to the most recent 4 entries.
`history_series.limited` is set whenever the free-tier cap was applied — including when the series was already 4 entries or shorter. It means "a cap applies to you", not "data was dropped".
Nested documents carry `_id`, `last_updated` and `valid_until`. `_id` is an internal artefact equal to the ticker; do not depend on it.
`valid_until` is advisory. Expiry makes a document a candidate for recompute, not stale data, and fundamentals additionally wait for a new SEC filing before they are re-pulled.
GET/api/aggregateNo key needed
Industry or sector roll-ups: weighted means, percentile bands, concentration (HHI), breadth and component lists.
Same payload for every caller. A key only raises your rate limit.
Parameters
type"industry" | "sector" · required
Which dimension to aggregate over.
namestring · required
The industry or sector name. `key` is accepted as an alias.
Rate limit: 120 burst, 20 req/s with a key — 60 burst, 10 req/s without
Omitting `type` returns `unsupported_type`, not a "missing parameter" error — an empty string simply is not one of the two accepted values.
Names are normalised: lowercased, whitespace collapsed to underscores, then `/` replaced with `_`. "Information Technology" becomes `information_technology`.
That normalisation is worth testing against. "Trucking / Logistics" becomes `trucking___logistics` — three underscores, because the slash is a separate whitespace-delimited token before it is replaced.
The response echoes the normalised `key`. Read it back rather than re-deriving it.
GET/get_fast_dataNo key needed
Latest price, session change and 52-week range for one symbol, from a single stored document.
Same payload for every caller. A key only raises your rate limit.
Parameters
tstring · required
Symbol to look up. `ticker` is accepted as an alias.
Rate limit: 120 burst, 20 req/s with a key — 60 burst, 10 req/s without
The only endpoint that takes a repeated parameter. Everywhere else a repeated parameter silently resolves to its last value.
The symbol cap is applied silently. Asking for 5 symbols without a Pro key returns 2, with no error and no marker — compare the returned key set against what you asked for.
Computed live per request, over a trailing 365 days. It is the slowest endpoint here.
A per-symbol upstream failure is swallowed: that symbol is simply absent from the response and the status is still 200.
`plot` values are raw closing prices, not rebased to a common start.
GET/api/assets/getFuller with a Pro key
Analyst estimates and insider-trading activity for one symbol, computed live.
Insider data requires a Pro key; without one it is locked.
Parameters
tickerstring · required
Symbol to look up. `t` is accepted as an alias.
Rate limit: 30 burst, 2 req/s with a key — 10 burst, 1 req per 2s without
Without a Pro key the `insiders` object is absent and `insiders_locked: true` is present instead. There is no truncated or teaser version.
When there is no insider data at all, neither key appears. So: neither present means "no data", `insiders_locked` means "gated".
An upstream failure fetching analyst data returns 404, not 502 — a 404 here does not reliably mean the symbol is unknown.
Nothing on this endpoint is cached; both halves are fetched live on every call, which is why its limit is the tightest of the data endpoints.
POST/api/ai/fundamentals-overviewKey required
A written narrative summary of a symbol’s fundamentals, generated from a structured context you supply.
Pro only: a Pro key or a signed-in Pro session.
Parameters
tickerstring · optional
Used for logging only — it does not steer the output.
contextobject · required
The structured fundamentals the summary is written from: Q-Scores, valuation, profitability, growth, solvency and the analyst signal.
Rate limit: 5 burst, 1 req per 50s with a key
Example response
{
"summary": "Apple trades at a premium to its sector on every multiple..."
}
Worth knowing
The prompt is built server-side. A prompt string in the body is ignored by design; only the structured `context` reaches the model.
A signed-in caller without an active Pro subscription gets 403 `pro_required`.
Every call reaches a paid model, which is why this endpoint carries the tightest keyed rate limit of any.
A malformed JSON body is currently treated as an empty object rather than rejected, so a broken request can produce a summary written from no context at all.
GET/health/liveNo key needed
Liveness probe. Always 200 when the process is serving.
Returns 503 with `"status": "not_ready"` when a dependency is down.
Rate limits
Limits are token buckets: a burst you can spend at once, refilling at a steady rate. Keyed requests are counted against your key rather than your IP address, so your allowance follows your credential across machines.
Exceeding one returns 429 with a retryAfter field and a matching Retry-After header. Back off and retry; do not spin.
429 response
{ "error": "rate_limited", "retryAfter": 3 }
Two endpoints stay comparatively tight even with a key: /api/assets/get and /get_compare_info fetch from upstream providers on every call, and that traffic is attributed to us rather than to you. The limits exist to keep those sources available to everyone.
Published limits are approximate and may be tightened. Treat 429 as normal operating feedback rather than an error condition.
Errors
Every error is JSON with an error field. Some carry extra context — retryAfter, balance, limit.
`type` was not "industry" or "sector". An omitted `type` lands here too.
400 invalid_content_length
A non-numeric Content-Length header.
401 invalid_api_key
No key exists with that value. Check for a truncated paste.
401 unauthorized
The key-management endpoints were called without a signed-in session.
403 api_key_revoked
The key exists but was revoked. Distinct from 401 so you can tell a revocation from a typo.
403 pro_required
The caller (key owner or signed-in user) does not hold an active Pro subscription.
404 not_found
No such symbol, industry or sector — or, on /api/assets/get, an upstream fetch that came back empty.
409 key_limit_reached
You already hold the maximum number of active keys. Revoke one first.
413 payload_too_large
A request body above 1 MiB.
429 rate_limited
Carries `retryAfter` in seconds, and a matching Retry-After header.
503 storage_unavailable
The datastore is unreachable. Retry with backoff.
Fair use
Market data served here is derived from third-party sources, including Yahoo Finance, SEC EDGAR filings and public insider-transaction disclosures. Redistributing it wholesale, or reselling it as a competing data feed, is not what a Pro subscription covers. Building a product on top of it is.