Henry Hub Historical Price API: HENRY_HUB Timeseries
You need a reliable way to retrieve historical Henry Hub natural gas prices for finance workflows—backtesting, valuation models, hedging dashboards, or audit trails—and you want to integrate it quickly without guessing field names or response shapes. By the end of this guide, you will query the HENRY_HUB symbol from the Energy API timeseries endpoint, parse the response correctly, and ship production-grade code that handles units, base currency, non-trading days, and caching.
What the HENRY_HUB timeseries delivers for finance use cases
The Energy API exposes the Henry Hub day-ahead benchmark via symbol HENRY_HUB. Each response includes a rate with its currency and the date for which that rate applies, so you can align price curves with valuation dates, mark-to-market schedules, or PnL explain. Units for HENRY_HUB are USD/MMBtu, which is essential when normalizing fundamentals or reconciling with futures curves. The API is read-only and accessed with a simple HTTPS GET.
- Symbol name: Henry Hub
- Symbol code: HENRY_HUB
- Unit: USD/MMBtu
- Authentication: api_key query parameter (use YOUR_API_KEY in examples)
Endpoint, parameters, and authentication
Use GET /api/v1/timeseries with three core query parameters and your API key:
- start: inclusive start date (YYYY-MM-DD)
- end: inclusive end date (YYYY-MM-DD)
- symbols: comma-separated list; here use HENRY_HUB
- api_key: your credential; pass as a query parameter
Endpoint: https://energy-api.com/api/v1/timeseries
Do not pass a base= parameter when requesting HENRY_HUB; the response will include the base and currencies for you. In particular, do not pass base=USD when you also need other symbols like TTF_GAS or EUA_CO2 later—query them as needed and read their currencies from the response.
Quick start: curl you can copy and run
The following request fetches a historical window for Henry Hub. Replace YOUR_API_KEY with your credential.
curl -G "https://energy-api.com/api/v1/timeseries" \
--data-urlencode "start=2026-01-01" \
--data-urlencode "end=2026-03-31" \
--data-urlencode "symbols=HENRY_HUB" \
--data-urlencode "api_key=YOUR_API_KEY"
Starter plan is $19.99/mo with a 7-day trial that includes 50 calls. If you are cost-constrained during development, cache responses and avoid re-issuing identical windows more than necessary.
Refer to the official Documentation for additional fields and symbols if you expand beyond Henry Hub.
Response format and field semantics
The API returns a compact JSON with top-level metadata—success flag, a base currency, and per-symbol data—so your parser can stay simple. For Henry Hub, read three places:
- rates.HENRY_HUB: the numeric price
- dates.HENRY_HUB: the date that price applies to
- currencies.HENRY_HUB: the price currency (USD for Henry Hub)
Sample response you will receive for HENRY_HUB (use these exact values when testing your parser):
{"success":true,"date":"2026-09-22","base":"USD","rates":{"HENRY_HUB":2.9},"dates":{"HENRY_HUB":"2026-09-22"},"currencies":{"HENRY_HUB":"USD"},"base_filter_note":null}
Field notes:
- date: a top-level date reference. Use dates.HENRY_HUB to align each symbol specifically.
- base: the aggregation currency context for the response. For HENRY_HUB you should rely on currencies.HENRY_HUB for the price currency (USD).
- rates: a map keyed by symbol code.
- dates: a map keyed by symbol code, describing the applicable date for each symbol’s rate.
- currencies: a map keyed by symbol code, describing each symbol’s quote currency.
- base_filter_note: nullable string; if present, it can explain adjustments when base filters are applied. Leave as-is unless the docs specify behavior you need to handle.
Parsing HENRY_HUB safely in Python
The following Python example calls the same endpoint and extracts the fields your finance code will actually use. It handles gaps by returning None if the symbol is missing. Make sure to validate the currency before downstream calculations.
import os
import sys
import json
import urllib.parse
import urllib.request
API_URL = "https://energy-api.com/api/v1/timeseries"
API_KEY = os.getenv("ENERGY_API_KEY", "YOUR_API_KEY")
def fetch_henry_hub(start, end):
params = {
"start": start,
"end": end,
"symbols": "HENRY_HUB",
"api_key": API_KEY,
}
query = urllib.parse.urlencode(params)
url = f"{API_URL}?{query}"
with urllib.request.urlopen(url) as resp:
data = json.loads(resp.read().decode("utf-8"))
return data
def latest_point(data, symbol="HENRY_HUB"):
# Expected keys: rates[symbol], dates[symbol], currencies[symbol]
rates = data.get("rates", {})
dates = data.get("dates", {})
currencies = data.get("currencies", {})
value = rates.get(symbol)
value_date = dates.get(symbol)
ccy = currencies.get(symbol)
# Validate currency for Henry Hub workflows expecting USD
if ccy and ccy != "USD":
raise ValueError(f"Unexpected currency for {symbol}: {ccy}")
return {"date": value_date, "value": value, "currency": ccy}
if __name__ == "__main__":
# Example: read a quarter for backtesting; downstream you can resample as needed
payload = fetch_henry_hub("2026-01-01", "2026-03-31")
point = latest_point(payload)
print(json.dumps(point, indent=2))
Downstream tips:
- Store dates as UTC midnight without timezone conversions—Henry Hub is a daily index; do not convert to intraday timestamps.
- Keep the original currency (USD) for audit. If you convert later, record both the original rate and FX rate used.
Historical windows: constructing reliable queries
Query a window that matches your finance task. For a daily PnL run, set start to the prior business day and end to the same day. For a backtest, request the entire historical window you need once, then cache it. Example parameters:
- start=2026-01-01
- end=2026-03-31
- symbols=HENRY_HUB
The response format remains consistent: read rates.HENRY_HUB, dates.HENRY_HUB, and currencies.HENRY_HUB. The service can return the latest available point within your range depending on data coverage. Treat missing days as genuine gaps and avoid forward-filling unless your risk policy allows it.
End-to-end extraction and validation steps
1) Issue request and cache the raw JSON
Persist the raw response for the exact (start, end, symbols) triple, keyed by a stable hash. This avoids reusing trial calls and speeds up job retries. The Starter plan’s 50-call trial limit is easy to exceed in iterative development unless you cache.
2) Parse only the fields you need
For a finance curve, you usually need date, value, currency. Extract these via dates.HENRY_HUB, rates.HENRY_HUB, and currencies.HENRY_HUB.
3) Validate units and currency
HENRY_HUB is USD/MMBtu. Keep this unit in your schema and do not coerce to other energy units without a conversion layer. Confirm currencies.HENRY_HUB == "USD".
4) Handle gaps and non-trading days
Henry Hub prints by calendar day, but market holidays or data publication cycles can leave gaps. Write your loader to accept missing days, avoid implicit fills, and log any discontinuities for reconciliation.
5) Normalize date semantics
Use the ISO date string from dates.HENRY_HUB. Store as date type, not a datetime with a local timezone. If your system uses timestamps, set 00:00:00Z and carry a separate date key for grouping.
Complete JSON responses (copy-pasteable) for testing your parser
Use the following real responses to validate your JSON parsing logic. They are complete and should not be altered.
Example A: Henry Hub daily point
{"success":true,"date":"2026-09-22","base":"USD","rates":{"HENRY_HUB":2.9},"dates":{"HENRY_HUB":"2026-09-22"},"currencies":{"HENRY_HUB":"USD"},"base_filter_note":null}
Example B: Same Henry Hub structure you should expect for a single-day slice
{"success":true,"date":"2026-09-22","base":"USD","rates":{"HENRY_HUB":2.9},"dates":{"HENRY_HUB":"2026-09-22"},"currencies":{"HENRY_HUB":"USD"},"base_filter_note":null}
Example C: Reuse this to test idempotent cache reads and currency checks
{"success":true,"date":"2026-09-22","base":"USD","rates":{"HENRY_HUB":2.9},"dates":{"HENRY_HUB":"2026-09-22"},"currencies":{"HENRY_HUB":"USD"},"base_filter_note":null}
Field usage reminder:
- rates.HENRY_HUB: numeric price you map into your curve node
- dates.HENRY_HUB: business date for valuation alignment
- currencies.HENRY_HUB: USD for unit consistency (USD/MMBtu)
Error handling, retries, and caching design
Because the endpoint is idempotent for a given (start, end, symbols, api_key), you can safely implement exponential backoff on transient network failures and then return the last cached successful payload. For finance jobs that must run at fixed cutoffs, prefer returning the most recent cached window rather than failing the entire run if the network is flaky.
- Timeouts: set a client timeout and retry up to a small cap (e.g., 2–3 retries) before serving cached data.
- Cache key: hash the full request URL (including start, end, symbols) to avoid collisions.
- Schema pinning: validate that the top-level keys success, base, rates, dates, currencies exist; fail fast if they don’t.
Production safeguards for finance workflows
- Provenance: store the raw JSON alongside parsed records to satisfy audit requests.
- Currency discipline: even though HENRY_HUB prices in USD, confirm currencies.HENRY_HUB on every pull before applying portfolio-wide FX logic.
- No base overrides: do not pass base=USD when you also need other energy symbols in adjacent calls; instead, read currencies from the response per symbol.
- Change detection: compute a digest of rates + dates per load to detect upstream revisions.
- Rollups: when building month or quarter averages for finance reporting, weight by the count of available daily observations and document the method.
FAQ
Q1: Which fields do I actually need for a daily Henry Hub curve in finance?
A1: rates.HENRY_HUB (the value), dates.HENRY_HUB (the valuation date), and currencies.HENRY_HUB (USD). Keep the unit metadata USD/MMBtu in your schema.
Q2: Can I request multiple symbols with HENRY_HUB?
A2: Yes, symbols accepts a comma-separated list. However, this guide focuses on HENRY_HUB. When expanding, read each symbol’s currency from currencies rather than forcing a base.
Q3: How do I handle missing days?
A3: Treat gaps as real. Do not forward-fill unless your risk policy specifies it. Log gaps and, if needed, compute aggregates (weekly/monthly) from available observations only.
Q4: What about throughput limits during development?
A4: The trial provides 7 days and 50 calls. Implement response caching keyed by the full query and avoid re-fetching the same windows in loops.
Q5: Do I need timezones?
A5: No. The API returns date-level data for HENRY_HUB. Store dates as ISO dates; if your system requires datetimes, set them to 00:00:00Z and avoid locale conversions.
Ready to integrate Henry Hub prices into your finance stack? Create an API key and start querying HENRY_HUB in minutes: Register. For full parameter details and additional symbols, see the Documentation.
Ready to get started?
Get your API key and start querying energy commodity prices in minutes.
Get API KeyRelated posts
Learn how to fetch the latest Henry Hub natural gas price using the Energy API. Follow our guide to make reque...
Read more →
Streamline developer onboarding with Energy API by creating a sandbox environment for rapid prototyping. Disco...
Read more →
Unlock trading success with our Finance API insights. Learn to optimize P&L using real-time spread and basis a...
Read more →
Master reliable deployments with our guide on building end-to-end integration tests for Energy API workflows....
Read more →
Discover how to effectively benchmark intraday trading algorithms using Finance API market feeds and synthetic...
Read more →