gridstatus-api — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited gridstatus-api (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
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.
cd /tmp && uv venv -q && source .venv/bin/activate && uv pip install gridstatusio pandas -qGRIDSTATUS_API_KEY in the user's .env file. If not present, instruct the user to:.env: GRIDSTATUS_API_KEY=your_key_hereimport 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.
| 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.
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())
EOFdf = 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}%)")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")# 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']]}")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 LMPsLoad (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| 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.
| 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 |
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~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.