# Alpha Vantage news sentiment API 429 limit exceeded

## TL;DR
Alpha Vantage's free tier allows 25 requests per day, so a briefing agent hits 429 fast, and the news sentiment endpoint costs the same as any other call. The fix is extreme request economy: cache everything, batch symbols into fewer calls, and never poll. For production sentiment intake, the premium plan or a licensed news sentiment provider is the honest answer.

## The error
```text
HTTP 429 Too Many Requests
{"Information": "Thank you for using Alpha Vantage! Our standard API rate limit is 25 requests per day."}
```

## When this helps
- Alpha Vantage calls return 429
- a sentiment pipeline exhausts the daily budget
- designing request economy for tight API quotas
- deciding between free tier and premium

## When it doesn't
- you need more than 25 calls a day permanently; upgrade instead of optimizing
- the error is the premium message; that is tier, not rate
- intraday freshness matters; the free tier cannot deliver it

## Works with
Alpha Vantage API as of 2026; 25 requests per day free, 5 per minute.

## Steps
### 1. Confirm the daily limit state
```bash
K="apikey"
curl -s "https://www.alphavantage.co/query?function=NEWS_SENTIMENT&tickers=AAPL&${K}=${ALPHAVANTAGE_KEY}" -o av.json -w "HTTP %{http_code}\n"
python3 -c "import json; d=json.load(open("av.json")); print(list(d.keys()))"
```
Expected: Either sentiment data or the limit message. The free tier is 25 calls per day and 5 per minute.

### 2. Batch tickers into a single call
```python
import requests, os
r = requests.get("https://www.alphavantage.co/query", params={"function": "NEWS_SENTIMENT", "tickers": "AAPL,MSFT,NVDA", "apikey": os.environ["ALPHAVANTAGE_KEY"]}, timeout=30)
print(r.status_code, len(r.json().get("feed", [])))
```
Expected: One call covering three tickers. Comma-separated tickers multiply the value of each precious call.

### 3. Cache sentiment responses by ticker and date
```python
import hashlib, json
q = "NEWS_SENTIMENT:AAPL:2026-10-09"
fp = hashlib.md5(q.encode()).hexdigest()
print("cache:", "cache/av_" + fp + ".json")
print("sentiment for a past date never changes; cache permanently")
```
Expected: A permanent cache path. Historical sentiment is immutable, so each query is asked exactly once.

### 4. Budget the 25 daily calls explicitly
```python
import json
budget = {"daily_cap": 25, "per_briefing": 5, "tickers_per_call": 10}
open("av_budget.json", "w").write(json.dumps(budget, indent=2))
print("5 calls per briefing, 10 tickers each: 50 tickers a day max")
```
Expected: A budget file. Explicit budgeting keeps the agent inside the free tier instead of discovering the 429 mid-run.

## Other ways people phrase this
### alphavantage 429 limit exceeded
The tiny free tier. Batch tickers, cache forever, budget explicitly.

### alpha vantage news sentiment 429
Sentiment costs a full call. One batched call per briefing, not per ticker.

### alphavantage standard api rate limit 25
The documented free limit. Design around it or pay for premium.

## Why it happens
Alpha Vantage's free tier is deliberately tiny: 25 requests a day across all endpoints. News sentiment is one of the more expensive endpoints to serve, so it shares the same small budget. The 429 is the budget enforcement; briefing agents that query per ticker blow it in one run.

## Edge cases
- The per-minute limit (5) is separate from the daily one; space batched calls.
- Premium tiers raise both limits; compare with licensed sentiment providers.
- Weekend and holiday gaps mean no new sentiment; do not waste calls re-checking.
- The Information message replaces data in the JSON; check for it before parsing feed items.

## Provenance

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