gridstatus-api
npx machina-cli add skill MisterClean/claude-plugins/gridstatus-api --openclawGridStatus API Skill
Query electricity grid data from US Independent System Operators (ISOs) using the GridStatus.io API. Access real-time and historical data for load, pricing (LMP), generation, fuel mix, and more.
Quick Start
IMPORTANT: Always use the Python SDK. The direct curl API has issues with date filtering on the free tier and returns stale sample data. The Python SDK correctly handles all parameters.
Setup
- Install SDK (use uv for isolation):
cd /tmp && uv venv -q && source .venv/bin/activate && uv pip install gridstatusio pandas -q
-
API Key: Check for
GRIDSTATUS_API_KEYin the user's.envfile. If not present, instruct the user to:- Create account at https://www.gridstatus.io
- Get API key from Settings page
- Add to
.env:GRIDSTATUS_API_KEY=your_key_here
-
Query data:
import os
os.environ['GRIDSTATUS_API_KEY'] = 'key_from_dotenv'
from gridstatusio import GridStatusClient
client = GridStatusClient()
df = client.get_dataset(
dataset="isone_fuel_mix",
start="2026-01-25",
end="2026-01-26",
limit=100
)
print(df.tail())
Free tier limit: 500,000 rows per month. Always use limit parameter.
Supported ISOs
| ISO | Region | Key Datasets |
|---|---|---|
| ERCOT | Texas | ercot_load, ercot_spp_*, ercot_fuel_mix |
| CAISO | California | caiso_load, caiso_lmp_*, caiso_fuel_mix |
| PJM | Mid-Atlantic/Midwest | pjm_load, pjm_lmp_*, pjm_standardized_* |
| MISO | Midwest | miso_load, miso_lmp_* |
| NYISO | New York | nyiso_load, nyiso_lmp_* |
| ISO-NE | New England | isone_load, isone_lmp_*, isone_fuel_mix |
| SPP | Southwest/Central | spp_load, spp_lmp_* |
See references/datasets-by-iso.md for complete dataset catalog.
Standard Query Template
Use this template for all queries. Run in a Python heredoc:
cd /tmp && source .venv/bin/activate && python3 << 'EOF'
import os
os.environ['GRIDSTATUS_API_KEY'] = 'YOUR_KEY_HERE'
from gridstatusio import GridStatusClient
client = GridStatusClient()
df = client.get_dataset(
dataset="DATASET_NAME",
start="YYYY-MM-DD",
end="YYYY-MM-DD",
limit=100
)
print(df.to_string())
EOF
Common Query Patterns
Current Fuel Mix (What's generating now?)
df = client.get_dataset(
dataset="isone_fuel_mix", # or ercot_fuel_mix, caiso_fuel_mix
start="2026-01-25",
end="2026-01-26",
limit=500
)
latest = df.iloc[-1]
total = latest[['coal','hydro','natural_gas','nuclear','oil','solar','wind','wood','refuse','other']].sum()
print(f"Oil: {latest['oil']:.0f} MW ({latest['oil']/total*100:.1f}%)")
System Load
df = client.get_dataset(
dataset="pjm_load",
start="2026-01-25",
end="2026-01-26",
timezone="US/Eastern",
limit=100
)
print(f"Current load: {df.iloc[-1]['load']:,.0f} MW")
Electricity Prices (LMP)
df = client.get_dataset(
dataset="ercot_spp_real_time_15_min",
start="2026-01-25",
end="2026-01-26",
filter_column="location",
filter_value="HB_HOUSTON",
limit=100
)
print(f"Houston price: ${df.iloc[-1]['spp']:.2f}/MWh")
Zone-Specific Load (Standardized Datasets)
df = client.get_dataset(
dataset="pjm_standardized_hourly",
start="2026-01-25",
end="2026-01-26",
timezone="market"
)
# Zone data in columns: df['load.comed'], df['load.aep'], etc.
print(f"ComEd load: {df.iloc[-1]['load.comed']:,.0f} MW")
Dataset Discovery
Check Dataset Metadata (date range, columns)
# Get dataset info including available date range
import requests
import os
api_key = os.environ.get('GRIDSTATUS_API_KEY')
r = requests.get(f"https://api.gridstatus.io/v1/datasets/pjm_load",
headers={"x-api-key": api_key})
meta = r.json()
print(f"Available: {meta['earliest_available_time_utc']} to {meta['latest_available_time_utc']}")
print(f"Columns: {[c['name'] for c in meta['all_columns']]}")
List Datasets
client.list_datasets(filter_term="ercot") # Search by keyword
datasets = client.list_datasets(filter_term="fuel_mix", return_list=True)
Dataset naming convention: {iso}_{data_type}_{frequency}
ercot_load- ERCOT system loadcaiso_lmp_real_time_5_min- CAISO 5-minute real-time LMPspjm_lmp_day_ahead_hourly- PJM day-ahead hourly LMPs
Energy Calculations
Load (MW) measures instantaneous power. Energy (MWh) = power x time.
| Data Frequency | Energy Formula | Example |
|---|---|---|
| 5-minute | energy_MWh = load_MW * (5/60) | 100,000 MW x 0.0833 = 8,333 MWh |
| 15-minute | energy_MWh = load_MW * (15/60) | 100,000 MW x 0.25 = 25,000 MWh |
| Hourly | energy_MWh = load_MW * 1 | 100,000 MW x 1 = 100,000 MWh |
# Total energy for a period (5-min data)
total_mwh = (df['load'] * (5/60)).sum()
total_gwh = total_mwh / 1000
Query Parameters Reference
| Parameter | Type | Description |
|---|---|---|
dataset | str | Required. Dataset ID (e.g., ercot_load) |
start | str | Start date (YYYY-MM-DD or ISO format) |
end | str | End date |
limit | int | Max rows to return |
timezone | str | "market" for ISO local time, or "US/Central" etc. |
filter_column | str | Column to filter on |
filter_value | str/list | Value(s) to match |
filter_operator | str | =, !=, >, <, >=, <=, in |
resample | str | Aggregate frequency ("1 hour", "1 day") |
resample_function | str | mean, sum, min, max |
See references/api-reference.md for complete documentation.
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Old/stale data returned | Using curl directly | Use Python SDK instead - curl has date filtering issues on free tier |
| 401 Unauthorized | Invalid/missing API key | Check GRIDSTATUS_API_KEY is set correctly |
| Empty DataFrame | Date range outside coverage | Check dataset metadata for available date range |
| ModuleNotFoundError | SDK not installed | Run: cd /tmp && uv venv -q && source .venv/bin/activate && uv pip install gridstatusio pandas -q |
| "Unknown column" error | Wrong filter column | Zone data is in columns after fetch, not filterable. Use df['load.comed'] |
| 429 Rate Limited | Too many requests | SDK auto-retries with backoff |
Why Not curl?
The direct HTTP API has a critical issue on the free tier: date parameters are ignored and it returns sample data from years ago. The Python SDK correctly handles date filtering and returns current data.
If you must use curl (e.g., for dataset metadata), it works for non-query endpoints:
# This works - metadata endpoint
curl -s -H "x-api-key: $GRIDSTATUS_API_KEY" \
"https://api.gridstatus.io/v1/datasets/pjm_load"
# This returns stale data - query endpoint has issues
curl -s -H "x-api-key: $GRIDSTATUS_API_KEY" \
"https://api.gridstatus.io/v1/datasets/pjm_load/query?start=2026-01-25" # BROKEN
Additional Resources
Reference Files
references/datasets-by-iso.md- Complete dataset catalog by ISOreferences/api-reference.md- Full API parameter documentationreferences/common-queries.md- Ready-to-use query patterns
Example Files
examples/python-query.py- Python SDK examples
Source
git clone https://github.com/MisterClean/claude-plugins/blob/main/skills/gridstatus-api/SKILL.mdView on GitHub Overview
GridStatus API lets you fetch real-time and historical electricity grid data from US ISOs (ERCOT, CAISO, PJM, and more) via GridStatus.io. It covers load, LMP pricing, generation, fuel mix, and other market metrics for grid analysis and market insights.
How This Skill Works
Use the Python SDK to authenticate with GRIDSTATUS_API_KEY, create a GridStatusClient, and call get_dataset with a dataset name, start, end, and limit. The docs emphasize using the Python SDK (not curl) for correct parameter handling and date filtering, including awareness of the free tier limits.
When to Use It
- You need current or historical ISO-wide load data.
- You want ISO pricing (LMP) data across regions.
- You need fuel mix or generation composition for an ISO.
- You’re comparing data across multiple ISOs (ERCOT, CAISO, PJM, etc.).
- You’re setting up API access and querying data via the Python SDK (avoid curl due to reliability).
Quick Start
- Step 1: Install SDK (use uv for isolation): cd /tmp && uv venv -q && source .venv/bin/activate && uv pip install gridstatusio pandas -q
- Step 2: API Key: Check GRIDSTATUS_API_KEY in the user\'s .env file. If not present, instruct the user to: - Create account at https://www.gridstatus.io - Get API key from Settings page - Add to .env: GRIDSTATUS_API_KEY=your_key_here
- Step 3: Query data: import os os.environ['GRIDSTATUS_API_KEY'] = 'YOUR_KEY_HERE' from gridstatusio import GridStatusClient client = GridStatusClient() df = client.get_dataset( dataset="DATASET_NAME", start="YYYY-MM-DD", end="YYYY-MM-DD", limit=100 ) print(df.to_string())
Best Practices
- Always use the Python SDK for parameter handling and date filtering.
- Store your GRIDSTATUS_API_KEY securely (e.g., .env) and load it in your environment.
- Respect the free tier: limit is 500,000 rows per month; always specify a limit.
- Choose the dataset name appropriate to your ISO and metric (e.g., ercot_load, isone_fuel_mix).
- Be mindful of timezones (use start/end and timezone parameters to align your data).
Example Use Cases
- df = client.get_dataset(dataset='isone_fuel_mix', start='2026-01-25', end='2026-01-26', limit=500) latest = df.iloc[-1] total = latest[['coal','hydro','natural_gas','nuclear','oil','solar','wind','wood','refuse','other']].sum() print(f"Oil: {latest['oil']:.0f} MW ({latest['oil']/total*100:.1f}%)")
- df = client.get_dataset(dataset='pjm_load', start='2026-01-25', end='2026-01-26', timezone='US/Eastern', limit=100) print(f"Current load: {df.iloc[-1]['load']:,.0f} MW")
- df = client.get_dataset(dataset='ercot_spp_real_time_15_min', start='2026-01-25', end='2026-01-26', filter_column='location', filter_value='HB_HOUSTON', limit=100) print(f"Houston price: ${df.iloc[-1]['spp']:.2f}/MWh")
- df = client.get_dataset(dataset='pjm_standardized_hourly', start='2026-01-25', end='2026-01-26', timezone='market') # Zone data in columns: df['load.comed'], df['load.aep'], etc. print(f"ComEd load: {df.iloc[-1]['load.comed']:,.0f} MW")
- df = client.get_dataset(dataset='caiso_fuel_mix', start='2026-01-25', end='2026-01-26', limit=100)