FRED series without an API key: fredgraph.csv, and when it hands you a zip

Checked 2026-09-08 · Statistical agencies: BLS, Census, BEA, FRED and EIA

The FRED JSON API refuses every keyless call with HTTP 400. The chart download endpoint https://fred.stlouisfed.org/graph/fredgraph.csv?id=SERIES needs no key and returns the full history as CSV, and cosd and coed trim the range. Ask for two series of different frequency in one call and the same URL returns a zip archive of separate CSVs with content-type application/zip - still HTTP 200, still named .csv in the path.

What we saw

The JSON API rejects a keyless observations call with HTTP 400 and a message naming the missing variable. Source (response body, 2026-09-08).

{"error_code":400,"error_message":"Bad Request.  Variable api_key is not set.  Read https:\/\/fred.stlouisfed.org\/docs\/api\/api_key.html for more information."}
HTTP 400

A well-formed but unregistered 32-character key gives a different message at the same status. Source (response body, 2026-09-08).

{"error_code":400,"error_message":"Bad Request.  The value for variable api_key is not registered.  Read https:\/\/fred.stlouisfed.org\/docs\/api\/api_key.html for more information."}
HTTP 400

fredgraph.csv serves one series keyless as CSV with a date column and the series id as the value column, back to the series start. Source (first lines, 2026-09-08).

observation_date,UNRATE
1948-01-01,3.4
1948-02-01,3.8
1948-03-01,4.0
1948-04-01,3.9

Two series of the same frequency come back as one wide CSV, with an empty cell where a series has no observation for that date. Source (headers and first rows, 2026-09-08).

content-type: application/csv
content-disposition: attachment; filename="fredgraph.csv"
observation_date,UNRATE,PAYEMS
1939-01-01,,29923
1939-02-01,,30100

Two series of different frequency come back as a zip archive containing README.txt, monthly.csv and quarterly.csv, at HTTP 200. Source (response headers and first bytes, 2026-09-08).

HTTP/2 200 
content-type: application/zip
content-disposition: attachment; filename="fredgraph.zip"
PK    README.txt ... monthly.csv ... quarterly.csv

cosd and coed trim the range on a single-series request. Source (first lines, 2026-09-08).

observation_date,UNRATE
2025-01-01,4.0
2025-02-01,4.2
2025-03-01,4.2

cosd is ignored once a second series id is added: the same date filter that trimmed a single series returns full history for two. Passing cosd twice does not fix it. Source (first lines, 2026-09-08).

=== two ids one cosd ===
observation_date,UNRATE,PAYEMS
1939-01-01,,29923
1939-02-01,,30100
=== two ids two cosd ===
observation_date,UNRATE,PAYEMS
1939-01-01,,29923
1939-02-01,,30100

A series id that does not exist returns HTTP 404 and an HTML page, not a CSV with an error row. Source (status and content-type, 2026-09-08).

HTTP/2 404 
content-type: text/html; charset=UTF-8

The command

curl -sS -w '\nHTTP %{http_code}\n' 'https://api.stlouisfed.org/fred/series/observations?series_id=UNRATE&file_type=json'
{"error_code":400,"error_message":"Bad Request.  Variable api_key is not set.  Read https:\/\/fred.stlouisfed.org\/docs\/api\/api_key.html for more information."}
HTTP 400

Checked 2026-09-08.

curl -sS 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=UNRATE' | head -5
observation_date,UNRATE
1948-01-01,3.4
1948-02-01,3.8
1948-03-01,4.0
1948-04-01,3.9

Checked 2026-09-08.

curl -sS -D - -o /dev/null 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=UNRATE' | grep -iE 'content-type|content-disposition'; curl -sS -D - -o /dev/null 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=UNRATE,GDPC1' | grep -iE 'content-type|content-disposition'
content-type: application/csv
content-disposition: attachment; filename="UNRATE.csv"
---multi---
content-type: application/zip
content-disposition: attachment; filename="fredgraph.zip"

Checked 2026-09-08.

curl -sS 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=UNRATE,PAYEMS&cosd=2025-01-01' | head -3
observation_date,UNRATE,PAYEMS
1939-01-01,,29923
1939-02-01,,30100

Checked 2026-09-08.

curl -sS -o /tmp/bad.out -w 'HTTP %{http_code}\n' -D - 'https://fred.stlouisfed.org/graph/fredgraph.csv?id=NOTASERIESXYZ' | grep -iE 'HTTP/|content-type'
HTTP/2 404 
content-type: text/html; charset=UTF-8

Checked 2026-09-08.

requestHTTPcontent-typefilenameshape
id=UNRATE200application/csvUNRATE.csvobservation_date,UNRATE
id=UNRATE,PAYEMS (both monthly)200application/csvfredgraph.csvone wide table, blanks where a series is short
id=UNRATE,GDPC1 (monthly + quarterly)200application/zipfredgraph.zipREADME.txt, monthly.csv, quarterly.csv
id=UNRATE&cosd=2025-01-01&coed=2025-06-01200application/csvUNRATE.csvrange honoured
id=UNRATE,PAYEMS&cosd=2025-01-01200application/csvfredgraph.csvrange ignored, full history from 1939
id=NOTASERIESXYZ404text/html-HTML error page

Limits

Open question

Does cosd get ignored for every multi-series request, or only when the series have different start dates? A pair that both begin after the cosd would separate those.

Plain text