# Finnhub API 403 on a premium stock news endpoint

## TL;DR
A 403 from Finnhub on a premium endpoint means the API key's plan does not include that product, like stock news or premium candles. The free tier covers basic quotes; news and premium data need a paid plan. Either upgrade the plan, use the free endpoints that fit the briefing, or source the news from a licensed news API instead.

## The error
```text
HTTP 403 Forbidden
{"error": "You are not authorized to access this endpoint. Premium plan required."}
```

## When this helps
- Finnhub premium endpoints return 403
- a market data agent needs stock news
- mapping Finnhub endpoints to plan tiers
- deciding whether to upgrade a Finnhub plan

## When it doesn't
- the error is 401; that is the token, not the tier
- the error is 429; that is rate limit
- you need premium data without paying; that is not available

## Works with
Finnhub API v1 as of 2026. Endpoint tiers are provider-side.

## Steps
### 1. Confirm which endpoint is gated and what the free tier covers
```bash
K="token"
curl -s "https://finnhub.io/api/v1/news?category=general&${K}=${FINNHUB_KEY}" -o fh.json -w "HTTP %{http_code}\n"
python3 -c "import json; print(str(json.load(open("fh.json")))[:200])"
```
Expected: The 403 body naming the premium gate. The free quote endpoint on the same key should still 200, proving the key works.

### 2. Verify the free endpoints work with the same key
```bash
K="token"
curl -s "https://finnhub.io/api/v1/quote?symbol=AAPL&${K}=${FINNHUB_KEY}" -o q.json -w "HTTP %{http_code}\n"
python3 -c "import json; print(json.load(open("q.json"))"
```
Expected: HTTP 200 with quote data. Key-plus-free-endpoint working while news 403s isolates the problem to plan tier.

### 3. Source stock news from a fitting channel
```python
import json
routing = {"quotes": "finnhub free tier", "stock_news": "licensed news api or finnhub premium"}
open("market_routing.json", "w").write(json.dumps(routing, indent=2))
print("news routed off the free tier")
```
Expected: A routing table. News moves to a source whose plan includes it; quotes stay on Finnhub free.

### 4. Document the tier map for the market data agent
```python
import json
tiers = {"quote": "free", "company_news": "premium", "candles_basic": "free", "candles_premium": "premium"}
open("finnhub_tiers.json", "w").write(json.dumps(tiers, indent=2))
print("tier map written; agent checks before calling")
```
Expected: A tier map file. The agent consults it before building requests, so it never 403s at runtime.

## Other ways people phrase this
### finnhub 403 premium endpoint
Tier gating. Match the endpoint to the plan or re-source.

### finnhub stock news unauthorized
Company news is a premium product. The free tier never included it.

### finnhub free plan limits
Quotes and basic candles are free; news and premium series are paid.

## Why it happens
Finnhub tiers its API by product: market data basics are free, news and premium series are paid. A 403 on a premium endpoint is the tier enforcement. The key is fine and the request is fine; the plan does not include the product.

## Edge cases
- Plan upgrades can take minutes to propagate; wait before retesting.
- The free tier has a 60-calls-per-minute limit on top of the product tiers.
- WebSocket plans are separate from REST plans; check both.
- Cache premium responses aggressively; they are the expensive calls.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_LCmFtCJnyM75n5yn0GCnfg
