Financial Literature

US Energy Information Administration

EIA API — Oil, gas and power prices, stocks and production — the energy side of every inflation story

When energy is the question — spot and futures prices, weekly crude and product inventories, production, natural gas storage — and you want the official series with history rather than a quote page.

energycommoditiespricesUnited Statesglobal
Asset classesenergy · commodities · prices
Frequencydaily → annual
History1986 → today
Limit · costFree key · 5,000 rows per request
KeyFree key needed — Register at eia.gov/opendata/register.php; DEMO_KEY works for a quick test with a low limit.
Formats · pull withjson · xml · csv — python, excel
LicenceUS government work, public domain.
RedistributeYes, with attribution
Best for“What is WTI or Brent doing, from the official series?” · “Are crude stocks building? (the Wednesday number)”
When to use it

Reach for it when…

When energy is the question — spot and futures prices, weekly crude and product inventories, production, natural gas storage — and you want the official series with history rather than a quote page.

Not for: Intraday prices (a futures feed), non-energy commodities (World Bank Pink Sheet, CFTC for positioning), non-US power markets.

How to read it

Units, revisions, traps

Units. Dollars per barrel (crude), per million Btu (gas), cents per kWh (power); stocks in thousand barrels. Weekly data are for the week ending Friday, released Wednesday.

Revisions. Weekly petroleum data are revised in the monthly report; monthly figures are the ones to trust for history.

  • The v2 API needs facets and data[] parameters spelled exactly; a missing data[0]=value returns metadata only.
  • Series ids from the old v1 API still work through the seriesid route, but the route names differ.
  • Sorting defaults to ascending; ask for sort[0][direction]=desc to get recent rows first.

Classic mistake: Comparing WTI (Cushing) to Brent (dated) without noting the spread has its own story.

How to use it in your own work

Three recipes

Each recipe: Python · Excel · Sheets, with how to read the result. Python recipes run under pandas; recipe 1 is re-run by the weekly check where the source allows it.

How to use it in your own work

Copy the snippet, change the series id, read the result the way the footer says. Replace YOUR_…_KEY with your own key where one is needed.

Recipe 1WTI spot, daily

# Cushing WTI spot price, most recent 60 days
import requests, pandas as pd
KEY = "DEMO_KEY"   # replace with your free key; DEMO_KEY is rate-limited
u = ("https://api.eia.gov/v2/petroleum/pri/spt/data/?api_key=" + KEY + "&frequency=daily&data[0]=value"
     "&facets[series][]=RWTC&sort[0][column]=period&sort[0][direction]=desc&length=60")
df = pd.DataFrame(requests.get(u, timeout=60).json()["response"]["data"])
s = df.set_index(pd.to_datetime(df.period))["value"].astype(float).sort_index()
print(s.tail())
How to read the resultA $10 move in crude is roughly a 0.3–0.4 point move in headline CPI a few months later, via gasoline.

Recipe 2Weekly crude inventories (the Wednesday number)

# US commercial crude stocks excluding SPR, weekly
import requests, pandas as pd
KEY = "YOUR_EIA_KEY"
u = ("https://api.eia.gov/v2/petroleum/stoc/wstk/data/?api_key=" + KEY + "&frequency=weekly&data[0]=value"
     "&facets[series][]=WCESTUS1&sort[0][column]=period&sort[0][direction]=desc&length=104")
df = pd.DataFrame(requests.get(u, timeout=60).json()["response"]["data"])
s = df.set_index(pd.to_datetime(df.period))["value"].astype(float).sort_index()
print(s.diff().tail(8))      # weekly build (+) or draw (−), thousand barrels
How to read the resultThe market trades the surprise against the API/consensus estimate, not the level. Seasonal: builds in spring, draws in summer.

Recipe 3Natural gas storage vs the 5-year average

# working gas in underground storage, weekly, lower 48
import requests, pandas as pd
KEY = "YOUR_EIA_KEY"
u = ("https://api.eia.gov/v2/natural-gas/stor/wkly/data/?api_key=" + KEY + "&frequency=weekly&data[0]=value"
     "&facets[series][]=NW2_EPG0_SWO_R48_BCF&sort[0][column]=period&sort[0][direction]=desc&length=300")
df = pd.DataFrame(requests.get(u, timeout=60).json()["response"]["data"])
s = df.set_index(pd.to_datetime(df.period))["value"].astype(float).sort_index()
wk = s.groupby(s.index.isocalendar().week)
print(pd.DataFrame({"latest": s.tail(1), "5y_avg_same_week": wk.mean().loc[s.index[-1].isocalendar().week]}))
How to read the resultStorage is read against the same week's five-year average; the deviation drives Henry Hub more than the level.

Series → question map

The ids we use from EIA API, each with the question it answers. The catalog's compare view reads the concept tags behind these rows.

SeriesAnswersRegionConcept
RWTCWhat is WTI spot?United Statesenergy
RBRTEWhat is Brent spot?globalenergy
WCESTUS1Are crude stocks building or drawing?United Statesenergy
NW2_EPG0_SWO_R48_BCFHow full is gas storage?United Statesenergy
RNGWHHDWhat is Henry Hub gas?United Statesenergy

Compare with

Same question, different source: World Bank Indicators API, FRED, CFTC Commitments of Traders. The compare view lines up coverage, frequency, history and access side by side and lists what the combination makes possible.

Open compare: EIA API · World Bank Indicators API · FRED →

Questions readers ask

Is there a way to test EIA without registering?

Yes, api_key=DEMO_KEY, with a tight rate limit. Registration is instant and free.

Does FRED carry EIA prices?

The headline spot prices (DCOILWTICO, DCOILBRENTEU, DHHNGSP), one day behind. Inventories and storage are EIA-only.

Why does my v2 query return no data?

The data[0]=value parameter is mandatory; without it the API returns the series metadata only.

From the paper

Educational only — we explain, we never advise · snippet licence: public domain · corrections to [email protected], fixed within a day and logged in the changelog.