Historical Queensland Electricity Prices
You need to programmatically pull historical Queensland electricity spot prices and turn them into a clean, reliable time series your app can chart, alert on, or backtest. By the end of this guide, you will query, parse, and validate the Energy API timeseries for AEMO Queensland (AEMO_QLD1_SPOT), understand units and base currency, and ship code that’s safe to run in production.
What you will build, the exact symbol, and how authentication works
This guide focuses on one symbol only: the Energy API’s Queensland electricity spot price.
- Symbol name: Queensland Electricity
- Symbol code: AEMO_QLD1_SPOT
- Unit: AUD/MWh
- Authentication: api_key query parameter. Use the literal placeholder YOUR_API_KEY in examples.
- Plan note: Starter $19.99/mo, trial 7 days / 50 calls.
We will use the GET /api/v1/timeseries endpoint with three required query parameters and one auth parameter:
- start: inclusive start date (YYYY-MM-DD)
- end: inclusive end date (YYYY-MM-DD)
- symbols: comma-separated list of series codes (we will use AEMO_QLD1_SPOT)
- api_key: YOUR_API_KEY
Important catalog facts to keep in mind while integrating:
- Read values from rates.AEMO_QLD1_SPOT keyed by date, and confirm currency via currencies.AEMO_QLD1_SPOT.
- Do not pass base=USD when you also need TTF_GAS or EUA_CO2.
Endpoint you will call and required parameters
The Energy API timeseries endpoint returns date-keyed values for one or more symbols. You must pass start, end, symbols, and your api_key as query parameters.
- HTTP method: GET
- URL: https://energy-api.com/api/v1/timeseries
- Query parameters: start, end, symbols, api_key
For Queensland Electricity (AEMO_QLD1_SPOT), call the endpoint with a date window you care about. The API responds with a compact JSON payload that includes:
- success: boolean
- date: the server’s latest date reference for the response
- base: the base currency string
- rates: an object keyed by symbol → numeric value
- dates: an object keyed by symbol → date string for the observation
- currencies: an object keyed by symbol → currency code
- base_filter_note: null or text note
Quick-start: curl you can paste into your terminal
Below is the official sample you can paste and run after inserting your API key. Keep the parameters exactly as shown to verify your environment is working. Then change symbols to AEMO_QLD1_SPOT to fetch Queensland electricity spot prices.
curl -G "https://energy-api.com/api/v1/timeseries" --data-urlencode "start=2026-01-01" --data-urlencode "end=2026-03-31" --data-urlencode "symbols=AEMO_QLD1_SPOT" --data-urlencode "api_key=YOUR_API_KEY"
Tip: start and end are inclusive. For multi-month pulls, chunk your requests by month or quarter to simplify caching and retries in production jobs.
Understanding responses: official samples and the Queensland series
The two blocks below show the response structure. The first is an official sample payload demonstrating field names and layout. The second is a real response for AEMO_QLD1_SPOT with AUD values you can rely on while building and testing parsing code.
Official sample JSON (field structure reference)
{
"success": true,
"date": "2026-10-23",
"base": "EUR",
"rates": {
"OMIE_ES_DA": 110.0906
},
"dates": {
"OMIE_ES_DA": "2026-10-23"
},
"currencies": {
"OMIE_ES_DA": "EUR"
},
"base_filter_note": null
}
This official sample uses a different symbol (OMIE_ES_DA) to illustrate the schema. For Queensland, substitute symbols=AEMO_QLD1_SPOT and read values from rates.AEMO_QLD1_SPOT with currency AUD.
Queensland Electricity (AEMO_QLD1_SPOT) — real response sample
{"success":true,"date":"2026-10-21","base":"AUD","rates":{"AEMO_QLD1_SPOT":123.29},"dates":{"AEMO_QLD1_SPOT":"2026-10-21"},"currencies":{"AEMO_QLD1_SPOT":"AUD"},"base_filter_note":null}
What the fields mean for our use case:
- success: true means the response is valid and parseable.
- date: 2026-10-21 is the response’s reference date for the dataset returned.
- base: AUD indicates pricing is in Australian dollars for this series.
- rates.AEMO_QLD1_SPOT: 123.29 is the numeric value to store for that date.
- dates.AEMO_QLD1_SPOT: 2026-10-21 is the observation date for that value.
- currencies.AEMO_QLD1_SPOT: AUD confirms the unit currency.
Queensland Electricity (AEMO_QLD1_SPOT) — same real response, test fixture copy
{"success":true,"date":"2026-10-21","base":"AUD","rates":{"AEMO_QLD1_SPOT":123.29},"dates":{"AEMO_QLD1_SPOT":"2026-10-21"},"currencies":{"AEMO_QLD1_SPOT":"AUD"},"base_filter_note":null}
Use this identical block as a local fixture when you write unit tests around your parser. Keeping a verbatim copy ensures your test suite asserts on the exact keys you will meet in production.
Python: fetch and parse AEMO_QLD1_SPOT safely
The snippet below calls the timeseries endpoint for Queensland Electricity, validates presence of fields, and extracts the price and currency for further processing. It also demonstrates chunking a larger date window into multiple calls.
import os
import sys
import json
import time
import urllib.parse
import urllib.request
from datetime import date, timedelta
API_URL = "https://energy-api.com/api/v1/timeseries"
API_KEY = "YOUR_API_KEY" # do not hardcode in production; read from env or secret manager
SYMBOL = "AEMO_QLD1_SPOT"
def fetch_window(start_str, end_str):
params = {
"start": start_str,
"end": end_str,
"symbols": SYMBOL,
"api_key": API_KEY,
}
url = API_URL + "?" + urllib.parse.urlencode(params)
req = urllib.request.Request(url, method="GET")
with urllib.request.urlopen(req, timeout=30) as resp:
if resp.status != 200:
raise RuntimeError(f"HTTP {resp.status}: {resp.read()!r}")
raw = resp.read()
data = json.loads(raw.decode("utf-8"))
if not data.get("success"):
raise RuntimeError("API indicated failure: " + json.dumps(data))
# Field presence checks
for key in ("date", "base", "rates", "dates", "currencies"):
if key not in data:
raise KeyError(f"Missing key in response: {key}")
# Extract the value, currency, and observation date
price = data["rates"].get(SYMBOL)
obs_date = data["dates"].get(SYMBOL)
ccy = data["currencies"].get(SYMBOL)
if price is None or obs_date is None or ccy is None:
raise KeyError(f"Incomplete series fields for {SYMBOL}")
# Return a normalized record
return {
"symbol": SYMBOL,
"observation_date": obs_date,
"price": float(price),
"currency": ccy,
"api_base": data["base"],
"response_date": data["date"]
}
def daterange_chunks(start_dt, end_dt, step_days=31):
cur = start_dt
while cur <= end_dt:
nxt = min(cur + timedelta(days=step_days - 1), end_dt)
yield cur, nxt
cur = nxt + timedelta(days=1)
def fetch_historical(start_dt, end_dt, pause_s=0.5):
records = []
for s, e in daterange_chunks(start_dt, end_dt, step_days=31):
rec = fetch_window(s.isoformat(), e.isoformat())
records.append(rec)
time.sleep(pause_s) # polite pacing; tune per your scheduler
return records
if __name__ == "__main__":
start_dt = date(2026, 1, 1)
end_dt = date(2026, 3, 31)
rows = fetch_historical(start_dt, end_dt)
for r in rows:
print(json.dumps(r))
Notes:
- Symbol is fixed to AEMO_QLD1_SPOT. Keep it singular here to simplify parsing.
- The example reads rates.AEMO_QLD1_SPOT and currencies.AEMO_QLD1_SPOT exactly once per response window. If your use case requires daily granularity within the window, design your data model around the observation date returned in dates.AEMO_QLD1_SPOT.
- Cache responses by (start, end, symbol) in object storage to control costs during development. The Starter plan includes a 7-day trial with 50 calls.
JavaScript: minimal fetch and field extraction
This Node.js example uses fetch to get a single window and returns the price, observation date, and currency for AEMO_QLD1_SPOT.
import fetch from "node-fetch";
const API_URL = "https://energy-api.com/api/v1/timeseries";
const API_KEY = "YOUR_API_KEY"; // load from env in production
const SYMBOL = "AEMO_QLD1_SPOT";
async function fetchQLDWindow(start, end) {
const params = new URLSearchParams({
start,
end,
symbols: SYMBOL,
api_key: API_KEY,
});
const url = `${API_URL}?${params.toString()}`;
const res = await fetch(url, { method: "GET" });
if (!res.ok) {
const text = await res.text();
throw new Error(`HTTP ${res.status}: ${text}`);
}
const data = await res.json();
if (!data.success) throw new Error("API indicated failure");
["date", "base", "rates", "dates", "currencies"].forEach((k) => {
if (!(k in data)) throw new Error(`Missing key: ${k}`);
});
const price = data.rates[SYMBOL];
const obsDate = data.dates[SYMBOL];
const ccy = data.currencies[SYMBOL];
if (price == null || obsDate == null || ccy == null) {
throw new Error(`Incomplete fields for ${SYMBOL}`);
}
return {
symbol: SYMBOL,
price: Number(price),
observation_date: obsDate,
currency: ccy,
api_base: data.base,
response_date: data.date,
};
}
(async () => {
const rec = await fetchQLDWindow("2026-01-01", "2026-03-31");
console.log(rec);
})();
Choosing date windows, retries, and idempotency
Electricity spot pricing is reported continuously across the year, but data vendors often publish daily aggregates for ease of use. Use stable, idempotent jobs to populate your database:
- Pick a coarse window (e.g., monthly) per call: 2026-01-01 to 2026-01-31, then 2026-02-01 to 2026-02-28, and so on.
- Cache each successful response keyed by (symbol, start, end) and persist a normalized row: symbol, observation_date, price (AUD/MWh), currency.
- Design retries to be safe to re-run with the same parameters. Store ETag-like hints if you reverse-proxy responses.
The endpoint returns all required fields in a single page for the requested symbol and range. If you query multiple symbols at once, still extract your target values from the rates, dates, and currencies objects by key.
Units, base currency, time semantics, and market calendar
For AEMO_QLD1_SPOT:
- Unit: AUD/MWh. Treat values as Australian dollars per megawatt-hour.
- Base currency: The response’s base field and currencies.AEMO_QLD1_SPOT are AUD for this symbol. Convert only if your downstream system requires another currency, and keep conversions out of this ingestion step to maintain auditability.
- Dates: Use dates.AEMO_QLD1_SPOT as the canonical observation date for storage and joins. Do not assume the API’s top-level date is the same as the observation date.
- Timezone: The API returns ISO dates without time components in these samples. Align your downstream logic to a consistent timezone (e.g., Australia/Brisbane) for scheduling, but store the API’s provided date as-is.
- Non-trading days: Electricity markets run daily, but publication schedules can vary by holiday or maintenance. If a day’s data is not present, do not forward-fill unless your analytics specifically require it.
Validating and monitoring your ingestion
Defensive checks you should implement from day one:
- Schema validation: Assert presence of success, base, rates, dates, currencies. Verify symbol keys exist before use.
- Currency guardrail: Ensure currencies.AEMO_QLD1_SPOT is AUD. If it isn’t, quarantine the batch and alert.
- Monotonic calendar: Ensure observation_date values do not regress within a run. De-duplicate by symbol+date.
- Range sanity: Reject negative prices if your workflow is not designed to handle them; otherwise, flag for review.
- Transport reliability: Wrap calls with exponential backoff and a circuit breaker to avoid cascading failures.
If you also work with symbols like TTF_GAS or EUA_CO2, remember: do not pass base=USD when you also need those series. Keep currency settings consistent per batch to avoid mixed-base computations downstream.
Field-by-field mapping you will actually store
From the AEMO_QLD1_SPOT response, map the following to your table:
- symbol: literal AEMO_QLD1_SPOT
- observation_date: from dates.AEMO_QLD1_SPOT (YYYY-MM-DD)
- price_aud_per_mwh: from rates.AEMO_QLD1_SPOT
- currency: from currencies.AEMO_QLD1_SPOT (AUD)
- api_base: from base (AUD)
- response_date: from date
Keep ingestion raw and untransformed; perform analytics and conversions in downstream layers so you can re-derive results if the vendor amends history.
Troubleshooting by comparing with a control sample
When you suspect parsing errors, compare your parser’s expectations with the official structure below. It is a valid control sample for keys and types even though it uses a different symbol.
{
"success": true,
"date": "2026-10-23",
"base": "EUR",
"rates": {
"OMIE_ES_DA": 110.0906
},
"dates": {
"OMIE_ES_DA": "2026-10-23"
},
"currencies": {
"OMIE_ES_DA": "EUR"
},
"base_filter_note": null
}
If your code fails against this block, the problem is in your JSON-path logic, not the upstream response. Fix your pathing first (e.g., rates[SYMBOL], not rates.SYMBOL string literal unless your language supports it).
Performance, cost control, and caching
Keep the integration cost-efficient and robust:
- Cache each (symbol, start, end) response for at least 24 hours in development and CI.
- Deduplicate writes: upsert by (symbol, observation_date) instead of blind inserts.
- Batch schedules: run backfills off-peak and pace calls at a modest rate; a 0.25–0.5s pause between calls is usually enough during initial loads.
- Testing: pin to a known response (see the real response fixture above) to lock your unit tests to a stable record.
End-to-end example: from HTTP to a normalized row
Put it all together:
- Call GET /api/v1/timeseries with start=2026-01-01, end=2026-03-31, symbols=AEMO_QLD1_SPOT, api_key=YOUR_API_KEY.
- Assert success==true and presence of base, rates, dates, currencies.
- Extract price=rates.AEMO_QLD1_SPOT, observation_date=dates.AEMO_QLD1_SPOT, currency=currencies.AEMO_QLD1_SPOT.
- Persist a row: (AEMO_QLD1_SPOT, observation_date, price, currency, base, response_date).
- Repeat monthly until your historical range is complete.
FAQ
How do I authenticate?
Pass your key via the api_key query parameter. Use the literal YOUR_API_KEY placeholder in examples; substitute your real key in production.
Which exact symbol should I request for Queensland spot?
Use AEMO_QLD1_SPOT. Read the value from rates.AEMO_QLD1_SPOT and confirm currency in currencies.AEMO_QLD1_SPOT.
What unit are the values in?
AUD/MWh. The response base and currency for AEMO_QLD1_SPOT are AUD.
Can I pull multiple months at once?
Yes. Provide a larger start–end window, or chunk by month to simplify caching and retries. Store the observation date from dates.AEMO_QLD1_SPOT.
Any gotchas with currency base parameters?
Yes. Do not pass base=USD when you also need TTF_GAS or EUA_CO2. Keep a consistent base per batch and verify currencies in the currencies object.
Ready to implement this in your stack? Start your 7-day trial and ship your Queensland Electricity integration today: Register. Need to check query parameters or field references while coding? Keep the Documentation open as you build.
Ready to get started?
Get your API key and start querying energy commodity prices in minutes.
Get API Key