sifting/io
7 min readSiftingIO Team

Natural gas price API: what NATGAS measures, MMBtu explained, and a unit conversion table

What the NATGAS natural gas price measures, what an MMBtu is, how to convert to therms, kWh, MWh and GJ, and how to fetch bars and live prices.

A natural gas price API returns a number like 2.850, and that number is meaningless until you know its unit. NATGAS, the natural gas symbol in SiftingIO's commodities feed, is a US-dollar quote, and US wholesale gas is priced per MMBtu (one million British thermal units), the unit this guide works in. That one fact answers most of the questions that come up when developers wire natural gas prices into a dashboard, a cost model, or a research dataset: why the price is a single-digit dollar figure, why it doesn't match a household utility bill, and why European gas prices look roughly three times bigger. This guide covers what NATGAS measures, what an MMBtu actually is, how to convert between MMBtu, therms, kilowatt-hours, and gigajoules, and the code to fetch historical bars and live prices.

What does NATGAS measure#

NATGAS is the US-dollar spot reference price for natural gas. Its symbol page lists USD as the quote currency and does not print the energy unit; this guide reads the price as USD per MMBtu, the standard unit for US wholesale gas, so check the magnitude of a live value before a conversion goes into production. Most commodity symbols in the feed follow the USD-pair form used across the commodities data product, such as XAUUSD for gold and WTIUSD for crude oil; natural gas is listed as NATGAS. The instrument's live detail page is the natural gas symbol page. The symbol catalog also has a separate NGASUSD page whose request examples use that symbol; this guide uses NATGAS, the symbol named in the API reference and the WebSocket documentation.

The published price is not a pass-through from one venue. SiftingIO describes its commodity values as aggregated, derived, and calculated spot and reference values based on multiple third-party sources, so the published number can differ from the price on any specific venue.

Two boundaries matter. First, the value is a synthetic reference price rather than an official exchange print, and it isn't executable depth; use it for charts, alerts, models, and sanity checks, never for order routing. Second, it's a wholesale benchmark. The rate a utility bills a household includes distribution, storage, and retail margin on top of the commodity itself, so NATGAS will not match anyone's gas bill.

MMBtu explained#

A British thermal unit (Btu) is the energy needed to raise one pound of water by one degree Fahrenheit. MMBtu means one million Btu. The double M comes from the Roman numeral M for thousand, so MM reads "a thousand thousands". You'll also see dekatherm (Dth), which is the same quantity under a different name, and therm, which is one tenth of it.

Natural gas trades by energy content instead of volume because the heat content of a cubic foot varies with the gas mix. Volume conversions are therefore approximate. The US Energy Information Administration's average heat-content figure is about 1,037 Btu per cubic foot, which puts one MMBtu near 964 cubic feet, or roughly 27.3 cubic meters.

UnitDefinition1 MMBtu equals
MMBtu1,000,000 Btu1
Dekatherm (Dth)1,000,000 Btu1
Therm100,000 Btu10 therms
Kilowatt-hour (kWh)3,412.14 Btu293.07 kWh
Megawatt-hour (MWh)3,412,142 Btu0.29307 MWh
Gigajoule (GJ)947,817 Btu1.055056 GJ
Mcf (1,000 cubic feet)~1,037,000 Btu~0.964 Mcf

Every row except Mcf is an exact physical definition (kWh rounded to two decimals). The Mcf row depends on gas composition, so treat it as an estimate.

How do you convert a natural gas price between units#

Take a last trade of 2.850 USD/MMBtu. Dividing or multiplying by the factors above converts the price into whatever unit the rest of your system uses:

Target unitFormulaResult at 2.850 USD/MMBtu
USD per thermprice / 100.2850
USD per dekathermprice × 12.850
USD per kWhprice / 293.070.00972
USD per MWhprice × 3.412149.72
USD per GJprice / 1.0550562.70

The 2.850 figure is an arbitrary worked example; the arithmetic holds at any price level. Two of these conversions come up constantly. Power engineers and European market analysts quote gas in per-MWh terms, so the 3.412 factor bridges the two conventions: 2.85 USD/MMBtu is 9.72 USD/MWh. European benchmark prices are also quoted in euros, so a full comparison needs a currency leg as well. Both legs can come from the same API: divide the USD/MWh figure by the live EURUSD rate from /v1/last/quote/forex/EURUSD to land on EUR/MWh.

Fetching historical bars and live prices#

Historical natural gas bars come from the /v1/hist family. The historical endpoints require gzip, so send Accept-Encoding: gzip; curl's --compressed flag sets the header and decompresses the reply in one step:

curl --compressed -H "X-API-Key: $SIFTING_KEY" \
  "https://api.sifting.io/v1/hist/commodities/NATGAS/bars?start=2026-01-01&interval=1d&limit=200"

Bars are OHLCV with UTC timestamps, at intervals from 1m up to 1mo. The v field is a tick count, the number of price updates observed during the bar, so don't read it as traded volume. start is required on the first page, as a YYYY-MM-DD date or an RFC 3339 timestamp, and end defaults to now. Pagination is cursor-based: pass limit (default 1000, max 2000) and follow meta.next_cursor for as long as the response carries one. The pricing page states that full historical depth is included on every plan, Free to Ultra, and lists 20+ years of history for commodities on supported series. When start predates the available coverage, the API reference documents a 422 data_unavailable error with an earliest field carrying the first date it can serve.

In Python, requests negotiates gzip on its own, which turns the conversion table into a three-line pandas exercise:

import pandas as pd
import requests

resp = requests.get(
    "https://api.sifting.io/v1/hist/commodities/NATGAS/bars",
    headers={"X-API-Key": "sft_your_key_here"},
    params={"start": "2026-01-01", "interval": "1d", "limit": 200},
)
resp.raise_for_status()
bars = pd.DataFrame(resp.json()["data"])

bars["close_per_therm"] = bars["c"] / 10
bars["close_usd_mwh"] = bars["c"] * 3.41214
bars["close_cents_kwh"] = bars["c"] / 293.07 * 100

For the current price, the /v1/last snapshot endpoints return the latest trade and the best bid and ask:

curl -H "X-API-Key: $SIFTING_KEY" \
  "https://api.sifting.io/v1/last/trade/commodities/NATGAS"

The matching quote endpoint, /v1/last/quote/commodities/NATGAS, carries the symbol, bid and ask with sizes, and a Unix millisecond timestamp. If a dashboard needs continuous updates instead of polling, the same API key works over WebSocket at wss://stream.sifting.io/ws/v1; connection setup, keepalive rules, and reconnect handling for commodities are covered in the commodities streaming guide.

Common pitfalls#

The historical endpoints return 406 gzip_required when a request doesn't accept gzip. Plain curl without --compressed hits this immediately. Python's requests sends the header by default, which is why the exact same URL can fail in a terminal and work in a script.

Unit mixups are the classic natural gas bug, and they're silent. A price treated as USD/MWh when it's USD/MMBtu is wrong by a factor of 3.4; treated as USD/therm it's wrong by 10; compared against a European benchmark without converting both the energy unit and the currency, it's off by whatever EURUSD happens to be. A cheap guard is a magnitude assertion after every conversion step: if a per-MMBtu column jumps by a factor of three or ten with no market event behind it, suspect the conversion before the market.

Live snapshots can return 503 stale_snapshot when the latest snapshot is older than the staleness threshold, which the error reference gives as 5 seconds by default. The error body includes last_t and server_now, so the client can decide whether the last value is still usable for display. Treat it as "render with a stale badge and retry later" instead of as an outage.

The free tier requires no credit card and includes bar history and live snapshots, enough to test every conversion in this post against real prices. Start building free