Diesel price API in Python: retail, ULSD and gasoil without mixing units
By OilPriceAPI · API contract and public series checked November 5, 2026
A diesel number needs a market, unit and source date. Texas retail, German retail, US wholesale ULSD and ICE gasoil are different series. Putting them in one chart without those labels makes a valid response misleading. This example checks all four in one call.
Choose a series
| Series | Code | Basis |
|---|---|---|
| Texas retail | DIESEL_RETAIL_STATE_TX_USD | USD/gallon |
| Germany retail | DIESEL_RETAIL_DE_EUR | EUR/litre |
| US wholesale ULSD | ULSD_DIESEL_USD | USD/gallon |
| ICE gasoil | GASOIL_USD | USD/tonne |
DIESEL_USD is a separate distillate market signal, neither a Texas pump average nor the named ULSD assessment. The diesel API guide explains the product and other supported codes.
Run one authenticated request
Set OILPRICEAPI_KEY in your environment, save this as diesel_prices.py, then run python3 diesel_prices.py. The latest-prices API puts current batch rows in data.pricesand unavailable or stale rows in data.missing.
import json
import math
import os
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
codes = [
"DIESEL_RETAIL_STATE_TX_USD", # USD/gallon, Texas retail
"DIESEL_RETAIL_DE_EUR", # EUR/litre, Germany retail
"ULSD_DIESEL_USD", # USD/gallon, wholesale ULSD
"GASOIL_USD", # USD/tonne, ICE gasoil
]
query = urlencode({"by_code": ",".join(codes)})
key = os.environ.get("OILPRICEAPI_KEY")
if not key:
raise SystemExit("Set OILPRICEAPI_KEY before running this example")
request = Request(
"https://api.oilpriceapi.com/v1/prices/latest?" + query,
headers={"Authorization": "Token " + key},
)
try:
with urlopen(request, timeout=10) as response:
payload = json.load(response)
except HTTPError as error:
if error.code in (401, 403):
raise SystemExit("Check the API key and access to these diesel series") from error
if error.code == 402:
raise SystemExit("Check your plan's access to these diesel series") from error
if error.code == 429:
raise SystemExit("Request limit reached; wait before retrying") from error
raise SystemExit(f"API request failed with HTTP {error.code}") from error
except URLError as error:
raise SystemExit("API connection failed; retry after checking the network") from error
if payload.get("status") != "success" or not isinstance(payload.get("data"), dict):
raise RuntimeError("No usable diesel response")
data = payload["data"]
prices = data.get("prices")
missing = data.get("missing", [])
if not isinstance(prices, list) or not isinstance(missing, list):
raise RuntimeError("Unexpected diesel batch response shape")
seen = set()
for quote in prices:
if not isinstance(quote, dict) or quote.get("code") not in codes:
continue
seen.add(quote["code"])
if quote.get("stale") or quote.get("data_status") != "current":
print(quote["code"], "stale:", quote.get("as_of"))
continue
price = quote.get("price")
if (not isinstance(price, (int, float)) or isinstance(price, bool)
or not math.isfinite(price) or not quote.get("as_of")
or not quote.get("unit") or not quote.get("currency")):
print(quote["code"], "invalid price or missing source details")
continue
print(quote["code"], quote["price"], quote["currency"],
"per", quote["unit"], "as of", quote["as_of"])
for omitted in missing:
if isinstance(omitted, dict) and omitted.get("code") in codes:
seen.add(omitted["code"])
print(omitted["code"], "unavailable:", omitted.get("reason"))
for code in codes:
if code not in seen:
print(code, "unavailable: no price or missing reason returned")
A 200 response alone does not mean fresh data. On November 5, the public Germany series had a September 7 source date and a stale status. Check as_of, unit and freshness before using a quote in a fuel-cost model. The latest-prices reference documents the batch and stale-row behavior.
Next step
Start with a free key and the series your application needs. Check current plan and dataset access before production use.