Finnhub API
Finnhub provides real-time and historical market data with a developer-friendly free tier. Best known for US stock coverage.
Key endpoints
| Endpoint | Description | Free tier |
|---|---|---|
GET /quote |
Real-time quote (current, high, low, prev close) | ✅ |
GET /stock/profile2 |
Company profile (market cap, industry, etc.) | ✅ |
GET /stock/symbol |
Search/list stock symbols by exchange | ✅ |
GET /company-news |
Company news articles | ✅ |
GET /stock/metric |
Key metrics (52wk high/low, beta, etc.) | ✅ |
GET /stock/candle |
Historical OHLCV candles | ❌ (403) |
GET /stock/dividends |
Dividend history | ❌ |
GET /calendar/earnings |
Earnings calendar | ✅ |
GET /forex/rates |
Forex rates | ✅ |
GET /crypto/candle |
Crypto OHLCV | ✅ |
Python example: stock quote
import httpx
API_KEY = "your_finnhub_key"
BASE = "https://finnhub.io/api/v1"
HEADERS = {"X-Finnhub-Token": API_KEY}
def get_quote(symbol: str) -> dict:
"""Get real-time quote. Header auth keeps key out of URLs/logs."""
resp = httpx.get(f"{BASE}/quote", params={"symbol": symbol}, headers=HEADERS, timeout=10)
resp.raise_for_status()
return resp.json()
# Example
quote = get_quote("AAPL")
print(f"AAPL: ${quote['c']} (prev close: ${quote['pc']})")
Python example: company profile
def get_profile(symbol: str) -> dict:
"""Company fundamentals. Free tier includes profile2."""
resp = httpx.get(f"{BASE}/stock/profile2", params={"symbol": symbol}, headers=HEADERS, timeout=10)
resp.raise_for_status()
return resp.json()
# Example
profile = get_profile("AAPL")
print(f"{profile['name']}: {profile['finnhubIndustry']}, mkt cap ${profile['marketCapitalization']:,.0f}M")
Python example: symbol search
def search_symbols(query: str, exchange: str = "US") -> list[dict]:
"""Search stock symbols. Useful for autocomplete."""
resp = httpx.get(f"{BASE}/search", params={"q": query}, headers=HEADERS, timeout=10)
resp.raise_for_status()
return resp.json().get("result", [])
# Example
results = search_symbols("apple")
for r in results[:3]:
print(f"{r['symbol']}: {r['description']}")
Python example: company news
from datetime import date, timedelta
def get_news(symbol: str, days_back: int = 7) -> list[dict]:
"""Recent news for a symbol."""
to_date = date.today().isoformat()
from_date = (date.today() - timedelta(days=days_back)).isoformat()
resp = httpx.get(
f"{BASE}/company-news",
params={"symbol": symbol, "from": from_date, "to": to_date},
headers=HEADERS, timeout=15,
)
resp.raise_for_status()
return resp.json()
# Example
news = get_news("AAPL", days_back=3)
for n in news[:3]:
print(f"{n['datetime']}: {n['headline'][:80]}")
Notes:
- Free tier: 60 calls/min; global 30 req/sec cap across all plans
/stock/candlereturns 403 on free tier — build charts by polling/quoteor using WebSocket- Prefer
X-Finnhub-Tokenheader over?token=query param (key stays out of logs) - WebSocket:
wss://ws.finnhub.io?token=KEY— 1 concurrent connection per key
Integration surface
- Versioning
- v1 in URL path
- Resource groups
- Stock quotes, Company fundamentals, News, Economic data, Crypto/Forex
- Pagination
- Varies by endpoint; cursor or limit/offset
- Errors
- HTTP 429 on rate limit; 403 on premium endpoints with free key
- Webhooks
- Not supported; use WebSocket for streaming
- Official SDKs
- finnhub-python (official), finnhub-go, finnhub-ruby