# Guardian API 429 rate limit on the search endpoint

## TL;DR
Guardian API 429s mean the briefing agent exceeded the 500-calls-per-day limit on the free tier or the per-second burst limit. The fix is request budgeting: cache article bodies, batch queries into fewer calls, and stay under the daily cap. For production briefing volume, the Guardian's approved commercial tier or a licensed news API is the honest answer, not squeezing the free tier.

## The error
```text
HTTP 429 Too Many Requests
(Guardian Open Platform search endpoint timed out / throttled)
```

## When this helps
- Guardian API search calls return 429
- a briefing agent exhausts the daily call budget
- designing request budgets for news APIs
- deciding between free tier and commercial access

## When it doesn't
- the error is 401; that is the API key
- you need more than 500 calls a day permanently; upgrade instead of optimizing
- the API is down; 429 is throttling, 5xx is outage

## Works with
Guardian Open Platform API as of 2026; 500 calls per day on the standard tier.

## Steps
### 1. Confirm the daily quota state
```bash
K="api-key"
curl -s "https://content.guardianapis.com/search?q=[topic]&${K}=${GUARDIAN_KEY}" -o guardian.json -w "HTTP %{http_code}\n"
python3 -c "import json; d=json.load(open("guardian.json")); print(d.get("response", {}).get("status"))"
```
Expected: A status field showing ok or the throttle message. The free tier allows 500 calls per day and 12 per second.

### 2. Batch queries to spend fewer calls
```python
import requests, os
r = requests.get("https://content.guardianapis.com/search", params={"q": "[topic] OR [topic2]", "page-size": 50, "api-key": os.environ["GUARDIAN_KEY"]}, timeout=30)
print(r.status_code, len(r.json()["response"]["results"]))
```
Expected: One call returning up to 50 results. OR queries and large page sizes multiply the value of each call.

### 3. Cache article bodies by article id
```python
import hashlib
art_id = "[guardian article id]"
fp = hashlib.md5(art_id.encode()).hexdigest()
print("cache path:", "cache/guardian_" + fp + ".json")
print("Guardian articles are immutable; cache forever")
```
Expected: A permanent cache path. Article content never changes, so every repeat fetch is a wasted call.

### 4. Add polite spacing between calls
```python
import time, requests, os
for q in ["[topic1]", "[topic2]"]:
    r = requests.get("https://content.guardianapis.com/search", params={"q": q, "api-key": os.environ["GUARDIAN_KEY"]}, timeout=30)
    print(q, r.status_code)
    time.sleep(2)
```
Expected: 200s at a polite pace. The per-second burst limit is separate from the daily cap; spacing handles both.

## Other ways people phrase this
### guardian api rate limit 429
Daily cap or burst limit. Batch, cache, and space requests.

### content.guardianapis.com too many requests
The endpoint behind the Open Platform. Same budgeting advice.

### guardian search api quota exceeded
The free tier is small by design. Production volume needs the commercial tier.

## Why it happens
The Guardian's free API tier is rate-limited to keep it sustainable: 500 calls a day and a per-second burst cap. Briefing agents that query per topic per hour blow through it. The 429 is the budget enforcement; the fix is spending calls wisely or buying a bigger budget.

## Edge cases
- The test key has even lower limits; register for a personal key before building.
- Show-fields and show-blocks parameters cost nothing extra; fetch full bodies in the search call.
- Commercial use requires the approved tier; the free tier is for non-commercial use.
- Response caching headers are weak; implement the article-id cache yourself.

## Provenance

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