FinaQuotes REST API reference

The FinaQuotes REST API is the HTTPS companion to the WebSocket quotes feed. It serves OHLC candle history in nine timeframes, the catalog of instruments the feed delivers, asset class summaries and instrument logos. It is meant for brokers, trading platforms and financial websites that already use the feed and need charts, symbol lists and reference data.

Live prices are not served over REST. Ticks arrive only through the WebSocket feed - see the WebSocket API documentation. Use REST to load history when a chart opens, to build symbol pickers and to show logos.

Base URL and format

  • Base URL: https://feed.finaquotes.com/api/v1/ (HTTPS only).
  • All endpoints are GET requests with query parameters.
  • Responses are JSON. Timestamps are milliseconds since the Unix epoch, always in UTC.
  • The version is part of the path. Fields may be added to responses over time, so parse by name and ignore fields you do not know.
EndpointPurposeToken
/api/v1/instrumentsInstrument catalogrequired
/api/v1/categoriesAsset classes and their sizerequired
/api/v1/candlesOHLC price historyrequired
/api/v1/logos/...Instrument logosnot needed
/api/v1/healthService livenessnot needed

Authentication

Catalog and history endpoints are authenticated with a single header:

header
x-history-token: YOUR_HISTORY_TOKEN

The token is personal. It is issued by the operator together with your feed credentials and belongs to the same client account as your WebSocket access. When that access is revoked, expires or is rotated, the REST token stops working as well.

A request without a valid token returns 404 with an empty body. This is intentional: the API does not confirm that a protected endpoint exists. If you get 404 on every call, check the header name and the token value first.

Keep the token server-side Call the API from your backend and pass the data to your pages. Do not put the token into browser code or mobile apps where users can read it.

GET /api/v1/instruments

Returns the catalog of active instruments served by the feed. It matches the Symbols response of the WebSocket feed one to one: the same symbols and the same price precision. The response contains no prices.

ParameterTypeDescription
categorystring, optionalFilter by asset class: crypto, stocks, forex, metals, commodities, indices or bonds. An unknown value returns 400. Without it the full catalog is returned.

The response is an object with count (the number of items in instruments) and the instruments array, sorted by category and then by symbol. One stock and one currency pair look like this:

json
{
  "symbol": "AAPL",
  "name": "Apple Inc.",
  "category": "stocks",
  "currency": "USD",
  "digits": 2,
  "session": "nasdaq",
  "logo": {
    "icon": "https://feed.finaquotes.com/api/v1/logos/icon/AAPL.webp?v=b7b8407f",
    "full": "https://feed.finaquotes.com/api/v1/logos/logo/AAPL.svg?v=5165a409"
  }
}
{
  "symbol": "AUDCAD",
  "name": "Australian Dollar / Canadian Dollar",
  "category": "forex",
  "currency": "CAD",
  "digits": 5,
  "session": "forex_24_5",
  "logo": null
}
FieldTypeMeaning
symbolstringThe ticker as used by the feed. Tickers with a dot are sent without it, e.g. BRK.B becomes BRKB.
namestringHuman-readable instrument name.
categorystringAsset class, one of the values listed above.
currencystringQuote currency of the price.
digitsintDecimal places in the price - matches Precision in the feed.
sessionstringTrading session type, e.g. 24_7, nasdaq, forex_24_5.
logoobject | nullAbsolute icon and full logo URLs, or null when the instrument has no logo. Either URL inside the object can also be null. See Logos.

GET /api/v1/categories

Lists the asset classes with the number of active instruments in each. The order is fixed, and a class with no active instruments is still listed with a zero count, so the response is safe to render as a static menu.

shape
{
  "count": 7,
  "categories": [
    { "category": "crypto", "count": <int> },
    { "category": "stocks", "count": <int> },
    ...
  ]
}

The top-level count is the number of asset classes. Per-class counts change as the instrument list grows, so do not hardcode them.

GET /api/v1/candles

OHLCV price history for one instrument. Candles are built from one-minute bars; higher timeframes are aggregated from them. All bars are aligned to UTC. Stock candles exist only for the trading hours of the listing exchange, with daylight saving time taken into account; the pre-market and post-market of US stocks are added with session=extended (see below). The archive holds years of daily history and months of intraday history.

ParameterTypeDescription
symbolstring, requiredFeed symbol from the catalog, e.g. AAPL, EURUSD, BRKB.
tfstringTimeframe: 1m, 5m, 15m, 30m, 1H, 4H, 1D, 1W or 1MN. Values are case-sensitive.
fromint, optionalRange start, milliseconds since the Unix epoch (UTC).
toint, optionalRange end, milliseconds since the Unix epoch (UTC).
limitint, optionalNumber of bars. Default 1000, maximum 5000.
sessionstring, optionalregular (default) - regular trading hours only. extended - also the US stock pre-market and post-market; requires extended hours enabled for your account.
json
{
  "symbol": "AAPL",
  "tf": "1H",
  "candles": [
    { "ts": 1782928800000, "open": 293.725, "high": 295.53, "low": 292.7, "close": 294.72, "volume": 4190956, "trades": 43640 },
    { "ts": 1782932400000, "open": 294.73, "high": 295.55, "low": 293.7501, "close": 294.25, "volume": 5363332, "trades": 59130 }
  ]
}
FieldTypeMeaning
tsintBar open time, UTC, milliseconds.
open, high, low, closenumberOHLC prices of the bar.
volumenumberTraded volume of the bar.
tradesintNumber of trades in the bar.

A wrong tf or a missing symbol returns 400; an unknown symbol returns 404. For a period longer than one response, split it into consecutive windows with from and to. The bar that is still forming updates in real time over the WebSocket feed, so a chart usually loads history once over REST and then follows the feed.

Extended hours (US stocks)

With session=extended the response for 1m, 5m, 15m, 30m, 1H and 4H contains the regular session bars together with the pre-market (04:00-09:30) and post-market (16:00-20:00, New York time) bars of US stocks. For other instruments the result is the same as for regular.

  • For 1D, 1W and 1MN the parameter has no effect: daily and longer bars are always built from the regular session.
  • If extended hours are not enabled for your account, session=extended returns 403. To enable them, contact support through your account manager.
  • Any value other than regular or extended returns 400.
request
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/candles?symbol=AAPL&tf=5m&session=extended&limit=500"
Need a parameter that is not listed here, or deeper history for a specific instrument? It is not part of the public API - contact the FinaQuotes team through your account manager.

GET /api/v1/logos/{icon|logo}/{SYMBOL}.{ext}

Instrument logos are static files. They are public brand assets, so no token is needed and the files can be loaded directly in the browser. Take the URLs from the logo field of the catalog instead of building them by hand.

  • icon - a square raster image for instrument lists.
  • logo - a wide logo, usually SVG, for an instrument card.
  • SYMBOL is the catalog symbol (BRKB, not BRK.B).
  • ?v=... is a content version. A versioned URL is cached for a year as immutable; when a logo changes, the catalog returns a new v.

Logos are available for stocks. Other asset classes return logo: null in the catalog. A missing file returns 404.

GET /api/v1/health

A public liveness check for your monitoring. No token is needed. It returns 200 when the service is healthy ("status": "ok") and 503 when it is degraded ("status": "degraded").

json
{
  "status": "ok",
  "uptimeSec": 3600,
  "components": { ... }
}

Rely on the HTTP status and the status field. The contents of components are diagnostic and may change.

Rate limits

REST requests are limited per client IP address. The default is 120 requests per minute; some endpoints allow more. Logos have their own, much higher burst limit so that a list can load many icons at once. A request over the limit returns 429.

  • Cache the catalog and the categories on your side and refresh them every few minutes, not on every page view.
  • Load history once when a chart opens, then follow live updates over the WebSocket feed.
  • On 429, wait and retry with exponential backoff instead of retrying immediately.

There is no per-request billing. The WebSocket feed has no per-message charges either.

Status codes

CodeWhen
200Success.
400Invalid parameters: unknown category, wrong tf or session, missing symbol.
403session=extended in /candles while extended hours are not enabled for your account.
404Missing or invalid x-history-token (empty body), unknown symbol in /candles, or a logo file that does not exist.
429Rate limit exceeded - back off and retry later.
503/health reports the service as degraded.

Examples

curl

shell
# Forex part of the catalog
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/instruments?category=forex"

# Last 500 daily candles of EURUSD
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/candles?symbol=EURUSD&tf=1D&limit=500"

# Liveness, no token
curl -i "https://feed.finaquotes.com/api/v1/health"

Python

Standard library only. The token is read from an environment variable so it never ends up in the code.

history.py
import json
import os
import time
import urllib.error
import urllib.parse
import urllib.request

BASE = "https://feed.finaquotes.com/api/v1"
TOKEN = os.environ["FINAQUOTES_HISTORY_TOKEN"]


def get(path, **params):
    url = BASE + path + "?" + urllib.parse.urlencode(params)
    req = urllib.request.Request(url, headers={"x-history-token": TOKEN})
    for attempt in range(5):
        try:
            with urllib.request.urlopen(req, timeout=15) as resp:
                return json.load(resp)
        except urllib.error.HTTPError as e:
            if e.code == 429:
                time.sleep(2 ** attempt)
                continue
            raise
    raise RuntimeError("rate limited: " + url)


catalog = get("/instruments", category="stocks")
print(catalog["count"], "stocks in the catalog")

week_ms = 7 * 24 * 3600 * 1000
now_ms = int(time.time() * 1000)
bars = get("/candles", symbol="AAPL", tf="1H", **{"from": now_ms - week_ms, "to": now_ms})
for bar in bars["candles"][-3:]:
    print(bar["ts"], bar["open"], bar["high"], bar["low"], bar["close"])

Related